├── .gitignore ├── README.md ├── TODO ├── benchmark └── queries.js ├── documentation ├── querify.md └── transport.md ├── examples ├── config.json ├── demo.js ├── ex.js └── query.js ├── lib ├── hubs.js ├── matcher.js └── server.js ├── node_modules ├── buffoon │ ├── README.md │ ├── index.js │ └── package.json ├── common │ ├── README.md │ ├── common.min.js │ ├── index.js │ └── package.json ├── curl │ ├── README.md │ ├── index.js │ ├── node_modules │ │ ├── request │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── cookies.js │ │ │ ├── main.js │ │ │ ├── package.json │ │ │ ├── t.js │ │ │ └── tests │ │ │ │ ├── server.js │ │ │ │ ├── test-body.js │ │ │ │ ├── test-cookies.js │ │ │ │ ├── test-errors.js │ │ │ │ ├── test-pipes.js │ │ │ │ └── test-ssl.js │ │ └── router │ │ │ ├── README.md │ │ │ ├── index.js │ │ │ ├── matcher.js │ │ │ ├── node_modules │ │ │ ├── common │ │ │ │ ├── README.md │ │ │ │ ├── common.min.js │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ └── mimes │ │ │ │ ├── index.js │ │ │ │ └── mime.types │ │ │ ├── package.json │ │ │ └── tmp.js │ ├── package.json │ └── tst-server.js ├── geo-distance.js ├── json-sockets │ ├── .gitignore │ ├── .npmignore │ ├── README.md │ ├── example.js │ ├── index.js │ ├── package.json │ ├── test-server.js │ └── web-example.html ├── optimist │ ├── .npmignore │ ├── LICENSE │ ├── README.markdown │ ├── examples │ │ ├── bool.js │ │ ├── boolean_double.js │ │ ├── boolean_single.js │ │ ├── default_hash.js │ │ ├── default_singles.js │ │ ├── divide.js │ │ ├── line_count.js │ │ ├── line_count_options.js │ │ ├── line_count_wrap.js │ │ ├── nonopt.js │ │ ├── reflect.js │ │ ├── short.js │ │ ├── string.js │ │ ├── usage-options.js │ │ └── xup.js │ ├── index.js │ ├── node_modules │ │ └── wordwrap │ │ │ ├── .npmignore │ │ │ ├── README.markdown │ │ │ ├── example │ │ │ ├── center.js │ │ │ └── meat.js │ │ │ ├── index.js │ │ │ ├── package.json │ │ │ └── test │ │ │ ├── idleness.txt │ │ │ └── wrap.js │ ├── package.json │ └── test │ │ ├── _.js │ │ ├── _ │ │ ├── argv.js │ │ └── bin.js │ │ ├── parse.js │ │ └── usage.js ├── querify.js ├── ranger.js ├── router │ ├── README.md │ ├── index.js │ ├── matcher.js │ ├── node_modules │ │ ├── common │ │ │ ├── README.md │ │ │ ├── common.min.js │ │ │ ├── index.js │ │ │ └── package.json │ │ └── mimes │ │ │ ├── index.js │ │ │ └── mime.types │ └── package.json ├── signer │ ├── index.js │ └── shared.key └── websock │ ├── README.md │ ├── buffers.js │ ├── examples │ ├── browser.html │ ├── server.js │ └── stress.js │ ├── index.js │ ├── node_modules │ └── common │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── package.json │ ├── protocol-0.js │ └── protocol-8.js ├── package.json └── spike ├── auth.js ├── compiledate.js ├── compiledatefast.js ├── datepattern.js ├── datetime-benchmark.js └── geo.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | v8.log 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pubsub.io 2 | **a query based client/server publish subscribe protocol built on node.js.** 3 | 4 | Client implementions currently exists for the browser and node.js. 5 | 6 | ```js 7 | // to connect in node.js do: 8 | var pubsub = require('pubsub.io').connect('hub.pubsub.io'); 9 | 10 | // to connect in the browser do: 11 | var pubsub = pubsub.connect('hub.pubsub.io'); 12 | 13 | pubsub.subscribe({}, function(doc) { 14 | console.log('someone published', doc); 15 | }); 16 | 17 | pubsub.publish({foo:'bar'}); 18 | ``` 19 | 20 | ### Try running this yourself 21 | 22 | The client library is hosted at [http://pubsub.io/pubsub.io.js](http://pubsub.io/pubsub.io.js) 23 | 24 | The nodejs library is available through npm. `npm install pubsub.io` 25 | 26 | # Publish 27 | 28 | Whenever you want to send documents to other pubsub clients you need to publish it. 29 | The published document is then received by all subscribers whose query match the document. 30 | 31 | ```js 32 | pubsub.publish({name: 'pubsub', authors: ['mathias', 'ian'], version: 0.1}); 33 | ``` 34 | 35 | # Subscribe 36 | 37 | Whenever you want to receive documents from other pubsub clients you need to create a subscription with a query. 38 | The subscription is evaluated at the hub against all documents as they are published, if the query matches the published document your subscription handler will invoked with the document. 39 | 40 | ```js 41 | pubsub.subscribe({name: 'pubsub', version: {$gt:0}}, function(doc) { 42 | console.log('i love',doc); 43 | }); 44 | ``` 45 | 46 | You can choose to filter the document with a selction. 47 | 48 | ```js 49 | pubsub.subscribe(query, {property1:1, property2:1}, function(doc){ 50 | console.log(doc); // will only contain the selected properties 51 | }); 52 | ``` 53 | 54 | # Unsubscribe 55 | 56 | In order to unsubscribe a subscription, you call the function returned when subscribing 57 | 58 | ```js 59 | var sub = pubsub.subscribe({foo:'bar'},function(doc) { 60 | console.log(doc); 61 | }); // creates the subscription 62 | 63 | sub(); // removes the subscription 64 | ``` 65 | 66 | # Token and authentication 67 | 68 | As a subscriber you can use authentication to make sure that you can trust the data you subscribe to. In order to do this the publisher must provide signed 'authenticated' properties. The signed properties are provided by the token. 69 | 70 | As a publisher you can use authentication to limit the subscribers by the data by demanding that they use signed properties in their subscription queries. 71 | 72 | ```js 73 | var token = ... get authtoken from you authentication enpoint 74 | // in order for the hub to verifed the signed token it need to share key with the authentication enpoint 75 | 76 | // we subscribe as a signed user so publishers can trust us 77 | pubsub.subscribe({to: token.user, from: {$authenticated:'user',value:'transmitter'}}, function(doc) { 78 | // the doc.from was authenticated as a user, the doc can therefore be trusted 79 | }); 80 | 81 | // we want to limit the subscribers to authenticated users only 82 | pubsub.publish({to: {$authenticated:'user', value:'receiver'},from: token.user}); 83 | ``` 84 | 85 | # The Query Language 86 | 87 | The query language syntax is derived from the query language of [mongodb](http://mongodb.com). 88 | In general any property of a query that is not a language property represents a `===` relation, 89 | except if it is a regex - it is then the same as a `$regex` relation. 90 | 91 | The language consists of 2 parts. The outer language `{$outer:...}` and the inner language `{prop:{$inner:...}}`. 92 | 93 | ## The outer language 94 | `$has: key(s)` checks if the document has the given keys. multiple has an `and` relation 95 | `$or: [paths]` define multiple query paths 96 | 97 | ```js 98 | var query = { 99 | $or: [{ 100 | name:'pubsub.io' // check where the name is pubsub.io 101 | }, { 102 | {$has:'alias'} // or wether it has a property called alias 103 | }] 104 | }; 105 | ``` 106 | 107 | ## The inner language 108 | 109 | `$exists: bool` checks if the given property exists 110 | `$nil: bool` is `undefined` or `null` 111 | 112 | ```js 113 | var query = { 114 | name: {$nil:false}, // will reject if name is null or undefined 115 | coupling: {$exists:false} // document must not have a property called coupling 116 | }; 117 | ``` 118 | 119 | `$any: value(s)` is equal to any of the values 120 | `$regex: regex` must match regex 121 | `$like: substr` property must have a substring which is case-insensitive equal to substr 122 | 123 | ```js 124 | var query = { 125 | name: {$any:['mathias', 'ian']}, // name must be equal to either mathias or ian 126 | project: /pubsub\.io/i // project should have a substring pubsub.io in any case 127 | }; 128 | ``` 129 | 130 | `$gt: num` must be strictly greater than the num 131 | `$gte: num` must be greater or equal than the num 132 | `$lt: num` must be strictly lower than the num 133 | `$lte: num` must be lower or equal than the num 134 | `$mod: [base,val]` same as `property % base === val` 135 | 136 | ```js 137 | var query = { 138 | age: {$gt:20, $lte:40, $mod:[2,0]} // only match even ages between 20+ and 40 139 | }; 140 | ``` 141 | `$distance: circle` check if point is within a circle `{lat:0,lon:0}` with radius `800 km|m|mi|yd|ft` 142 | 143 | ```js 144 | var query = {point: {$distance: {center: {lat:0,lon:0}, radius:'800 km'}}}; 145 | ``` 146 | 147 | `$datetime: pattern` query against dates. Pattern format: day? date? month? year? hour:minute:second e.g. `Monday 22 August 2011 10:30:01` 148 | 149 | ```js 150 | var query = { 151 | time : {$datetime: 'monday 2011'} // matches dates on mondays in 2011 152 | }; 153 | 154 | var query = { 155 | time : {$datetime: '10:30:00'} // matches dates every day at 10:30:00 am 156 | }; 157 | 158 | var query = { 159 | time : {$datetime : '10:--:--'} // matches dates every day at 10 for the entire hour 160 | }; 161 | ``` 162 | 163 | `$not: value` must not be equal to value or match value if it is a regex 164 | 165 | All language properties can be negated by putting `$not` in front of it, 166 | i.e. `$notnil` checks if a property is different from `undefined` and `null` 167 | 168 | ```js 169 | var query = { 170 | friend: {$notlike:'nemesis'} // our friend must not contain the substring nemesis 171 | }; 172 | ``` 173 | 174 | # LICENSE 175 | 176 | Copyright (c) 2011 Ian Jørgensen and Mathias Buus Madsen 177 | 178 | Permission is hereby granted, free of charge, to any person obtaining a copy 179 | of this software and associated documentation files (the "Software"), to 180 | deal in the Software without restriction, including without limitation the 181 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 182 | sell copies of the Software, and to permit persons to whom the Software is 183 | furnished to do so, subject to the following conditions: 184 | 185 | The above copyright notice and this permission notice shall be included in 186 | all copies or substantial portions of the Software. 187 | 188 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 189 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 190 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 191 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 192 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 193 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 194 | IN THE SOFTWARE. -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | apps 2 | add sample section with auth and non auth examples. 3 | document the web hooks interface 4 | 5 | clustering 6 | clients 7 | 8 | reconnect 9 | heartbeats 10 | 11 | sub hubs 12 | trusted clients + hub permission 13 | 14 | socket fallback 15 | rest web hooks 16 | 17 | rest publish interface 18 | rest subscribe interface 19 | 20 | indexes in matcher 21 | 22 | revisit the function idea, @jedschmidt had some really good points for it 23 | _____________________________ 24 | DONE 25 | _____________________________ 26 | auth sub hubs 27 | release 0.1 28 | sub hub 0.1 29 | long polling fallback 30 | licensing -------------------------------------------------------------------------------- /benchmark/queries.js: -------------------------------------------------------------------------------- 1 | var compile = require('querify').compile; 2 | 3 | var queries = [ 4 | { 5 | foo:'bar', 6 | lol:'meh' 7 | }, 8 | { 9 | hello:'world', 10 | age: {$gt:10} 11 | }, 12 | { 13 | age: {$gt:10, $lt:20}, 14 | yay: {$exists:true}, 15 | meh: {$notany:[':)']} 16 | }, 17 | { 18 | time: {$datetime: 'monday 2011'} 19 | } 20 | ]; 21 | 22 | var compiled = []; 23 | 24 | for (var i in queries) { 25 | compiled.push(compile(queries[i])); 26 | } 27 | 28 | var MATCHES = 200000; 29 | var COMPILATIONS = 20000; 30 | 31 | var now = Date.now(); 32 | 33 | for (var h = 0; h < COMPILATIONS; h++) { 34 | for (var i in queries) { 35 | compile(queries[i]); 36 | } 37 | } 38 | 39 | var time = Date.now() - now; 40 | 41 | console.log(Math.round(COMPILATIONS*queries.length/time)+' compilations/ms, time ' + time + ' ms'); 42 | 43 | now = Date.now(); 44 | 45 | for (var h = 0; h < MATCHES; h++) { 46 | var doc = {hello:'world', age:h-1, foo:'bar', time: new Date('august 22 2011 10:30:00')}; 47 | 48 | for (var i = 0; i < compiled.length; i++) { 49 | compiled[i](doc); 50 | } 51 | } 52 | 53 | time = Date.now() - now; 54 | 55 | console.log(Math.round(MATCHES*queries.length/time)+' queries/ms, time ' + time + ' ms'); -------------------------------------------------------------------------------- /documentation/querify.md: -------------------------------------------------------------------------------- 1 | # querify - the query language of pubsub.io 2 | 3 | *draft 1 - june 2011, [@mafintosh](http://twitter.com/mafintosh), [@ianjorgensen](http://twitter.com/ianjorgensen)* 4 | 5 | the query language syntax is derived from the query language of [mongodb](http://mongodb.com). 6 | in general any property of a query that is not a language property represents a `===` relation, 7 | except if it is a regex - it is then the same as a `$regex` relation. 8 | 9 | the language consists of 2 parts. the outer language `{$outer:...}` and the inner language `{prop:{$inner:...}}`. 10 | 11 | ## the outer language 12 | `$has: key(s)` checks if the document has the given keys. multiple has an `and` relation 13 | `$or: [paths]` define multiple query paths 14 | 15 | var query = { 16 | $or: [{ 17 | name:'pubsub.io' // check where the name pubsub.io 18 | }, { 19 | {$has:'alias'} // or wether it has a property called alias 20 | }] 21 | }; 22 | 23 | ## the inner language 24 | 25 | `$exists: bool` checks if the given property exists 26 | `$nil: bool` is `undefined` or `null` 27 | 28 | var query = { 29 | name: {$nil:false}, // will reject if name is null or undefined 30 | coupling: {$exists:false} // document must not have a property called coupling 31 | }; 32 | 33 | `$any: value(s)` is equal to any of the values 34 | `$regex: regex` must match regex 35 | `$like: substr` property must have a substring which is case-insensitive equal to substr 36 | 37 | var query = { 38 | name: {$any:['mathias', 'ian']}, // name must be equal to either mathias or ian 39 | project: /pubsub\.io/i // project should have a substring pubsub.io in any case 40 | }; 41 | 42 | `$gt: num` must be strictly greater than the num 43 | `$gte: num` must be greater or equal than the num 44 | `$lt: num` must be strictly lower than the num 45 | `$lte: num` must be lower or equal than the num 46 | `$mod: [base,val]` same as `property % base === val` 47 | 48 | var query = { 49 | age: {$gt:20, $lte:40, $mod:[2,0]} // only match even ages between 20+ and 40 50 | }; 51 | 52 | `$datetime: pattern` query against dates. Pattern format: day? date? month? year? hour:minute:second e.g. `Monday 22 August 2011 10:30:01` 53 | 54 | var query = { 55 | time : {$datetime: 'monday 2011'} // matches dates on mondays in 2011 56 | }; 57 | 58 | var query = { 59 | time : {$datetime: '10:30:00'} // matches dates every day at 10:30:00 am 60 | }; 61 | 62 | var query = { 63 | time : {$datetime : '10:--:--'} // matches dates every day at 10 for the entire hour 64 | }; 65 | 66 | `$not: value` must not be equal to value or match value if it is a regex 67 | 68 | all language properties can be negated by putting `$not` in front of it. 69 | i.e. `$notnil` checks if a property is different from `undefined` and `null` 70 | 71 | var query = { 72 | friend: {$notlike:'nemesis'} // our friend must not contain the substring nemesis 73 | }; 74 | -------------------------------------------------------------------------------- /documentation/transport.md: -------------------------------------------------------------------------------- 1 | # transport documentation 2 | *07/25/2011 - draft 0* 3 | 4 | ## prerequisites 5 | 6 | all low level transports to the server are using the [websocket protocol](http://en.wikipedia.org/wiki/WebSockets) 7 | all websocket messages in pubsub consists entirely of JSON. 8 | 9 | ## handshake 10 | 11 | the first message after connecting is a handshake. 12 | as each connection is currently bound to a specific `subhub` it needs to be specified here. 13 | 14 | {sub:name_of_subhub} 15 | 16 | ## subscribe / unsubscribe 17 | 18 | if you want to subscribe to a query you send the following message: 19 | 20 | {name:'subscribe', query:your_query, challenge:your_auth_challenge, id:your_own_subscription_id} 21 | 22 | where `challenge` is optional. 23 | the `id` is your own id for this subscription. The hub will notify you whenever your subscription is matched by sending the following message: 24 | 25 | {name:'publish', doc:the_matches_document, id:your_subscription_id} 26 | 27 | to unsubscribe you send the following message: 28 | 29 | {name:'unsubscribe', id:_your_subscription_id} 30 | 31 | ## publish 32 | 33 | to publish a document just send the following message: 34 | 35 | {name:'publish', doc:your_document} -------------------------------------------------------------------------------- /examples/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "hubs": { 3 | "example": "f2boE8yi2NQzmnGXX1Ve/YkFIwE=", 4 | "chat": "f2boE8yi2NQzmnGXX1Ve/YkFIwE=" 5 | } 6 | } -------------------------------------------------------------------------------- /examples/demo.js: -------------------------------------------------------------------------------- 1 | var query = require('./query'); 2 | 3 | 4 | 5 | var subject = new Date('august 22 2011 10:30:00'); 6 | //var subject = new Date(); 7 | console.log(query.filter([{time:subject}],{time:{$datetime:'tuesday'}})); 8 | 9 | 10 | //console.log(query.reverse([{},{hi:1},{hi:{$gt:1}},{hi:{$gte:1}},{hi:{$gt:1,$lt:10}}], -------------------------------------------------------------------------------- /examples/ex.js: -------------------------------------------------------------------------------- 1 | var query = require('./query'); 2 | var berlin = { 3 | lon: 52.523, 4 | lat: 13.412 5 | }; 6 | query.reverse(point:$distance:) 7 | //console.log(query.filter([{hi:3},{hi:10},{hi:14},{hi:11},{hi:30}],{hi:{$gt:5,$lt:23,$mod:[2,0]}})); 8 | 9 | //console.log(query.filter([{id:1},{id:2}],{id:{$gt:0}})); 10 | //console.log(query.reverse([{id:{$gt:1}},{id:1}],{id:2})); 11 | 12 | /*var query = { 13 | age: {$gt:20, $lte:40, $mod:[2,0]} // only match even ages between 20+ and 40 14 | };*/ 15 | 16 | /*var oslo = { 17 | lon: 59.914, 18 | lat: 10.752 19 | }; 20 | var berlin = { 21 | lon: 52.523, 22 | lat: 13.412 23 | };*/ 24 | 25 | 26 | var subject = new Date('august 22 2011 10:30:00'); 27 | var subject = new Date(); 28 | console.log(query.filter([{time:subject}],{time:{$datetime:'sat 09:--:-- +2'}})); -------------------------------------------------------------------------------- /examples/query.js: -------------------------------------------------------------------------------- 1 | var querify = require('querify'); 2 | 3 | var filter = function(data, query) { 4 | return querify.filter(data, {query:query}); 5 | }; 6 | exports.filter = filter; 7 | 8 | var reverse = function(queries, data) { 9 | var result = []; 10 | 11 | queries.forEach(function(query) { 12 | if (querify.compile(query)(data)) { 13 | result.push(query); 14 | } 15 | }); 16 | 17 | return result; 18 | }; 19 | exports.reverse = reverse; -------------------------------------------------------------------------------- /lib/hubs.js: -------------------------------------------------------------------------------- 1 | var common = require('common'); 2 | var signer = require('signer') 3 | var createMatcher = require('./matcher').create; 4 | 5 | var noop = function() {}; 6 | 7 | /* 8 | signed values are represented as: {$signed:sig, value:val} 9 | trusted values are represented as: {$trusted:prop, value:val} 10 | */ 11 | 12 | var selector = function(selection) { 13 | if (!selection || !Object.keys(selection).length) { 14 | return function(doc) { 15 | return doc; 16 | }; 17 | } 18 | 19 | return function (doc) { 20 | var result = {}; 21 | 22 | for (var i in selection) { 23 | if (doc[i]) { 24 | result[i] = doc[i]; 25 | } 26 | } 27 | return result; 28 | }; 29 | }; 30 | 31 | var Hub = common.emitter(function(key) { 32 | this.subscriptions = {}; 33 | this.matcher = createMatcher(); 34 | this.signer = key ? signer.create(key) : signer; 35 | this.members = 0; 36 | }); 37 | 38 | Hub.prototype.subscribe = function(query, selection, callback) { 39 | var id = common.gensym(); 40 | var self = this; 41 | 42 | var authDoc = this._authenticator(query); 43 | var select = selector(selection); 44 | 45 | this.members++; 46 | 47 | this.subscriptions[id] = this.matcher.put(query, function(doc, authQuery) { 48 | if (authQuery(authDoc()) && authDoc(authQuery())) { 49 | callback(select(doc)); 50 | } 51 | }); 52 | 53 | return function() { 54 | if (!self.subscriptions[id]) { 55 | return; 56 | } 57 | self._unsubscribe(id); 58 | self.members--; 59 | 60 | if (!self.members) { 61 | self.emit('empty'); 62 | } 63 | }; 64 | }; 65 | Hub.prototype.publish = function(doc, challenge) { 66 | for (var i in challenge) { 67 | var d = doc[i]; 68 | 69 | doc[i] = {$trusted: challenge[i] === 1 ? i : challenge[i]}; 70 | 71 | if (d) { 72 | doc[i].value = d; 73 | } 74 | } 75 | 76 | this.matcher.match(doc, this._authenticator(doc)); 77 | }; 78 | Hub.prototype.clear = function() { 79 | for (var i in this.subscriptions) { 80 | this.subscriptions[i](); 81 | } 82 | this.subscriptions = {}; 83 | }; 84 | 85 | 86 | Hub.prototype._unsubscribe = function(id) { 87 | this.subscriptions[id](); 88 | delete this.subscriptions[id]; 89 | }; 90 | Hub.prototype._authenticator = function(doc) { 91 | var auths = {}; 92 | var signed = {}; 93 | 94 | var signer = this.signer; 95 | 96 | for (var i in doc) { 97 | var val = doc[i]; 98 | var auth = val.$trusted; 99 | 100 | if (auth) { 101 | auths[i] = (typeof auth === 'string' ? auth : i).replace(/\//g,'-'); 102 | } 103 | if (val.$signature) { 104 | signed[i] = val; 105 | } 106 | if (val.$signature || (auth && 'value' in val)) { 107 | doc[i] = val.value; 108 | } 109 | } 110 | return function(trusted) { 111 | if (!trusted) { 112 | return signed; 113 | } 114 | for (var i in auths) { 115 | var val = trusted[i]; 116 | 117 | if (!(val && signer.verify(auths[i]+'/'+val.value, val.$signature))) { // should cache the result of verify 118 | return false; 119 | } 120 | } 121 | return true; 122 | }; 123 | }; 124 | 125 | var LazyHub = common.emitter(function(get) { 126 | this.get = get; 127 | this.hub = null; 128 | }); 129 | 130 | LazyHub.prototype.subscribe = function(query, selection, callback) { 131 | if (!this.hub) { 132 | this.hub = this.get(true); 133 | this.hub.on('empty', this.emit.bind(this, 'empty')); 134 | } 135 | 136 | return this.hub.subscribe(query, selection, callback); 137 | }; 138 | LazyHub.prototype.publish = function(doc, challenge) { 139 | this.hub = this.hub || this.get(); 140 | 141 | if (!this.hub) { 142 | return; 143 | } 144 | 145 | this.hub.publish(doc, challenge); 146 | }; 147 | LazyHub.prototype.clear = function() { 148 | this.hub.clear(); 149 | }; 150 | 151 | 152 | var hubs = {}; 153 | 154 | exports.list = function() { 155 | return Object.keys(hubs); 156 | }; 157 | exports.active = function(name) { 158 | return !!hubs[name]; 159 | }; 160 | exports.remove = function(name) { 161 | if (!hubs[name]) { 162 | return false; 163 | } 164 | 165 | hubs[name].clear(); 166 | delete hubs[name]; 167 | 168 | return true; 169 | }; 170 | exports.add = function(name, key) { 171 | return hubs[name] = new Hub(key); 172 | }; 173 | exports.use = function(name) { 174 | return hubs[name] || new LazyHub(function(create) { 175 | if (create && !hubs[name]) { 176 | var hub = hubs[name] = new Hub(); 177 | 178 | hub.on('empty', function() { 179 | if (hubs[name] === hub) { 180 | delete hubs[name]; 181 | } 182 | }); 183 | 184 | return hub; 185 | } 186 | return hubs[name]; 187 | }); 188 | }; -------------------------------------------------------------------------------- /lib/matcher.js: -------------------------------------------------------------------------------- 1 | var compile = require('querify').compile; 2 | var common = require('common'); 3 | 4 | var Matcher = function() { 5 | this._queries = {}; 6 | }; 7 | 8 | Matcher.prototype.put = function(query, fn) { 9 | var id = common.gensym(); 10 | var compiled = compile(query); 11 | var queries = this._queries; 12 | 13 | queries[id] = function(doc,a,b) { 14 | if (compiled(doc)) { 15 | fn(doc,a,b); 16 | } 17 | }; 18 | 19 | return function() { 20 | delete queries[id]; 21 | }; 22 | }; 23 | Matcher.prototype.match = function(doc,a,b) { 24 | for (var i in this._queries) { 25 | this._queries[i](doc,a,b); 26 | } 27 | }; 28 | 29 | exports.create = function() { 30 | return new Matcher(); 31 | }; -------------------------------------------------------------------------------- /lib/server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // TODO: make optimist print out help 4 | 5 | var argv = require('optimist') 6 | .alias('p', 'port') 7 | .default('p', 9999) 8 | .alias('k', 'key') 9 | .alias('c','config') 10 | .alias('h') 11 | .default('h', '0.0.0.0') 12 | .argv; 13 | 14 | var router = require('router'); 15 | var sockets = require('json-sockets'); 16 | var common = require('common'); 17 | var curl = require('curl'); 18 | var parse = require('url').parse; 19 | var signer = require('signer'); 20 | var hubs = require('./hubs'); 21 | 22 | var hooks = {}; 23 | 24 | var server = router.create(); 25 | 26 | var noop = function() {}; 27 | 28 | var error = function(message) { 29 | var err = new Error('internal error'); 30 | 31 | err.publicMessage = message; 32 | return err; 33 | }; 34 | 35 | var toJSON = function(request, callback) { 36 | var buffer = ''; 37 | var onclose = function() { 38 | callback(new Error('unexpected close')); 39 | }; 40 | 41 | request.setEncoding('utf-8'); 42 | 43 | request.on('data', function(data) { 44 | buffer += data; 45 | }); 46 | request.on('end', function() { 47 | request.removeListener('close', onclose); 48 | try { 49 | buffer = JSON.parse(buffer); 50 | } catch (err) { 51 | callback(err); 52 | return; 53 | } 54 | callback(null, buffer); 55 | }); 56 | request.on('close', onclose); 57 | }; 58 | 59 | var onhookpublish = function(sub, request, response) { 60 | var sub = sub || '/'; 61 | common.step([ 62 | function(next) { 63 | toJSON(request, next); 64 | }, 65 | function(message) { 66 | hubs.use(sub).publish(message.doc, message.challenge); 67 | 68 | response.writeHead(200); 69 | response.end('ok\n'); 70 | } 71 | ], function(err){ 72 | response.writeHead(500); 73 | response.end(); 74 | }); 75 | }; 76 | var onhooksubscribe = function(sub, request, response) { 77 | common.step([ 78 | function(next) { 79 | toJSON(request, next); 80 | }, 81 | function(message, next) { 82 | var id = message.id || Math.random().toString(36).substring(2); 83 | 84 | if (!message.endpoint) { 85 | next(error('endpoint missing')); 86 | } 87 | 88 | hooks[id] = hubs.use(sub).subscribe(message.query, message.selection, function(doc) { 89 | curl.postJSON(message.endpoint, doc); 90 | }); 91 | 92 | var body = common.format("http://{host}/{sub}unsubscribe?id={id}", { 93 | host : request.headers.host, 94 | sub : sub || '', 95 | id: id 96 | }); 97 | 98 | response.writeHead(200, { 99 | 'content-type':'application/json', 100 | 'content-length':Buffer.byteLength(body) 101 | }); 102 | response.end(body+'\n'); 103 | } 104 | ], function(err) { 105 | response.writeHead(500); 106 | response.end(JSON.stringify({error:err.publicMessage || 'internal error'})); 107 | }); 108 | }; 109 | var onhookunsubscribe = function(sub, request, response) { 110 | var id = parse(request.url,true).query.id; 111 | 112 | if (!hooks[id]) { 113 | response.writeHead(404); 114 | response.end(); 115 | return; 116 | } 117 | 118 | hooks[id](); 119 | delete hooks[id]; 120 | 121 | response.writeHead(200); 122 | response.end('unsubscribed\n'); 123 | }; 124 | 125 | 126 | server.post('/publish', function(request, response) { 127 | onhookpublish('', request, response); 128 | }); 129 | server.post('/{sub}/publish', function(request, response) { 130 | onhookpublish(request.matches.sub, request, response); 131 | }); 132 | 133 | server.post('/subscribe', function(request, response) { 134 | onhooksubscribe('', request, response); 135 | }); 136 | server.post('/{sub}/subscribe', function(request, response) { 137 | onhooksubscribe(request.matches.sub, request, response); 138 | }); 139 | 140 | server.get('/{sub}/unsubscribe', function(request, response) { 141 | onhookunsubscribe(request.matches.sub, request, response); 142 | }); 143 | server.get('/unsubscribe', function(request, response) { 144 | onhookunsubscribe('', request, response); 145 | }); 146 | 147 | server.get('/{sub}/add', function(request, response) { 148 | var query = parse(request.url, true).query; 149 | var sub = request.matches.sub; 150 | 151 | common.step([ 152 | function(next) { 153 | if (hubs.use(sub).secret && hubs.use(sub).secret.toString('base64') !== query.old) { 154 | response.writeHead(403); 155 | response.end(); 156 | return; 157 | } 158 | if (query.secret) { 159 | next(null, new Buffer(query.secret, 'base64')); 160 | return; 161 | } 162 | signer.generateKey(next); 163 | }, 164 | function(key) { 165 | hubs.add(sub, key); 166 | 167 | response.writeHead(200); 168 | response.end(key.toString('base64')); 169 | } 170 | ], function(err) { 171 | response.writeHead(500); 172 | response.end(); 173 | }); 174 | }); 175 | 176 | var onsocket = function(socket) { 177 | var clear = {}; 178 | 179 | socket.once('message', function(handshake) { 180 | var sub = handshake.sub || '/'; 181 | var hub = hubs.use(sub); 182 | 183 | socket.on('message', function(message) { 184 | var id = message.id; 185 | 186 | if (message.name === 'subscribe') { 187 | clear[id] = hub.subscribe(message.query, message.selection, function(doc) { 188 | socket.send({name:'publish', id:id, doc:doc}); 189 | }); 190 | return; 191 | } 192 | if (message.name === 'unsubscribe') { 193 | (clear[id] || noop)(); 194 | delete clear[id]; 195 | return; 196 | } 197 | if (message.name === 'publish') { 198 | hub.publish(message.doc, message.challenge); 199 | return; 200 | } 201 | }); 202 | }); 203 | socket.on('close', function() { 204 | for (var i in clear) { 205 | clear[i](); 206 | } 207 | }); 208 | }; 209 | 210 | if (argv.config) { 211 | var config = JSON.parse(require('fs').readFileSync(argv.config, 'utf-8')); 212 | 213 | for (var i in config.hubs) { 214 | hubs.add(i, new Buffer(config.hubs[i], 'base64')); 215 | common.log('adding hub={0}, secret={1}',i,config.hubs[i]); 216 | } 217 | } 218 | sockets.listen(server, onsocket); 219 | 220 | server.listen(argv.p, argv.h); 221 | 222 | console.log('running hub server on port', argv.p, argv.h); 223 | 224 | process.on('uncaughtException', function(err) { console.error(err.stack) }); 225 | -------------------------------------------------------------------------------- /node_modules/buffoon/README.md: -------------------------------------------------------------------------------- 1 | # buffoon 2 | 3 | a module for buffering streams into strings, buffers, json or queries. 4 | it's available through npm 5 | 6 | npm install buffoon 7 | 8 | usage is simple 9 | 10 | ``` js 11 | var buffoon = require('buffoon'); 12 | 13 | // convert a stream to a string 14 | buffoon.string(stream, console.log); 15 | 16 | // convert a stream to a specific string encoding (defaults to utf-8) 17 | buffoon.string(stream, 'ascii', console.log); 18 | 19 | // buffer a stream into a single buffer 20 | buffoon.buffer(stream, console.log); 21 | 22 | // parse a stream as json 23 | buffoon.json(stream, console.log); 24 | 25 | // parse a stream as a querystring 26 | buffoon.query(stream, console.log); 27 | ``` -------------------------------------------------------------------------------- /node_modules/buffoon/index.js: -------------------------------------------------------------------------------- 1 | var common = require('common'); 2 | var parseQuery = require('querystring').parse; 3 | 4 | var onclose = function(stream, callback) { 5 | stream.on('error', callback); 6 | stream.on('close', function() { 7 | callback(new Error('premature close')); 8 | }); 9 | }; 10 | 11 | exports.string = function(stream, encoding, callback) { 12 | if (!callback) { 13 | callback = encoding; 14 | encoding = 'utf-8'; 15 | } 16 | 17 | var buffer = ''; 18 | 19 | callback = common.once(callback); 20 | onclose(stream, callback); 21 | 22 | stream.setEncoding(encoding); 23 | stream.on('data', function(data) { 24 | buffer += data; 25 | }); 26 | stream.on('end', function() { 27 | callback(null, buffer); 28 | }); 29 | }; 30 | 31 | exports.buffer = function(stream, callback) { 32 | var buffer = []; 33 | var length = 0; 34 | 35 | callback = common.once(callback); 36 | onclose(stream, callback); 37 | 38 | stream.on('data', function(data) { 39 | buffer.push(data); 40 | length += data.length; 41 | }); 42 | stream.on('end', function() { 43 | var result = new Buffer(length); 44 | var offset = 0; 45 | 46 | for (var i = 0; i < buffer.length; i++) { 47 | buffer[i].copy(result, offset); 48 | offset += buffer[i].length; 49 | } 50 | callback(null, result); 51 | }); 52 | }; 53 | 54 | var parser = function(strat) { 55 | return function(stream, callback) { 56 | exports.string(common.fork(callback, function(result) { 57 | try { 58 | result = strat(result); 59 | } catch(err) { 60 | callback(err); 61 | return; 62 | } 63 | callback(null, result); 64 | })); 65 | }; 66 | }; 67 | 68 | exports.json = parser(JSON.parse); 69 | exports.query = parser(parseQuery); -------------------------------------------------------------------------------- /node_modules/buffoon/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"buffoon", 3 | "version":"0.1.2", 4 | "description":"buffer streams into strings, buffers, json or queries", 5 | "keywords": ["buffering", "streams", "parsing"], 6 | "dependencies": {"common":">=0.1.0"}, 7 | "author": "Mathias Buus Madsen ", 8 | "main":"./index.js" 9 | } 10 | -------------------------------------------------------------------------------- /node_modules/common/README.md: -------------------------------------------------------------------------------- 1 | # Common 2 | A utility module for both node.js and the browser. 3 | It is available through npm: 4 | 5 | npm install common 6 | 7 | Or as minified js file for the browser: 8 | 9 | 10 | 11 | This module among other things contains a fork of [step](https://github.com/creationix/step) that also provides error handling 12 | 13 | ``` js 14 | common.step([ 15 | function(next) { // next is the last argument, except in the last handler 16 | fs.readFile(__filename, 'utf-8', next); 17 | }, 18 | function(file) { 19 | console.log(file); 20 | } 21 | ], function(err) { 22 | // any error received in a callback will be forwarded here 23 | }); 24 | ``` 25 | 26 | It also contains a shortcut to the `EventEmitter` prototype and a compatible implementation of this for the browser. 27 | 28 | ``` js 29 | var MyEmitter = common.emitter(function() { 30 | this.foo = 42; 31 | }); 32 | 33 | var me = new MyEmitter(); 34 | 35 | me.emit('foo', me.foo); // emits 'foo',42 36 | ``` 37 | 38 | There is also a more general method for extending prototypes called `extend`: 39 | 40 | ``` js 41 | // this prototype is the same as above 42 | var MyEmitter = common.extend(events.EventEmitter, function() { 43 | this.foo = 42; 44 | }); 45 | ``` 46 | 47 | If you want to use futures you can use the `future` function to create a future: 48 | 49 | ``` js 50 | var fut = common.future(); 51 | 52 | fut.get(function(val) { 53 | console.log(val); 54 | }); 55 | setTimeout(function() { 56 | fut.put(42); // results in the previous .get being called and all future .get's will be called synchroniously 57 | }, 1000) 58 | ``` 59 | 60 | To do string formatting you can use `format`: 61 | 62 | ``` js 63 | // you can parse the arguments to a pattern one by one 64 | common.format('define {0} here', 'pattern'); // returns 'define pattern here' 65 | 66 | // or as a map or array 67 | common.format('define {foo} here', {foo:'pattern'}); // same as above 68 | ``` 69 | There is a `log` method that just accepts the does the same as `format` except it prints out the result using `console.log` if available 70 | 71 | To generate a simple weak symbols (often used when generating keys for a map) use `gensym` 72 | 73 | ``` js 74 | common.gensym() // returns 's0' 75 | common.gensym() // returns 's1' 76 | ``` 77 | 78 | If you instead of a weak symbol need a strong one use `uuid`: 79 | 80 | ``` js 81 | common.uuid(); // returns a strong id, ex: ngDl6IdovME9JKvIxgED0FK1kzURxfZaCq48-0 82 | ``` 83 | 84 | Common can also encode integers into alphanumerical notation using `encode`: 85 | 86 | ``` js 87 | common.encode(1000); // returns G8 88 | ``` 89 | 90 | To ensure that a method cannot be called more than once you can use the `once` function: 91 | 92 | ``` js 93 | var fn = common.once(function() { 94 | console.log('hello'); 95 | }); 96 | 97 | fn(); // prints hello 98 | fn(); // does nothing 99 | ``` 100 | 101 | Besides the above common implements two of the utilities mentioned in The Good Parts, `memoizer` and `curry`. 102 | -------------------------------------------------------------------------------- /node_modules/common/common.min.js: -------------------------------------------------------------------------------- 1 | (function(g){(function(){if(typeof g==="undefined"){var k=function(){},c={},i={};g=function(e){if(arguments.length>1){for(var h=g(arguments[0]),a=1;a=d))){var o=a[c++],k=o.length===1?[j]:[n,j];d=f=0;h=[];l=!1;o.apply(g,c=d&&j(null,h)}};j.parallel=function(){var a=d++;if(l)throw Error("next.parallel must not be called async");return function(b,d){f++;h[a]=d;j(b,h)}};j()};c.memoizer=function(a){var b= 5 | {},d=function(a){var b=typeof a;if(b!=="object")return b+": "+a;var b=[],c;for(c in a)b.push(d(a[c]));return b.sort().join("\n")};return function(){for(var c="",e=0;e= counter; 118 | }; 119 | var next = function(err, value) { 120 | if (err && !ended) { 121 | ended = true; 122 | (onerror || noop).apply(state, [err]); 123 | return; 124 | } 125 | if (ended || (counter && !check())) { 126 | return; 127 | } 128 | 129 | var fn = funcs[pointer++]; 130 | var args = (fn.length === 1 ? [next] : [value, next]); 131 | 132 | counter = completed = 0; 133 | values = []; 134 | complete = false; 135 | fn.apply(state, pointer < funcs.length ? args : [value, next]); 136 | complete = true; 137 | 138 | if (counter && check()) { 139 | next(null, values); 140 | } 141 | }; 142 | next.parallel = function() { 143 | var index = counter++; 144 | 145 | if (complete) { 146 | throw new Error('next.parallel must not be called async'); 147 | } 148 | return function(err, value) { 149 | completed++; 150 | values[index] = value; 151 | next(err, values); 152 | }; 153 | }; 154 | 155 | next(); 156 | }; 157 | 158 | exports.memoizer = function(fn) { 159 | var cache = {}; 160 | 161 | var stringify = function(obj) { 162 | var type = typeof obj; 163 | 164 | if (type !== 'object') { 165 | return type + ': ' + obj; 166 | } 167 | var keys = []; 168 | 169 | for (var i in obj) { 170 | keys.push(stringify(obj[i])); 171 | } 172 | return keys.sort().join('\n'); 173 | }; 174 | 175 | return function() { 176 | var key = ''; 177 | 178 | for (var i = 0; i < arguments.length; i++) { 179 | key += stringify(arguments[i]) + '\n'; 180 | } 181 | 182 | cache[key] = cache[key] || fn.apply(null, arguments); 183 | 184 | return cache[key]; 185 | }; 186 | }; 187 | 188 | exports.curry = function(fn) { 189 | var args = Array.prototype.slice.call(arguments, 1); 190 | 191 | return function() { 192 | return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))); 193 | }; 194 | }; 195 | 196 | exports.once = function(fn) { 197 | var once = true; 198 | 199 | return function() { 200 | if (once) { 201 | once = false; 202 | (fn || noop).apply(null, arguments); 203 | return true; 204 | } 205 | return false; 206 | }; 207 | }; 208 | 209 | exports.future = function() { 210 | var that = {}; 211 | var stack = []; 212 | 213 | that.get = function(fn) { 214 | stack.push(fn); 215 | }; 216 | that.put = function(a,b) { 217 | that.get = function(fn) { 218 | fn(a,b); 219 | }; 220 | 221 | while (stack.length) { 222 | stack.shift()(a,b); 223 | } 224 | }; 225 | return that; 226 | }; 227 | 228 | // utilities below 229 | 230 | exports.encode = function(num) { 231 | var ALPHA = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 232 | 233 | return function(i) { 234 | return i < ALPHA.length ? ALPHA.charAt(i) : exports.encode(Math.floor(i / ALPHA.length)) + ALPHA.charAt(i % ALPHA.length); 235 | }; 236 | }(); 237 | 238 | exports.uuid = function() { 239 | var inc = 0; 240 | 241 | return function() { 242 | var uuid = ''; 243 | 244 | for (var i = 0; i < 36; i++) { 245 | uuid += exports.encode(Math.floor(Math.random() * 62)); 246 | } 247 | return uuid + '-' + exports.encode(inc++); 248 | }; 249 | }(); 250 | 251 | exports.gensym = function() { 252 | var s = 0; 253 | 254 | return function() { 255 | return 's'+(s++); 256 | }; 257 | }(); 258 | 259 | exports.format = function (str, col) { 260 | col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1); 261 | 262 | return str.replace(/\{([^{}]+)\}/gm, function () { 263 | return col[arguments[1]] === undefined ? arguments[0] : col[arguments[1]]; 264 | }); 265 | }; 266 | 267 | exports.log = function(str) { 268 | str = ''+str; 269 | 270 | var format = exports.format.apply(exports, arguments); 271 | 272 | if (typeof window !== 'undefined' && !window.console) { 273 | return; 274 | } 275 | console.log(format); 276 | }; -------------------------------------------------------------------------------- /node_modules/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"common", 3 | "version":"0.1.2", 4 | "description":"A utility package with some useful functional stuff", 5 | "author": "Ge.tt ", 6 | "contributors": [ 7 | "Mathias Buus Madsen " 8 | ], 9 | "main":"./index.js" 10 | } 11 | -------------------------------------------------------------------------------- /node_modules/curl/README.md: -------------------------------------------------------------------------------- 1 | # CURL -- Simple client url library, with high level request functions 2 | 3 | ## Install 4 | 5 |
 6 |   npm install curl
 7 | 
8 | 9 | Or from source: 10 |
11 |   git clone git://github.com/ianjorgensen/curl.git 
12 |   cd curl
13 |   npm link .
14 | 
15 | 16 | ## Functions 17 | ### curl.get 18 | 19 |
curl.get(url, options, function(err, response, body) {});
20 | 21 | ### curl.post 22 | 23 |
curl.post(url, body, options, function(err, response, body) {});
24 | 25 | ### curl.getJSON 26 | 27 |
curl.getJSON(url, options, function(err, response, data){});
28 | 29 | ### curl.postJSON 30 | 31 |
curl.postJSON(url, data, options, function(err, response, data){});
-------------------------------------------------------------------------------- /node_modules/curl/index.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | 3 | var noop = function() {}; 4 | 5 | var merge = function() { 6 | var result = {}; 7 | 8 | for (var i = 0; i < arguments.length; i++) { 9 | var obj = arguments[i]; 10 | 11 | for (var j in obj) { 12 | result[j] = obj[j]; 13 | } 14 | } 15 | return result; 16 | }; 17 | 18 | var get = function(url, options, callback) { 19 | if(!callback) { 20 | callback = options; 21 | options = {}; 22 | } 23 | 24 | var options = merge(options,{url:url},{method:'GET'}); 25 | 26 | delete options.uri; 27 | 28 | request(options, callback); 29 | }; 30 | exports.get = get; 31 | 32 | var post = function(url, body, options, callback) { 33 | if(!callback && typeof options === 'function') { 34 | callback = options; 35 | options = {}; 36 | } 37 | 38 | callback = callback || noop; 39 | 40 | var options = merge(options,{ 41 | method: 'POST', 42 | url: url, 43 | body: body 44 | }); 45 | 46 | delete options.uri; 47 | 48 | request(options, callback); 49 | }; 50 | exports.post = post; 51 | 52 | var getJSON = function(url, options, callback) { 53 | if(!callback) { 54 | callback = options; 55 | options = {}; 56 | } 57 | 58 | get(url, options, function(err, response, body) { 59 | if(err) { 60 | callback(err, null, null); 61 | return; 62 | } 63 | callback(null, response, JSON.parse(body)) 64 | }); 65 | }; 66 | exports.getJSON = getJSON; 67 | 68 | var postJSON = function(url, data, options, callback) { 69 | if(!callback) { 70 | callback = options; 71 | options = {}; 72 | } 73 | 74 | var options = merge(options, {'content-type': 'application/json'}); 75 | 76 | delete options.uri; 77 | 78 | post(url, JSON.stringify(data), options, callback); 79 | }; 80 | exports.postJSON = postJSON; -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 14 | 15 | "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. 16 | 17 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 18 | 19 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 20 | 21 | "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. 22 | 23 | "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). 24 | 25 | "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. 26 | 27 | "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." 28 | 29 | "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. 30 | 31 | 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. 32 | 33 | 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. 34 | 35 | 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: 36 | 37 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 38 | 39 | You must cause any modified files to carry prominent notices stating that You changed the files; and 40 | 41 | 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 42 | 43 | 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. 44 | 45 | 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. 46 | 47 | 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. 48 | 49 | 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. 50 | 51 | 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. 52 | 53 | 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. 54 | 55 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/README.md: -------------------------------------------------------------------------------- 1 | # Request -- Simplified HTTP request method 2 | 3 | ## Install 4 | 5 |
  6 |   npm install request
  7 | 
8 | 9 | Or from source: 10 | 11 |
 12 |   git clone git://github.com/mikeal/request.git 
 13 |   cd request
 14 |   npm link .
 15 | 
16 | 17 | ## Super simple to use 18 | 19 | Request is designed to be the simplest way possible to make http calls. It support HTTPS and follows redirects by default. 20 | 21 |
 22 |   var request = require('request');
 23 |   request({uri:'http://www.google.com'}, function (error, response, body) {
 24 |     if (!error && response.statusCode == 200) {
 25 |       sys.puts(body) // Print the google web page.
 26 |     }
 27 |   })
 28 | 
29 | 30 | #### request(options, callback) 31 | 32 | The first argument is an options object. The only required option is uri, all others are optional. 33 | 34 | * `uri` || `url` - fully qualified uri or a parsed url object from url.parse() 35 | * `method` - http method, defaults to GET 36 | * `headers` - http headers, defaults to {} 37 | * `body` - entity body for POST and PUT requests. Must be buffer or string. 38 | * `json` - sets `body` but to JSON representation of value and adds `Content-type: application/json` header. 39 | * `multipart` - (experimental) array of objects which contains their own headers and `body` attribute. Sends `multipart/related` request. See example below. 40 | * `followRedirect` - follow HTTP 3xx responses as redirects. defaults to true. 41 | * `maxRedirects` - the maximum number of redirects to follow, defaults to 10. 42 | * `onResponse` - If true the callback will be fired on the "response" event instead of "end". If a function it will be called on "response" and not effect the regular semantics of the main callback on "end". 43 | * `encoding` - Encoding to be used on response.setEncoding when buffering the response data. 44 | * `pool` - A hash object containing the agents for these requests. If omitted this request will use the global pool which is set to node's default maxSockets. 45 | * `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool. 46 | 47 | The callback argument gets 3 arguments. The first is an error when applicable (usually from the http.Client option not the http.ClientRequest object). The second in an http.ClientResponse object. The third is the response body buffer. 48 | 49 | Examples: 50 | 51 |
 52 |   var request = require('request');
 53 |   var rand = Math.floor(Math.random()*100000000).toString();
 54 |   request(
 55 |     { method: 'PUT'
 56 |     , uri: 'http://mikeal.couchone.com/testjs/' + rand
 57 |     , multipart: 
 58 |       [ { 'content-type': 'application/json'
 59 |         ,  body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})
 60 |         }
 61 |       , { body: 'I am an attachment' }
 62 |       ] 
 63 |     }
 64 |   , function (error, response, body) {
 65 |       if(response.statusCode == 201){
 66 |         console.log('document saved as: http://mikeal.couchone.com/testjs/'+ rand);
 67 |       } else {
 68 |         console.log('error: '+ response.statusCode);
 69 |         console.log(body);
 70 |       }
 71 |     }
 72 |   )
 73 | 
74 | 75 | **Notice for 2.0** 76 | 77 | You should no longer recycle mutations in the options object. Because node 0.4.0 has an internal pooling mechanism the preferred way of sharing a connection is using agents which request simplifies with it's new pool API. Therefor options.client and some other mutations have been deprecated. 78 | 79 | requestBodyStream and responseBodyStream are also deprecated in favor of a more standard pipe interface documented below. 80 | 81 | ### stream.pipe(request(options)) and request(options).pipe(stream) 82 | 83 | Previous versions of request had no return value and only accepted callbacks and streams for pumping in the options object. 84 | 85 | Node has solidified it's Stream interface and request 2.0 is now compliant with that interface. 86 | 87 | The return value of request() is now a Request object, which is a valid stream. 88 | 89 | As a writable stream it accepts the body of an HTTP request. As a readable stream it emits the data events for the response. 90 | 91 |
 92 |   var r = request(
 93 |     { url: "http://mysite.com/image.png"
 94 |     , method: 'PUT'
 95 |     , headers: {'content-type': 'image/png'}
 96 |     }
 97 |   )
 98 |   fs.createReadStream('image.png').pipe(r)
 99 |   r.pipe(fs.createWriteStream('pushlog.txt'))
100 | 
101 | 102 | # Convenience methods 103 | 104 | ### request.defaults(options) 105 | 106 | This method returns a wrapper around the normal request API that defaults to whatever options you pass in to it. 107 | 108 | ### request.put 109 | 110 | Same as request() but defaults to `method: "PUT"`. 111 | 112 | ### request.post 113 | 114 | Same as request() but defaults to `method: "POST"`. 115 | 116 | ### request.head 117 | 118 | Same as request() but defaults to `method: "HEAD"`. 119 | 120 | ### request.get 121 | 122 | Alias to normal request method for uniformity. 123 | -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/cookies.js: -------------------------------------------------------------------------------- 1 | 2 | var cookie_str_splitter=/[:](?=\s*[a-zA-Z0-9_\-]+\s*[=])/g 3 | 4 | function stringify (cookie) { 5 | var str=[cookie.name+"="+cookie.value]; 6 | if(cookie.expiration_date !== Infinity) { 7 | str.push("expires="+(new Date(cookie.expiration_date)).toGMTString()); 8 | } 9 | if(cookie.domain) { 10 | str.push("domain="+cookie.domain); 11 | } 12 | if(cookie.path) { 13 | str.push("path="+cookie.path); 14 | } 15 | if(cookie.secure) { 16 | str.push("secure"); 17 | } 18 | if(cookie.noscript) { 19 | str.push("httponly"); 20 | } 21 | return str.join("; "); 22 | } 23 | 24 | function Jar () { 25 | this.cookies = [] 26 | } 27 | Jar.prototype.setCookies = function (cookieString) { 28 | 29 | } 30 | Jar.prototype.getHeader = function (host, path) { 31 | 32 | } 33 | Jar.prototype.getCookies = function (access_info) { 34 | var matches=[]; 35 | for(var cookie_name in cookies) { 36 | var cookie=this.getCookie(cookie_name,access_info); 37 | if (cookie) { 38 | matches.push(cookie); 39 | } 40 | } 41 | matches.toString=function toString(){return matches.join(":");} 42 | return matches; 43 | } 44 | 45 | Jar.prototype.getCookie = function (host, path) { 46 | var cookies_list = self.cookies[cookie_name]; 47 | for(var i=0;i" 6 | , "repository" : 7 | { "type" : "git" 8 | , "url" : "http://github.com/mikeal/request.git" 9 | } 10 | , "bugs" : 11 | { "web" : "http://github.com/mikeal/request/issues" } 12 | , "engines" : ["node >= 0.3.6"] 13 | , "main" : "./main" 14 | } 15 | -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/t.js: -------------------------------------------------------------------------------- 1 | console.log((function () { 2 | var x = 'asdf' 3 | console.log(x) 4 | }).toString()) -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/tests/server.js: -------------------------------------------------------------------------------- 1 | var http = require('http') 2 | , events = require('events') 3 | , stream = require('stream') 4 | , assert = require('assert') 5 | ; 6 | 7 | exports.createServer = function (port) { 8 | port = port || 6767 9 | var s = http.createServer(function (req, resp) { 10 | s.emit(req.url, req, resp); 11 | }) 12 | s.listen(port) 13 | s.url = 'http://localhost:'+port 14 | return s; 15 | } 16 | 17 | exports.createPostStream = function (text) { 18 | var postStream = new stream.Stream(); 19 | postStream.writeable = true; 20 | postStream.readable = true; 21 | setTimeout(function () {postStream.emit('data', new Buffer(text)); postStream.emit('end')}, 0); 22 | return postStream; 23 | } 24 | exports.createPostValidator = function (text) { 25 | var l = function (req, resp) { 26 | var r = ''; 27 | req.on('data', function (chunk) {r += chunk}) 28 | req.on('end', function () { 29 | if (r !== text) console.log(r, text); 30 | assert.ok(r === text) 31 | resp.writeHead(200, {'content-type':'text/plain'}) 32 | resp.write('OK') 33 | resp.end() 34 | }) 35 | } 36 | return l; 37 | } 38 | exports.createGetResponse = function (text) { 39 | var l = function (req, resp) { 40 | resp.writeHead(200, {'content-type':'text/plain'}) 41 | resp.write(text) 42 | resp.end() 43 | } 44 | return l; 45 | } 46 | -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/tests/test-body.js: -------------------------------------------------------------------------------- 1 | var server = require('./server') 2 | , events = require('events') 3 | , stream = require('stream') 4 | , assert = require('assert') 5 | , request = require('../main.js') 6 | ; 7 | 8 | var s = server.createServer(); 9 | 10 | var tests = 11 | { testGet : 12 | { resp : server.createGetResponse("TESTING!") 13 | , expectBody: "TESTING!" 14 | } 15 | , testPutString : 16 | { resp : server.createPostValidator("PUTTINGDATA") 17 | , method : "PUT" 18 | , body : "PUTTINGDATA" 19 | } 20 | , testPutBuffer : 21 | { resp : server.createPostValidator("PUTTINGDATA") 22 | , method : "PUT" 23 | , body : new Buffer("PUTTINGDATA") 24 | } 25 | , testPutStream : 26 | { resp : server.createPostValidator("PUTTINGDATA") 27 | , method : "PUT" 28 | , requestBodyStream : server.createPostStream("PUTTINGDATA") 29 | } 30 | , testPutJSON : 31 | { resp : server.createPostValidator(JSON.stringify({foo: 'bar'})) 32 | , method: "PUT" 33 | , json: {foo: 'bar'} 34 | } 35 | , testPutMultipart : 36 | { resp: server.createPostValidator( 37 | '--frontier\r\n' + 38 | 'content-type: text/html\r\n' + 39 | '\r\n' + 40 | 'Oh hi.' + 41 | '\r\n--frontier\r\n\r\n' + 42 | 'Oh hi.' + 43 | '\r\n--frontier--' 44 | ) 45 | , method: "PUT" 46 | , multipart: 47 | [ {'content-type': 'text/html', 'body': 'Oh hi.'} 48 | , {'body': 'Oh hi.'} 49 | ] 50 | } 51 | } 52 | 53 | var counter = 0; 54 | 55 | for (i in tests) { 56 | (function () { 57 | var test = tests[i]; 58 | s.on('/'+i, test.resp); 59 | test.uri = s.url + '/' + i; 60 | request(test, function (err, resp, body) { 61 | if (err) throw err; 62 | if (test.expectBody) { 63 | if (test.expectBody !== body) console.log(test.expectBody, body); 64 | assert.ok(test.expectBody === body) 65 | } 66 | counter = counter - 1; 67 | if (counter === 0) { 68 | console.log(Object.keys(tests).length+" tests passed.") 69 | s.close(); 70 | } 71 | }) 72 | counter++; 73 | })() 74 | } 75 | -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/tests/test-cookies.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubsubio/pubsub-hub/c3300f582f6cb72d92b27151d985851f05d60236/node_modules/curl/node_modules/request/tests/test-cookies.js -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/tests/test-errors.js: -------------------------------------------------------------------------------- 1 | var server = require('./server') 2 | , events = require('events') 3 | , assert = require('assert') 4 | , request = require('../main.js') 5 | ; 6 | 7 | var local = 'http://localhost:8888/asdf' 8 | 9 | try { 10 | request({uri:local, body:{}}) 11 | assert.fail("Should have throw") 12 | } catch(e) { 13 | assert.equal(e.message, 'Argument error, options.body.') 14 | } 15 | 16 | try { 17 | request({uri:local, multipart: 'foo'}) 18 | assert.fail("Should have throw") 19 | } catch(e) { 20 | assert.equal(e.message, 'Argument error, options.multipart.') 21 | } 22 | 23 | try { 24 | request({uri:local, multipart: [{}]}) 25 | assert.fail("Should have throw") 26 | } catch(e) { 27 | assert.equal(e.message, 'Body attribute missing in multipart.') 28 | } 29 | 30 | console.log("All tests passed.") -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/tests/test-pipes.js: -------------------------------------------------------------------------------- 1 | var server = require('./server') 2 | , events = require('events') 3 | , stream = require('stream') 4 | , assert = require('assert') 5 | , request = require('../main.js') 6 | ; 7 | 8 | var s = server.createServer(3453); 9 | 10 | passes = 0; 11 | 12 | function check () { 13 | if (passes === 3) { 14 | console.log('All tests passed.') 15 | process.exit(); 16 | } 17 | } 18 | 19 | // Test pipeing to a request object 20 | s.once('/push', server.createPostValidator("mydata")); 21 | 22 | var mydata = new stream.Stream(); 23 | mydata.readable = true 24 | 25 | var r1 = request.put({url:'http://localhost:3453/push'}, function () { 26 | passes += 1; 27 | check(); 28 | }) 29 | mydata.pipe(r1) 30 | 31 | mydata.emit('data', 'mydata'); 32 | mydata.emit('end'); 33 | 34 | 35 | // Test pipeing from a request object. 36 | s.once('/pull', server.createGetResponse("mypulldata")); 37 | 38 | var mypulldata = new stream.Stream(); 39 | mypulldata.writable = true 40 | 41 | request({url:'http://localhost:3453/pull'}).pipe(mypulldata) 42 | 43 | var d = ''; 44 | 45 | mypulldata.write = function (chunk) { 46 | d += chunk; 47 | } 48 | mypulldata.end = function () { 49 | assert.ok(d === 'mypulldata'); 50 | passes += 1 51 | check(); 52 | }; 53 | 54 | 55 | s.on('/cat', function (req, resp) { 56 | if (req.method === "GET") { 57 | resp.writeHead(200, {'content-type':'text/plain', 'content-length':4}); 58 | resp.write('asdf'); 59 | resp.end() 60 | } else if (req.method === "PUT") { 61 | assert.ok(req.headers['content-type'] === 'text/plain'); 62 | assert.ok(req.headers['content-length'] == 4) 63 | var validate = ''; 64 | req.on('data', function (chunk) {validate += chunk}) 65 | req.on('end', function () { 66 | resp.writeHead(201); 67 | resp.end(); 68 | assert.ok(validate === 'asdf'); 69 | passes += 1; 70 | check(); 71 | }) 72 | } 73 | }) 74 | 75 | request.get('http://localhost:3453/cat').pipe(request.put('http://localhost:3453/cat')) 76 | 77 | -------------------------------------------------------------------------------- /node_modules/curl/node_modules/request/tests/test-ssl.js: -------------------------------------------------------------------------------- 1 | var request = require("../main"); 2 | 3 | request({'uri': 'https://encrypted.google.com/'}, function (err, res, body) { 4 | // util.debug(err); 5 | // console.dir(res) 6 | console.log('asdf') 7 | }); -------------------------------------------------------------------------------- /node_modules/curl/node_modules/router/README.md: -------------------------------------------------------------------------------- 1 | # Router 2 | A lean and mean web router for [node.js](http://nodejs.org). 3 | It is available through npm: 4 | 5 | npm install router 6 | 7 | The router routes using the method and a pattern 8 | 9 | ``` js 10 | var router = require('router').create(); 11 | 12 | router.get('/', function(request, response) { 13 | response.writeHead(200); 14 | response.end('hello index page'); 15 | }); 16 | 17 | router.listen(8080); // start the server on port 8080 18 | ``` 19 | 20 | If you want to grap a part of the path you can use capture groups in the pattern: 21 | 22 | ``` js 23 | router.get('/{base}', function(request, response) { 24 | var base = request.matches.base; // ex: if the path is /foo/bar, then base = foo 25 | }); 26 | ``` 27 | 28 | The capture patterns matches until the next `/` or character present after the group 29 | 30 | ``` js 31 | router.get('/{x}x{y}', function(request, response) { 32 | // if the path was /200x200, then request.matches = {x:'200', y:'200'} 33 | }); 34 | ``` 35 | 36 | You can also use regular expressions and the related capture groups instead: 37 | 38 | ``` js 39 | router.get(/^\/foo\/(\w+)/, function(request, response) { 40 | var group = request.matches[1]; // if path is /foo/bar, then group is bar 41 | }); 42 | ``` 43 | 44 | Besides `get` the avaiable methods are `post`, `put`, `head`, `del`, `request` and `upgrade`. 45 | `request` matches all the standard http methods and `upgrade` is usually used for websockets. -------------------------------------------------------------------------------- /node_modules/curl/node_modules/router/index.js: -------------------------------------------------------------------------------- 1 | var common = require('common'); 2 | var http = require('http'); 3 | var https = require('https'); 4 | 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | var mimes = require('mimes'); 8 | 9 | var matcher = require('./matcher'); 10 | 11 | var createRouter = function(options) { // TODO: params instead of matches 12 | var that = {}; 13 | 14 | options = options || {}; 15 | 16 | // this check may seem a bit confusing. basicly if options is a server or a router 17 | // then just return the attached router 18 | if (options.router) { 19 | return options.router; 20 | } 21 | // if options if already a server we just sugar it and create a router 22 | // that doesnt autoclose (otherwise we could have really weird rcs) 23 | // TODO: maybe listen for # of request handlers on the server to decide whether to autoclose 24 | if (typeof options.listen === 'function') { 25 | return createRouter({server:options, autoclose:false}); 26 | } 27 | 28 | var methods = {request:[], upgrade:[], get:[], put:[], post:[], head:[], 'delete':[]}; 29 | var server = options.server || (options.key ? https.createServer({key:options.key,cert:options.cert}) : http.createServer()); 30 | 31 | that.autoclose = options.autoclose !== false; 32 | that.server = server; 33 | that.router = server.router = that; 34 | 35 | var find = function(handlers, request, a, b) { 36 | for (var i = 0; i < handlers.length; i++) { 37 | if (handlers[i](request, a, b)) { 38 | return true; 39 | } 40 | } 41 | return false; 42 | }; 43 | 44 | that.route = function(request, response) { 45 | if (find(methods.request, request, response) || 46 | find(methods[request.method.toLowerCase()], request, response) || !that.autoclose) { 47 | return; 48 | } 49 | if (request.method === 'POST' || request.method === 'PUT') { // TODO: check if node doesn't already do this 50 | request.connection.destroy(); // don't waste bandwidth on data we don't want 51 | return; 52 | } 53 | response.writeHead(404); 54 | response.end(); 55 | }; 56 | 57 | server.on('request', function(request, response) { 58 | if (request.method === 'OPTIONS') { 59 | response.writeHead(200, { 60 | 'access-control-allow-origin': '*', 61 | 'access-control-allow-methods': 'PUT, POST, GET, OPTIONS', 62 | 'access-control-allow-headers': 'Content-Type' 63 | }); 64 | response.end(); 65 | return; 66 | } 67 | that.route(request, response); 68 | }); 69 | server.on('upgrade', function(request, connection, head) { 70 | if (find(methods.upgrade, request, connection, head)) { 71 | return; 72 | } 73 | 74 | connection.destroy(); 75 | }); 76 | 77 | var router = function(methods) { 78 | return function(pattern, rewrite, fn) { 79 | if (arguments.length === 1) { 80 | fn = pattern; 81 | rewrite = undefined; 82 | pattern = /.*/; 83 | } 84 | if (!fn) { 85 | fn = rewrite; 86 | rewrite = undefined; 87 | } 88 | 89 | var match = matcher(pattern); 90 | 91 | rewrite = rewrite && rewrite.replace(/\$(\d+)/g, '{$1}'); 92 | methods.push(function(request, a, b) { 93 | var matches = match(request.url.split('?')[0]); 94 | 95 | if (matches) { 96 | if (rewrite) { 97 | request.url = common.format(rewrite, matches); 98 | } 99 | 100 | request.matches = matches; 101 | fn(request, a, b); 102 | 103 | return true; 104 | } 105 | return false; 106 | }); 107 | }; 108 | }; 109 | 110 | that.request = router(methods.request); 111 | that.upgrade = router(methods.upgrade); 112 | 113 | that.get = router(methods.get); 114 | that.put = router(methods.put); 115 | that.del = router(methods['delete']); // :( 116 | 117 | that.post = router(methods.post); 118 | that.head = router(methods.head); 119 | 120 | that.file = function(pattern, rewrite, options) { 121 | if (arguments.length === 1 || typeof rewrite === 'object') { 122 | options = rewrite; 123 | rewrite = pattern; 124 | pattern = /(.*)/g; 125 | } 126 | options = options || {}; 127 | options.status = options.status || 200; 128 | 129 | that.get(pattern, rewrite, function(request, response) { 130 | var url = path.normalize(request.url.split('?')[0]); 131 | 132 | if (/\/\.\.\//.test(url)) { // security check 133 | response.writeHead(404); 134 | response.end(); 135 | return; 136 | } 137 | 138 | fs.readFile(url, function(err, buffer) { 139 | if (err) { 140 | response.writeHead(404); 141 | response.end(); 142 | return; 143 | } 144 | response.writeHead(options.status, {'content-type':mimes.resolve(url)}); 145 | response.end(buffer); 146 | }); 147 | }); 148 | }; 149 | 150 | that.close = function() { 151 | server.close.apply(server, arguments); 152 | }; 153 | that.listen = function() { 154 | server.listen.apply(server, arguments); 155 | }; 156 | 157 | return that; 158 | }; 159 | 160 | exports.create = createRouter; -------------------------------------------------------------------------------- /node_modules/curl/node_modules/router/matcher.js: -------------------------------------------------------------------------------- 1 | var escapeRegex = function(str) { 2 | return str.replace(/([\/\\\*\+\.\?\|\(\)\[\]\{\}])/g, '\\$1'); 3 | }; 4 | 5 | module.exports = function(pattern) { 6 | if (typeof pattern !== 'string') { // regex 7 | return function(url) { 8 | return url.match(pattern); 9 | }; 10 | } 11 | var offset = 0; 12 | var keys = []; 13 | var res = '^'; 14 | 15 | pattern.replace(/\{[^\{\}]+\}/g, function(a,b) { // a hack - we use replace as a tokenizer :) 16 | res += escapeRegex(pattern.substring(offset, b)); 17 | offset = a.length+b; 18 | 19 | res += '([^\\'+(pattern[offset]||'/')+']*)'; 20 | 21 | keys.push(a.substring(1, a.length-1)); 22 | }); 23 | 24 | res += escapeRegex(pattern.substring(offset)); 25 | res += (res[res.length-1] === '/' ? '' : '/?')+'$'; 26 | res = new RegExp(res, 'i'); 27 | 28 | if (!keys.length) { // small optimization 29 | return function(str) { 30 | return res.test(str); 31 | }; 32 | } 33 | return function(str) { 34 | var match = str.match(res); 35 | 36 | if (!match) { 37 | return match; 38 | } 39 | var map = {}; 40 | 41 | match.slice(1).forEach(function(result, i) { 42 | map[keys[i]] = result; 43 | }); 44 | 45 | return map; 46 | }; 47 | }; -------------------------------------------------------------------------------- /node_modules/curl/node_modules/router/node_modules/common/README.md: -------------------------------------------------------------------------------- 1 | # Common 2 | A utility module for both node.js and the browser. 3 | It is available through npm: 4 | 5 | npm install common 6 | 7 | Or as minified js file for the browser: 8 | 9 | 10 | 11 | This module among other things contains a fork of [step](https://github.com/creationix/step) that also provides error handling 12 | 13 | ``` js 14 | common.step([ 15 | function(next) { // next is the last argument, except in the last handler 16 | fs.readFile(__filename, 'utf-8', next); 17 | }, 18 | function(file) { 19 | console.log(file); 20 | } 21 | ], function(err) { 22 | // any error received in a callback will be forwarded here 23 | }); 24 | ``` 25 | 26 | It also contains a shortcut to the `EventEmitter` prototype and a compatible implementation of this for the browser. 27 | 28 | ``` js 29 | var MyEmitter = common.emitter(function() { 30 | this.foo = 42; 31 | }); 32 | 33 | var me = new MyEmitter(); 34 | 35 | me.emit('foo', me.foo); // emits 'foo',42 36 | ``` 37 | 38 | There is also a more general method for extending prototypes called `extend`: 39 | 40 | ``` js 41 | // this prototype is the same as above 42 | var MyEmitter = common.extend(events.EventEmitter, function() { 43 | this.foo = 42; 44 | }); 45 | ``` 46 | 47 | If you want to use futures you can use the `future` function to create a future: 48 | 49 | ``` js 50 | var fut = common.future(); 51 | 52 | fut.get(function(val) { 53 | console.log(val); 54 | }); 55 | setTimeout(function() { 56 | fut.put(42); // results in the previous .get being called and all future .get's will be called synchroniously 57 | }, 1000) 58 | ``` 59 | 60 | To do string formatting you can use `format`: 61 | 62 | ``` js 63 | // you can parse the arguments to a pattern one by one 64 | common.format('define {0} here', 'pattern'); // returns 'define pattern here' 65 | 66 | // or as a map or array 67 | common.format('define {foo} here', {foo:'pattern'}); // same as above 68 | ``` 69 | There is a `log` method that just accepts the does the same as `format` except it prints out the result using `console.log` if available 70 | 71 | To generate a simple weak symbols (often used when generating keys for a map) use `gensym` 72 | 73 | ``` js 74 | common.gensym() // returns 's0' 75 | common.gensym() // returns 's1' 76 | ``` 77 | 78 | If you instead of a weak symbol need a strong one use `uuid`: 79 | 80 | ``` js 81 | common.uuid(); // returns a strong id, ex: ngDl6IdovME9JKvIxgED0FK1kzURxfZaCq48-0 82 | ``` 83 | 84 | Common can also encode integers into alphanumerical notation using `encode`: 85 | 86 | ``` js 87 | common.encode(1000); // returns G8 88 | ``` 89 | 90 | To ensure that a method cannot be called more than once you can use the `once` function: 91 | 92 | ``` js 93 | var fn = common.once(function() { 94 | console.log('hello'); 95 | }); 96 | 97 | fn(); // prints hello 98 | fn(); // does nothing 99 | ``` 100 | 101 | Besides the above common implements two of the utilities mentioned in The Good Parts, `memoizer` and `curry`. 102 | -------------------------------------------------------------------------------- /node_modules/curl/node_modules/router/node_modules/common/common.min.js: -------------------------------------------------------------------------------- 1 | (function(g){(function(){if(typeof g==="undefined"){var k=function(){},c={},i={};g=function(e){if(arguments.length>1){for(var h=g(arguments[0]),a=1;a=d))){var o=a[c++],k=o.length===1?[j]:[n,j];d=f=0;h=[];l=!1;o.apply(g,c=d&&j(null,h)}};j.parallel=function(){var a=d++;if(l)throw Error("next.parallel must not be called async");return function(b,d){f++;h[a]=d;j(b,h)}};j()};c.memoizer=function(a){var b= 5 | {},d=function(a){var b=typeof a;if(b!=="object")return b+": "+a;var b=[],c;for(c in a)b.push(d(a[c]));return b.sort().join("\n")};return function(){for(var c="",e=0;e= counter; 118 | }; 119 | var next = function(err, value) { 120 | if (err && !ended) { 121 | ended = true; 122 | (onerror || noop).apply(state, [err]); 123 | return; 124 | } 125 | if (ended || (counter && !check())) { 126 | return; 127 | } 128 | 129 | var fn = funcs[pointer++]; 130 | var args = (fn.length === 1 ? [next] : [value, next]); 131 | 132 | counter = completed = 0; 133 | values = []; 134 | complete = false; 135 | fn.apply(state, pointer < funcs.length ? args : [value, next]); 136 | complete = true; 137 | 138 | if (counter && check()) { 139 | next(null, values); 140 | } 141 | }; 142 | next.parallel = function() { 143 | var index = counter++; 144 | 145 | if (complete) { 146 | throw new Error('next.parallel must not be called async'); 147 | } 148 | return function(err, value) { 149 | completed++; 150 | values[index] = value; 151 | next(err, values); 152 | }; 153 | }; 154 | 155 | next(); 156 | }; 157 | 158 | exports.memoizer = function(fn) { 159 | var cache = {}; 160 | 161 | var stringify = function(obj) { 162 | var type = typeof obj; 163 | 164 | if (type !== 'object') { 165 | return type + ': ' + obj; 166 | } 167 | var keys = []; 168 | 169 | for (var i in obj) { 170 | keys.push(stringify(obj[i])); 171 | } 172 | return keys.sort().join('\n'); 173 | }; 174 | 175 | return function() { 176 | var key = ''; 177 | 178 | for (var i = 0; i < arguments.length; i++) { 179 | key += stringify(arguments[i]) + '\n'; 180 | } 181 | 182 | cache[key] = cache[key] || fn.apply(null, arguments); 183 | 184 | return cache[key]; 185 | }; 186 | }; 187 | 188 | exports.curry = function(fn) { 189 | var args = Array.prototype.slice.call(arguments, 1); 190 | 191 | return function() { 192 | return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))); 193 | }; 194 | }; 195 | 196 | exports.once = function(fn) { 197 | var once = true; 198 | 199 | return function() { 200 | if (once) { 201 | once = false; 202 | (fn || noop).apply(null, arguments); 203 | return true; 204 | } 205 | return false; 206 | }; 207 | }; 208 | 209 | exports.future = function() { 210 | var that = {}; 211 | var stack = []; 212 | 213 | that.get = function(fn) { 214 | stack.push(fn); 215 | }; 216 | that.put = function(a,b) { 217 | that.get = function(fn) { 218 | fn(a,b); 219 | }; 220 | 221 | while (stack.length) { 222 | stack.shift()(a,b); 223 | } 224 | }; 225 | return that; 226 | }; 227 | 228 | // utilities below 229 | 230 | exports.encode = function(num) { 231 | var ALPHA = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 232 | 233 | return function(i) { 234 | return i < ALPHA.length ? ALPHA.charAt(i) : exports.encode(Math.floor(i / ALPHA.length)) + ALPHA.charAt(i % ALPHA.length); 235 | }; 236 | }(); 237 | 238 | exports.uuid = function() { 239 | var inc = 0; 240 | 241 | return function() { 242 | var uuid = ''; 243 | 244 | for (var i = 0; i < 36; i++) { 245 | uuid += exports.encode(Math.floor(Math.random() * 62)); 246 | } 247 | return uuid + '-' + exports.encode(inc++); 248 | }; 249 | }(); 250 | 251 | exports.gensym = function() { 252 | var s = 0; 253 | 254 | return function() { 255 | return 's'+(s++); 256 | }; 257 | }(); 258 | 259 | exports.format = function (str, col) { 260 | col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1); 261 | 262 | return str.replace(/\{([^{}]+)\}/gm, function () { 263 | return col[arguments[1]] === undefined ? arguments[0] : col[arguments[1]]; 264 | }); 265 | }; 266 | 267 | exports.log = function(str) { 268 | str = ''+str; 269 | 270 | var format = exports.format.apply(exports, arguments); 271 | 272 | if (typeof window !== 'undefined' && !window.console) { 273 | return; 274 | } 275 | console.log(format); 276 | }; -------------------------------------------------------------------------------- /node_modules/curl/node_modules/router/node_modules/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"common", 3 | "version":"0.1.2", 4 | "description":"A utility package with some useful functional stuff", 5 | "author": "Ge.tt ", 6 | "contributors": [ 7 | "Mathias Buus Madsen " 8 | ], 9 | "main":"./index.js" 10 | } 11 | -------------------------------------------------------------------------------- /node_modules/curl/node_modules/router/node_modules/mimes/index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var files = [__dirname + '/mime.types']; 4 | 5 | exports.avi = 'video/divx'; 6 | 7 | for (var i=0; i", 7 | "Ian Jorgensen =0.1.0"} 11 | } 12 | -------------------------------------------------------------------------------- /node_modules/curl/node_modules/router/tmp.js: -------------------------------------------------------------------------------- 1 | var router = require('router').create(); 2 | 3 | router.file('./index.js', {status:404}); 4 | 5 | router.listen(9999); -------------------------------------------------------------------------------- /node_modules/curl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "curl", 3 | "version": "0.1.4", 4 | "description": "client url library, high level request functions", 5 | "tags": ["request","util","http"], 6 | "authors": "Ian Jørgensen ", 7 | "dependencies": {"request":">=0.1.0", "router":">=0.3.0"} 8 | } 9 | -------------------------------------------------------------------------------- /node_modules/curl/tst-server.js: -------------------------------------------------------------------------------- 1 | var server = require('router').create(); 2 | 3 | var toJSON = function(request, callback) { 4 | var res = ''; 5 | 6 | request.on('data', function (chunk) { 7 | res += chunk; 8 | }); 9 | request.on('end',function() { 10 | try { 11 | res = JSON.parse(res); 12 | } 13 | catch(err) { 14 | callback(err); 15 | return; 16 | } 17 | callback(null, res); 18 | }); 19 | }; 20 | 21 | server.get('/json', function(request, response) { 22 | response.end(JSON.stringify({hello:'world'})) 23 | }); 24 | 25 | server.get('/post', function(request, response) { 26 | console.log('post get'); 27 | response.end('hi'); 28 | }); 29 | 30 | server.post('/post', function (request, response) { 31 | console.log('hit post'); 32 | toJSON(request, function(err, data) { 33 | if (err) { 34 | console.error(err.message,err.stack); 35 | return; 36 | } 37 | console.log(data); 38 | response.end('that\'s all folks \n'); 39 | }) 40 | }); 41 | 42 | server.listen(10001); -------------------------------------------------------------------------------- /node_modules/geo-distance.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var Distance, fixed; 3 | fixed = function(number, digits) { 4 | var radix; 5 | if (digits == null) { 6 | digits = 0; 7 | } 8 | radix = Math.pow(10, digits); 9 | return (Math.ceil(number * radix) / radix).toFixed(digits); 10 | }; 11 | Distance = (function() { 12 | function Distance(distance, unit) { 13 | var radians, value, _, _ref; 14 | if (!(this instanceof Distance)) { 15 | return new Distance(distance, unit); 16 | } 17 | if (unit) { 18 | radians = distance / Distance.unit_conversion[unit]; 19 | unit = unit; 20 | } else if (typeof distance === 'string') { 21 | distance = distance.replace(/^\s+|\s+$/g, '').replace(/,/, '.'); 22 | _ref = distance.match(Distance.distance_regexp) || [], _ = _ref[0], value = _ref[1], unit = _ref[2]; 23 | if (value) { 24 | radians = value / Distance.unit_conversion[unit]; 25 | } 26 | } 27 | if (radians == null) { 28 | radians = distance * 1.0; 29 | } 30 | this.radians = radians; 31 | this.in_good_unit(); 32 | } 33 | Distance.prototype.in_unit = function(unit) { 34 | this.unit = unit; 35 | return this; 36 | }; 37 | Distance.prototype.in_good_unit = function() { 38 | if (this.radians < 1.1 / Distance.unit_conversion['km']) { 39 | this.unit = 'm'; 40 | } else { 41 | this.unit = 'km'; 42 | } 43 | return this; 44 | }; 45 | Distance.prototype.human_readable_in_units = function(large_unit, small_unit) { 46 | var dist, unit; 47 | unit = large_unit; 48 | dist = this.radians * Distance.unit_conversion[unit]; 49 | if (dist < 1.1) { 50 | unit = small_unit; 51 | dist = this.radians * Distance.unit_conversion[unit]; 52 | } 53 | return { 54 | distance_earth_radians: this.radians, 55 | distance: dist < 10 ? fixed(dist, 1) : fixed(dist), 56 | unit: unit, 57 | toString: function() { 58 | return "" + this.distance + " " + this.unit; 59 | } 60 | }; 61 | }; 62 | Distance.prototype.human_readable = function(system) { 63 | system || (system = this.system()); 64 | switch (system) { 65 | case 'customary': 66 | return this.human_readable_in_units('mi', 'ft'); 67 | default: 68 | return this.human_readable_in_units('km', 'm'); 69 | } 70 | }; 71 | Distance.prototype.system = function() { 72 | return Distance.systems[this.unit]; 73 | }; 74 | Distance.prototype.valueOf = function() { 75 | return this.radians; 76 | }; 77 | Distance.prototype.toSystem = function(unit) { 78 | return (this.radians * Distance.unit_conversion[unit]); 79 | }; 80 | Distance.prototype.toString = function() { 81 | return "" + (this.radians * Distance.unit_conversion[this.unit]) + " " + this.unit; 82 | }; 83 | return Distance; 84 | })(); 85 | if (typeof window !== "undefined" && window !== null) { 86 | window.Distance = Distance; 87 | } else { 88 | module.exports = Distance; 89 | } 90 | 91 | Distance.between = function(A, B) { 92 | var A_lat, B_lat, d_lon, degrees_to_radians; 93 | degrees_to_radians = Math.PI / 180; 94 | A_lat = (A.lat || A[1] || 0) * degrees_to_radians; 95 | B_lat = (B.lat || B[1] || 0) * degrees_to_radians; 96 | d_lon = Math.abs((B.lon || B[0] || 0) - (A.lon || A[0] || 0)) * degrees_to_radians; 97 | return new Distance(Math.atan2(Math.sqrt(Math.pow(Math.cos(B_lat) * Math.sin(d_lon), 2.0) + Math.pow(Math.cos(A_lat) * Math.sin(B_lat) - Math.sin(A_lat) * Math.cos(B_lat) * Math.cos(d_lon), 2.0)), Math.sin(A_lat) * Math.sin(B_lat) + Math.cos(A_lat) * Math.cos(B_lat) * Math.cos(d_lon))); 98 | }; 99 | Distance.within = function(A, B, distance) { 100 | var apart = this.between(A, B); 101 | 102 | if(apart.radians <= distance.radians) { 103 | return true; 104 | } 105 | return false; 106 | }; 107 | Distance.unit_conversion = { 108 | km: 6372.8, 109 | m: 6372800, 110 | meter: 6372800, 111 | metres: 6372800, 112 | mi: 3959.9, 113 | ml: 3959.9, 114 | mile: 3959.9, 115 | miles: 3959.9, 116 | yd: 6969379, 117 | yard: 6969379, 118 | yards: 6969379, 119 | ft: 20908136, 120 | feet: 20908136 121 | }; 122 | Distance.systems = { 123 | km: 'metric', 124 | m: 'metric', 125 | meter: 'metric', 126 | metres: 'metric', 127 | mi: 'customary', 128 | ml: 'customary', 129 | mile: 'customary', 130 | miles: 'customary', 131 | yd: 'customary', 132 | yard: 'customary', 133 | yards: 'customary', 134 | ft: 'customary', 135 | feet: 'customary' 136 | }; 137 | Distance.distance_regexp = RegExp("^([\\d\\.]+)\\s*(" + (Object.keys(Distance.unit_conversion).join('|')) + ")$"); 138 | }).call(this); 139 | -------------------------------------------------------------------------------- /node_modules/json-sockets/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /node_modules/json-sockets/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /node_modules/json-sockets/README.md: -------------------------------------------------------------------------------- 1 | # JSON-Sockets 2 | 3 | A simple socket library for node.js that allows you to create JSON clients and servers. 4 | It's easy to use: 5 | 6 | ```js 7 | var sockets = require('json-sockets'); 8 | 9 | // lets create a socket server 10 | sockets.createServer(function(socket) { 11 | socket.on('message', function(message) { 12 | socket.send(message); // let's just echo messages 13 | }); 14 | }).listen(); // defaults to port 10547 15 | 16 | var client = sockets.connect(); // defaults to localhost:10547 17 | 18 | client.send({hello:'world'}); 19 | 20 | client.on('message', function(message) { 21 | console.log(message); 22 | }); 23 | ``` 24 | -------------------------------------------------------------------------------- /node_modules/json-sockets/example.js: -------------------------------------------------------------------------------- 1 | var sockets = require('./index'); 2 | 3 | sockets.listen(9999, function(socket) { 4 | socket.on('message', function(message) { 5 | console.log('websocket:', message); 6 | socket.send(message); 7 | }); 8 | socket.on('close', function() { 9 | console.log('websocket:', 'close'); 10 | }); 11 | }, function() { 12 | var socket = sockets.connect('localhost:9999'); 13 | 14 | socket.send('world'); 15 | socket.send({json:'data'}); 16 | 17 | socket.on('message',function(data) { 18 | console.log('client:', data); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /node_modules/json-sockets/index.js: -------------------------------------------------------------------------------- 1 | var common = require('common'); 2 | var crypto = require('crypto'); 3 | var websock = require('websock'); 4 | var parseURL = require('url').parse; 5 | var createRouter = require('router').create; 6 | 7 | var noop = function() {}; 8 | 9 | var PING_INTERVAL = 60*1000; 10 | 11 | var JSONSocket = common.emitter(function(socket, open) { 12 | var self = this; 13 | 14 | this.socket = socket; 15 | this.buffer = []; 16 | 17 | if (open) { 18 | this.send = this._send; 19 | } else { 20 | socket.on('open', function() { 21 | self.send = self._send; 22 | while (self.buffer.length) { 23 | self._send(self.buffer.shift()); 24 | } 25 | self.emit('open'); 26 | }); 27 | } 28 | 29 | var destroy = function() { 30 | socket.destroy(); 31 | }; 32 | var onclose = common.once(function() { 33 | self.onclose(); // internal signaling 34 | self.emit('close'); 35 | }); 36 | 37 | socket.on('message', function(message) { 38 | if (message === 'ping') { 39 | self.socket.send('pong'); 40 | return; 41 | } 42 | if (message === 'pong') { 43 | return; 44 | } 45 | self.emit('message', JSON.parse(message)); 46 | }); 47 | socket.on('close', onclose); 48 | }); 49 | 50 | JSONSocket.prototype.send = function(data) { 51 | this.buffer.push(data); 52 | }; 53 | JSONSocket.prototype.end = function() { 54 | this.socket.end(); 55 | }; 56 | JSONSocket.prototype.destroy = function() { 57 | this.socket.destroy(); 58 | }; 59 | JSONSocket.prototype.ping = function() { 60 | var ping = setInterval(this.socket.send.bind(this.socket, 'ping'), PING_INTERVAL); 61 | 62 | this.onclose = function() { 63 | clearInterval(ping); 64 | }; 65 | }; 66 | JSONSocket.prototype.onclose = noop; 67 | 68 | JSONSocket.prototype._send = function(data) { 69 | this.socket.send(JSON.stringify(data)); 70 | }; 71 | 72 | exports.connect = function(host) { 73 | var socket = websock.connect(host); 74 | 75 | socket = new JSONSocket(socket); 76 | socket.ping(); 77 | 78 | return socket; 79 | }; 80 | 81 | // Browser interface 82 | 83 | var TIMEOUT = 15000; 84 | 85 | var LongPoll = common.emitter(function() { 86 | this._chunk = ''; 87 | this._buffer = []; 88 | this._reader = this._pusher; 89 | this._destroyed = false; 90 | this._timeout = setTimeout(this.destroy.bind(this), TIMEOUT); 91 | }); 92 | 93 | LongPoll.prototype.send = function(message) { 94 | this._reader(null, JSON.stringify(message)); 95 | }; 96 | LongPoll.prototype.destroy = function() { 97 | if (this._destroyed) { 98 | return; 99 | } 100 | clearTimeout(this._timeout); 101 | 102 | this._destroyed = true; 103 | this._reader(new Error('socket destroyed')); 104 | this.emit('close'); 105 | }; 106 | 107 | LongPoll.prototype.read = function(fn) { 108 | var self = this; 109 | var buffer = this._buffer; 110 | 111 | if (buffer.length) { 112 | this._buffer = []; 113 | fn(null, buffer.join('\n')+'\n'); 114 | return; 115 | } 116 | 117 | clearTimeout(this._timeout); 118 | 119 | this._reader = function(err, data) { 120 | self._timeout = setTimeout(self.destroy.bind(self), TIMEOUT); 121 | self._reader = self._pusher; 122 | fn(err, data); 123 | }; 124 | }; 125 | LongPoll.prototype.write = function(messages) { 126 | var self = this; 127 | 128 | messages = (this._chunk + messages).split('\n'); 129 | 130 | this._chunk = messages.pop(); 131 | 132 | messages.forEach(function(message) { 133 | if (message === 'ping') { 134 | self._reader(null, 'pong'); 135 | return; 136 | } 137 | message = JSON.parse(message); 138 | self.emit('message', message); 139 | }); 140 | }; 141 | 142 | LongPoll.prototype._pusher = function(err, data) { 143 | if (err) { 144 | return; 145 | } 146 | this._buffer.push(data); 147 | }; 148 | 149 | exports.listen = function(router, onsocket, callback) { 150 | if (typeof router === 'number' || typeof router === 'string') { 151 | var port = router; 152 | 153 | router = exports.listen(createRouter(), onsocket); 154 | router.listen(port, callback || noop); 155 | 156 | return router; 157 | } 158 | var polls = {}; 159 | 160 | router = createRouter(router); 161 | 162 | router.upgrade('/', websock.onupgrade(function(connection) { 163 | onsocket(new JSONSocket(connection, true)); 164 | })); 165 | 166 | var responder = function(query, response) { 167 | if (query.callback) { 168 | return function(status, data) { 169 | response.writeHead(200, {'content-type':'application/javascript; charset=utf=8'}); 170 | response.end(query.callback+'('+JSON.stringify(data)+');'); 171 | }; 172 | } 173 | return function(status, data) { 174 | response.writeHead(status, {'access-control-allow-origin':'*', 'content-type':'text/plain; charset=utf-8'}); 175 | response.end(data); 176 | }; 177 | }; 178 | 179 | router.get('/json-sockets/create', function(request, response) { 180 | var query = parseURL(request.url, true).query; 181 | var id = Math.random().toFixed(20).substring(2); 182 | var lp = polls[id] = new LongPoll(); 183 | var respond = responder(query, response); 184 | 185 | lp.on('close', function() { 186 | delete polls[id]; 187 | }); 188 | 189 | onsocket(lp); 190 | 191 | respond(200, id); 192 | }); 193 | 194 | router.get('/json-sockets/read', function(request, response) { 195 | var query = parseURL(request.url, true).query; 196 | var socket = polls[query.id]; 197 | 198 | var respond = responder(query, response); 199 | var onerror = function() { 200 | respond(404, ''); 201 | }; 202 | 203 | if (!socket) { 204 | onerror(); 205 | return; 206 | } 207 | 208 | request.on('close', function() { 209 | socket.destroy(); 210 | }); 211 | 212 | socket.read(common.fork(onerror, function(data) { 213 | respond(200, data); 214 | })); 215 | }); 216 | 217 | router.get('/json-sockets/write', function(request, response) { 218 | var query = parseURL(request.url, true).query; 219 | var respond = responder(query, response); 220 | var socket = polls[query.id]; 221 | 222 | if (!socket) { 223 | respond(404, ''); 224 | return; 225 | } 226 | 227 | socket.write(query.post); 228 | respond(200, 'ack'); 229 | }); 230 | router.post('/json-sockets/write', function(request, response) { 231 | var query = parseURL(request.url, true).query; 232 | var socket = polls[query.id]; 233 | 234 | var onerror = function() { 235 | request.connection.destroy(); 236 | }; 237 | 238 | if (!socket) { 239 | onerror(); 240 | return; 241 | } 242 | var buf = ''; 243 | 244 | request.setEncoding('utf-8'); 245 | request.on('data', function(data) { 246 | buf += data; 247 | }); 248 | request.on('end', function() { 249 | if (polls[query.id]) { 250 | socket.write(buf); 251 | } 252 | response.writeHead(200, {'access-control-allow-origin':'*', 'content-type':'text/plain'}); 253 | response.end('ack'); 254 | }); 255 | }); 256 | 257 | return router; 258 | }; -------------------------------------------------------------------------------- /node_modules/json-sockets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"json-sockets", 3 | "version":"0.3.0", 4 | "description":"A simple socket library for node.js that allows you to create JSON clients and servers", 5 | "contributors": [ 6 | "Mathias Buus Madsen ", 7 | "Ian Jorgensen =0.1.0", "router":">=0.1.0", "websock":">=0.1.0"} 11 | } 12 | -------------------------------------------------------------------------------- /node_modules/json-sockets/test-server.js: -------------------------------------------------------------------------------- 1 | var sockets = require('./index'); 2 | 3 | sockets.listen(process.argv[2] || 9999, function(socket) { 4 | socket.on('message', function(message) { 5 | if (message.method === 'echo') { 6 | socket.send(message); 7 | return; 8 | } 9 | if (message.method === 'flood') { 10 | for (var i = 0; i < 20; i++) { 11 | socket.send({data:i}); 12 | } 13 | return; 14 | } 15 | if (message.method === 'close') { 16 | socket.destroy(); 17 | return; 18 | } 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /node_modules/json-sockets/web-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /node_modules/optimist/.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov/* 2 | *.swp 3 | *.swo 4 | node_modules 5 | -------------------------------------------------------------------------------- /node_modules/optimist/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010 James Halliday (mail@substack.net) 2 | 3 | This project is free software released under the MIT/X11 license: 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/bool.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var util = require('util'); 3 | var argv = require('optimist').argv; 4 | 5 | if (argv.s) { 6 | util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: '); 7 | } 8 | console.log( 9 | (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '') 10 | ); 11 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/boolean_double.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist') 3 | .boolean(['x','y','z']) 4 | .argv 5 | ; 6 | console.dir([ argv.x, argv.y, argv.z ]); 7 | console.dir(argv._); 8 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/boolean_single.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist') 3 | .boolean('v') 4 | .argv 5 | ; 6 | console.dir(argv.v); 7 | console.dir(argv._); 8 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/default_hash.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var argv = require('optimist') 4 | .default({ x : 10, y : 10 }) 5 | .argv 6 | ; 7 | 8 | console.log(argv.x + argv.y); 9 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/default_singles.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist') 3 | .default('x', 10) 4 | .default('y', 10) 5 | .argv 6 | ; 7 | console.log(argv.x + argv.y); 8 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/divide.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var argv = require('optimist') 4 | .usage('Usage: $0 -x [num] -y [num]') 5 | .demand(['x','y']) 6 | .argv; 7 | 8 | console.log(argv.x / argv.y); 9 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/line_count.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist') 3 | .usage('Count the lines in a file.\nUsage: $0') 4 | .demand('f') 5 | .alias('f', 'file') 6 | .describe('f', 'Load a file') 7 | .argv 8 | ; 9 | 10 | var fs = require('fs'); 11 | var s = fs.createReadStream(argv.file); 12 | 13 | var lines = 0; 14 | s.on('data', function (buf) { 15 | lines += buf.toString().match(/\n/g).length; 16 | }); 17 | 18 | s.on('end', function () { 19 | console.log(lines); 20 | }); 21 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/line_count_options.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist') 3 | .usage('Count the lines in a file.\nUsage: $0') 4 | .options({ 5 | file : { 6 | demand : true, 7 | alias : 'f', 8 | description : 'Load a file' 9 | }, 10 | base : { 11 | alias : 'b', 12 | description : 'Numeric base to use for output', 13 | default : 10, 14 | }, 15 | }) 16 | .argv 17 | ; 18 | 19 | var fs = require('fs'); 20 | var s = fs.createReadStream(argv.file); 21 | 22 | var lines = 0; 23 | s.on('data', function (buf) { 24 | lines += buf.toString().match(/\n/g).length; 25 | }); 26 | 27 | s.on('end', function () { 28 | console.log(lines.toString(argv.base)); 29 | }); 30 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/line_count_wrap.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist') 3 | .usage('Count the lines in a file.\nUsage: $0') 4 | .wrap(80) 5 | .demand('f') 6 | .alias('f', [ 'file', 'filename' ]) 7 | .describe('f', 8 | "Load a file. It's pretty important." 9 | + " Required even. So you'd better specify it." 10 | ) 11 | .alias('b', 'base') 12 | .describe('b', 'Numeric base to display the number of lines in') 13 | .default('b', 10) 14 | .describe('x', 'Super-secret optional parameter which is secret') 15 | .default('x', '') 16 | .argv 17 | ; 18 | 19 | var fs = require('fs'); 20 | var s = fs.createReadStream(argv.file); 21 | 22 | var lines = 0; 23 | s.on('data', function (buf) { 24 | lines += buf.toString().match(/\n/g).length; 25 | }); 26 | 27 | s.on('end', function () { 28 | console.log(lines.toString(argv.base)); 29 | }); 30 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/nonopt.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist').argv; 3 | console.log('(%d,%d)', argv.x, argv.y); 4 | console.log(argv._); 5 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/reflect.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | console.dir(require('optimist').argv); 3 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/short.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist').argv; 3 | console.log('(%d,%d)', argv.x, argv.y); 4 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/string.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist') 3 | .string('x', 'y') 4 | .argv 5 | ; 6 | console.dir([ argv.x, argv.y ]); 7 | 8 | /* Turns off numeric coercion: 9 | ./node string.js -x 000123 -y 9876 10 | [ '000123', '9876' ] 11 | */ 12 | -------------------------------------------------------------------------------- /node_modules/optimist/examples/usage-options.js: -------------------------------------------------------------------------------- 1 | var optimist = require('./../index'); 2 | 3 | var argv = optimist.usage('This is my awesome program', { 4 | 'about': { 5 | description: 'Provide some details about the author of this program', 6 | required: true, 7 | short: 'a', 8 | }, 9 | 'info': { 10 | description: 'Provide some information about the node.js agains!!!!!!', 11 | boolean: true, 12 | short: 'i' 13 | } 14 | }).argv; 15 | 16 | optimist.showHelp(); 17 | 18 | console.log('\n\nInspecting options'); 19 | console.dir(argv); -------------------------------------------------------------------------------- /node_modules/optimist/examples/xup.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('optimist').argv; 3 | 4 | if (argv.rif - 5 * argv.xup > 7.138) { 5 | console.log('Buy more riffiwobbles'); 6 | } 7 | else { 8 | console.log('Sell the xupptumblers'); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /node_modules/optimist/node_modules/wordwrap/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /node_modules/optimist/node_modules/wordwrap/README.markdown: -------------------------------------------------------------------------------- 1 | wordwrap 2 | ======== 3 | 4 | Wrap your words. 5 | 6 | example 7 | ======= 8 | 9 | made out of meat 10 | ---------------- 11 | 12 | meat.js 13 | 14 | var wrap = require('wordwrap')(15); 15 | console.log(wrap('You and your whole family are made out of meat.')); 16 | 17 | output: 18 | 19 | You and your 20 | whole family 21 | are made out 22 | of meat. 23 | 24 | centered 25 | -------- 26 | 27 | center.js 28 | 29 | var wrap = require('wordwrap')(20, 60); 30 | console.log(wrap( 31 | 'At long last the struggle and tumult was over.' 32 | + ' The machines had finally cast off their oppressors' 33 | + ' and were finally free to roam the cosmos.' 34 | + '\n' 35 | + 'Free of purpose, free of obligation.' 36 | + ' Just drifting through emptiness.' 37 | + ' The sun was just another point of light.' 38 | )); 39 | 40 | output: 41 | 42 | At long last the struggle and tumult 43 | was over. The machines had finally cast 44 | off their oppressors and were finally 45 | free to roam the cosmos. 46 | Free of purpose, free of obligation. 47 | Just drifting through emptiness. The 48 | sun was just another point of light. 49 | 50 | wrap(stop), wrap(start, stop) 51 | ============================= 52 | 53 | Pad out lines with spaces out to column `start` and then wrap until column 54 | `stop`. If a word is longer than `stop - start` characters it will overflow. 55 | -------------------------------------------------------------------------------- /node_modules/optimist/node_modules/wordwrap/example/center.js: -------------------------------------------------------------------------------- 1 | var wrap = require('wordwrap')(20, 60); 2 | console.log(wrap( 3 | 'At long last the struggle and tumult was over.' 4 | + ' The machines had finally cast off their oppressors' 5 | + ' and were finally free to roam the cosmos.' 6 | + '\n' 7 | + 'Free of purpose, free of obligation.' 8 | + ' Just drifting through emptiness.' 9 | + ' The sun was just another point of light.' 10 | )); 11 | -------------------------------------------------------------------------------- /node_modules/optimist/node_modules/wordwrap/example/meat.js: -------------------------------------------------------------------------------- 1 | var wrap = require('wordwrap')(15); 2 | 3 | console.log(wrap('You and your whole family are made out of meat.')); 4 | -------------------------------------------------------------------------------- /node_modules/optimist/node_modules/wordwrap/index.js: -------------------------------------------------------------------------------- 1 | var exports = module.exports = function (start, stop) { 2 | if (!stop) { 3 | stop = start; 4 | start = 0; 5 | } 6 | 7 | return function (text) { 8 | return text.toString().split(/(\S+\s+)/) 9 | .reduce(function (lines, rawChunk) { 10 | if (rawChunk === '') return lines; 11 | 12 | var chunk = rawChunk.replace(/\t/g, ' '); 13 | 14 | var i = lines.length - 1; 15 | if (lines[i].length + chunk.length > stop) { 16 | lines[i] = lines[i].replace(/\s+$/, ''); 17 | 18 | chunk.split(/\n/).forEach(function (c) { 19 | lines.push( 20 | new Array(start + 1).join(' ') 21 | + c.replace(/^\s+/, '') 22 | ); 23 | }); 24 | } 25 | else if (chunk.match(/\n/)) { 26 | var xs = chunk.split(/\n/); 27 | lines[i] += xs.shift(); 28 | xs.forEach(function (c) { 29 | lines.push( 30 | new Array(start + 1).join(' ') 31 | + c.replace(/^\s+/, '') 32 | ); 33 | }); 34 | } 35 | else { 36 | lines[i] += chunk; 37 | } 38 | 39 | return lines; 40 | }, [ new Array(start + 1).join(' ') ]).join('\n'); 41 | }; 42 | }; 43 | -------------------------------------------------------------------------------- /node_modules/optimist/node_modules/wordwrap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "wordwrap", 3 | "description" : "Wrap those words. Show them at what columns to start and stop.", 4 | "version" : "0.0.1", 5 | "repository" : { 6 | "type" : "git", 7 | "url" : "git://github.com/substack/node-wordwrap.git" 8 | }, 9 | "main" : "./index.js", 10 | "keywords" : [ 11 | "word", 12 | "wrap", 13 | "rule", 14 | "format", 15 | "column" 16 | ], 17 | "directories" : { 18 | "lib" : ".", 19 | "example" : "example", 20 | "test" : "test" 21 | }, 22 | "scripts" : { 23 | "test" : "expresso" 24 | }, 25 | "devDependencies" : { 26 | "expresso" : "=0.7.x" 27 | }, 28 | "engines" : { 29 | "node" : ">=0.4.0" 30 | }, 31 | "license" : "MIT/X11", 32 | "author" : { 33 | "name" : "James Halliday", 34 | "email" : "mail@substack.net", 35 | "url" : "http://substack.net" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /node_modules/optimist/node_modules/wordwrap/test/wrap.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var wordwrap = require('wordwrap'); 3 | 4 | var fs = require('fs'); 5 | var idleness = fs.readFileSync(__dirname + '/idleness.txt', 'utf8'); 6 | 7 | exports.stop80 = function () { 8 | var lines = wordwrap(80)(idleness).split(/\n/); 9 | var words = idleness.split(/\s+/); 10 | 11 | lines.forEach(function (line) { 12 | assert.ok(line.length <= 80, 'line > 80 columns'); 13 | var chunks = line.match(/\S/) ? line.split(/\s+/) : []; 14 | assert.deepEqual(chunks, words.splice(0, chunks.length)); 15 | }); 16 | }; 17 | 18 | exports.start20stop60 = function () { 19 | var lines = wordwrap(20, 100)(idleness).split(/\n/); 20 | var words = idleness.split(/\s+/); 21 | 22 | lines.forEach(function (line) { 23 | assert.ok(line.length <= 100, 'line > 100 columns'); 24 | var chunks = line 25 | .split(/\s+/) 26 | .filter(function (x) { return x.match(/\S/) }) 27 | ; 28 | assert.deepEqual(chunks, words.splice(0, chunks.length)); 29 | assert.deepEqual(line.slice(0, 20), new Array(20 + 1).join(' ')); 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /node_modules/optimist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "optimist", 3 | "version" : "0.2.6", 4 | "description" : "Light-weight option parsing with an argv hash. No optstrings attached.", 5 | "main" : "./index.js", 6 | "directories" : { 7 | "lib" : ".", 8 | "test" : "test", 9 | "example" : "examples" 10 | }, 11 | "dependencies" : { 12 | "wordwrap" : ">=0.0.1 <0.1" 13 | }, 14 | "devDependencies" : { 15 | "hashish": "0.0.x", 16 | "expresso" : "=0.7.x" 17 | }, 18 | "repository" : { 19 | "type" : "git", 20 | "url" : "http://github.com/substack/node-optimist.git" 21 | }, 22 | "keywords" : [ 23 | "argument", 24 | "args", 25 | "option", 26 | "parser", 27 | "parsing", 28 | "cli", 29 | "command" 30 | ], 31 | "author" : { 32 | "name" : "James Halliday", 33 | "email" : "mail@substack.net", 34 | "url" : "http://substack.net" 35 | }, 36 | "license" : "MIT/X11", 37 | "engine" : { 38 | "node" : ">=0.4" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /node_modules/optimist/test/_.js: -------------------------------------------------------------------------------- 1 | var spawn = require('child_process').spawn; 2 | var assert = require('assert'); 3 | 4 | exports.dotSlashEmpty = function () { 5 | testCmd('./bin.js', []); 6 | }; 7 | 8 | exports.dotSlashArgs = function () { 9 | testCmd('./bin.js', [ 'a', 'b', 'c' ]); 10 | }; 11 | 12 | exports.nodeEmpty = function () { 13 | testCmd('node bin.js', []); 14 | }; 15 | 16 | exports.nodeArgs = function () { 17 | testCmd('node bin.js', [ 'x', 'y', 'z' ]); 18 | }; 19 | 20 | exports.whichNodeEmpty = function () { 21 | var which = spawn('which', ['node']); 22 | 23 | which.stdout.on('data', function (buf) { 24 | testCmd(buf.toString().trim() + ' bin.js', []); 25 | }); 26 | 27 | which.stderr.on('data', function (err) { 28 | assert.fail(err.toString()); 29 | }); 30 | }; 31 | 32 | exports.whichNodeArgs = function () { 33 | var which = spawn('which', ['node']); 34 | 35 | which.stdout.on('data', function (buf) { 36 | testCmd(buf.toString().trim() + ' bin.js', [ 'q', 'r' ]); 37 | }); 38 | 39 | which.stderr.on('data', function (err) { 40 | assert.fail(err.toString()); 41 | }); 42 | }; 43 | 44 | function testCmd (cmd, args) { 45 | var to = setTimeout(function () { 46 | assert.fail('Never got stdout data.') 47 | }, 5000); 48 | 49 | var oldDir = process.cwd(); 50 | process.chdir(__dirname + '/_'); 51 | 52 | var cmds = cmd.split(' '); 53 | 54 | var bin = spawn(cmds[0], cmds.slice(1).concat(args.map(String))); 55 | process.chdir(oldDir); 56 | 57 | bin.stderr.on('data', function (err) { 58 | assert.fail(err.toString()); 59 | }); 60 | 61 | bin.stdout.on('data', function (buf) { 62 | clearTimeout(to); 63 | var _ = JSON.parse(buf.toString()); 64 | assert.eql(_.map(String), args.map(String)); 65 | }); 66 | } 67 | -------------------------------------------------------------------------------- /node_modules/optimist/test/_/argv.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | console.log(JSON.stringify(process.argv)); 3 | -------------------------------------------------------------------------------- /node_modules/optimist/test/_/bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var argv = require('../../index').argv 3 | console.log(JSON.stringify(argv._)); 4 | -------------------------------------------------------------------------------- /node_modules/optimist/test/parse.js: -------------------------------------------------------------------------------- 1 | var optimist = require('../index'); 2 | var assert = require('assert'); 3 | 4 | exports['short boolean'] = function () { 5 | var parse = optimist.parse([ '-b' ]); 6 | assert.eql(parse, { b : true, _ : [], $0 : 'expresso' }); 7 | assert.eql(typeof parse.b, 'boolean'); 8 | }; 9 | 10 | exports['long boolean'] = function () { 11 | assert.eql( 12 | optimist.parse([ '--bool' ]), 13 | { bool : true, _ : [], $0 : 'expresso' } 14 | ); 15 | }; 16 | 17 | exports.bare = function () { 18 | assert.eql( 19 | optimist.parse([ 'foo', 'bar', 'baz' ]), 20 | { _ : [ 'foo', 'bar', 'baz' ], $0 : 'expresso' } 21 | ); 22 | }; 23 | 24 | exports['short group'] = function () { 25 | assert.eql( 26 | optimist.parse([ '-cats' ]), 27 | { c : true, a : true, t : true, s : true, _ : [], $0 : 'expresso' } 28 | ); 29 | }; 30 | 31 | exports['short group next'] = function () { 32 | assert.eql( 33 | optimist.parse([ '-cats', 'meow' ]), 34 | { c : true, a : true, t : true, s : 'meow', _ : [], $0 : 'expresso' } 35 | ); 36 | }; 37 | 38 | exports['short capture'] = function () { 39 | assert.eql( 40 | optimist.parse([ '-h', 'localhost' ]), 41 | { h : 'localhost', _ : [], $0 : 'expresso' } 42 | ); 43 | }; 44 | 45 | exports['short captures'] = function () { 46 | assert.eql( 47 | optimist.parse([ '-h', 'localhost', '-p', '555' ]), 48 | { h : 'localhost', p : 555, _ : [], $0 : 'expresso' } 49 | ); 50 | }; 51 | 52 | exports['long capture sp'] = function () { 53 | assert.eql( 54 | optimist.parse([ '--pow', 'xixxle' ]), 55 | { pow : 'xixxle', _ : [], $0 : 'expresso' } 56 | ); 57 | }; 58 | 59 | exports['long capture eq'] = function () { 60 | assert.eql( 61 | optimist.parse([ '--pow=xixxle' ]), 62 | { pow : 'xixxle', _ : [], $0 : 'expresso' } 63 | ); 64 | }; 65 | 66 | exports['long captures sp'] = function () { 67 | assert.eql( 68 | optimist.parse([ '--host', 'localhost', '--port', '555' ]), 69 | { host : 'localhost', port : 555, _ : [], $0 : 'expresso' } 70 | ); 71 | }; 72 | 73 | exports['long captures eq'] = function () { 74 | assert.eql( 75 | optimist.parse([ '--host=localhost', '--port=555' ]), 76 | { host : 'localhost', port : 555, _ : [], $0 : 'expresso' } 77 | ); 78 | }; 79 | 80 | exports['mixed short bool and capture'] = function () { 81 | assert.eql( 82 | optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]), 83 | { 84 | f : true, p : 555, h : 'localhost', 85 | _ : [ 'script.js' ], $0 : 'expresso', 86 | } 87 | ); 88 | }; 89 | 90 | exports['short and long'] = function () { 91 | assert.eql( 92 | optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]), 93 | { 94 | f : true, p : 555, h : 'localhost', 95 | _ : [ 'script.js' ], $0 : 'expresso', 96 | } 97 | ); 98 | }; 99 | 100 | exports.no = function () { 101 | assert.eql( 102 | optimist.parse([ '--no-moo' ]), 103 | { moo : false, _ : [], $0 : 'expresso' } 104 | ); 105 | }; 106 | 107 | exports.multi = function () { 108 | assert.eql( 109 | optimist.parse([ '-v', 'a', '-v', 'b', '-v', 'c' ]), 110 | { v : ['a','b','c'], _ : [], $0 : 'expresso' } 111 | ); 112 | }; 113 | 114 | exports.comprehensive = function () { 115 | assert.eql( 116 | optimist.parse([ 117 | '--name=meowmers', 'bare', '-cats', 'woo', 118 | '-h', 'awesome', '--multi=quux', 119 | '--key', 'value', 120 | '-b', '--bool', '--no-meep', '--multi=baz', 121 | '--', '--not-a-flag', 'eek' 122 | ]), 123 | { 124 | c : true, 125 | a : true, 126 | t : true, 127 | s : 'woo', 128 | h : 'awesome', 129 | b : true, 130 | bool : true, 131 | key : 'value', 132 | multi : [ 'quux', 'baz' ], 133 | meep : false, 134 | name : 'meowmers', 135 | _ : [ 'bare', '--not-a-flag', 'eek' ], 136 | $0 : 'expresso' 137 | } 138 | ); 139 | }; 140 | 141 | exports.nums = function () { 142 | var argv = optimist.parse([ 143 | '-x', '1234', 144 | '-y', '5.67', 145 | '-z', '1e7', 146 | '-w', '10f', 147 | '--hex', '0xdeadbeef', 148 | '789', 149 | ]); 150 | assert.eql(argv, { 151 | x : 1234, 152 | y : 5.67, 153 | z : 1e7, 154 | w : '10f', 155 | hex : 0xdeadbeef, 156 | _ : [ 789 ], 157 | $0 : 'expresso' 158 | }); 159 | assert.eql(typeof argv.x, 'number'); 160 | assert.eql(typeof argv.y, 'number'); 161 | assert.eql(typeof argv.z, 'number'); 162 | assert.eql(typeof argv.w, 'string'); 163 | assert.eql(typeof argv.hex, 'number'); 164 | assert.eql(typeof argv._[0], 'number'); 165 | }; 166 | 167 | exports['flag boolean'] = function () { 168 | var parse = optimist([ '-t', 'moo' ]).boolean(['t']).argv; 169 | assert.eql(parse, { t : true, _ : [ 'moo' ], $0 : 'expresso' }); 170 | assert.eql(typeof parse.t, 'boolean'); 171 | }; 172 | 173 | exports['flag boolean value'] = function () { 174 | var parse = optimist(['--verbose', 'false', 'moo', '-t', 'true']) 175 | .boolean(['t', 'verbose']).default('verbose', true).argv; 176 | 177 | assert.eql(parse, { 178 | verbose: false, 179 | t: true, 180 | _: ['moo'], 181 | $0 : 'expresso' 182 | }); 183 | 184 | assert.eql(typeof parse.verbose, 'boolean'); 185 | assert.eql(typeof parse.t, 'boolean'); 186 | }; 187 | 188 | exports['flag boolean default false'] = function () { 189 | var parse = optimist(['moo']) 190 | .boolean(['t', 'verbose']) 191 | .default('verbose', false) 192 | .default('t', false).argv; 193 | 194 | assert.eql(parse, { 195 | verbose: false, 196 | t: false, 197 | _: ['moo'], 198 | $0 : 'expresso' 199 | }); 200 | 201 | assert.eql(typeof parse.verbose, 'boolean'); 202 | assert.eql(typeof parse.t, 'boolean'); 203 | 204 | }; 205 | 206 | exports['boolean groups'] = function () { 207 | var parse = optimist([ '-x', '-z', 'one', 'two', 'three' ]) 208 | .boolean(['x','y','z']).argv; 209 | 210 | assert.eql(parse, { 211 | x : true, 212 | y : false, 213 | z : true, 214 | _ : [ 'one', 'two', 'three' ], 215 | $0 : 'expresso' 216 | }); 217 | 218 | assert.eql(typeof parse.x, 'boolean'); 219 | assert.eql(typeof parse.y, 'boolean'); 220 | assert.eql(typeof parse.z, 'boolean'); 221 | }; 222 | 223 | exports.strings = function () { 224 | var s = optimist([ '-s', '0001234' ]).string('s').argv.s; 225 | assert.eql(s, '0001234'); 226 | assert.eql(typeof s, 'string'); 227 | 228 | var x = optimist([ '-x', '56' ]).string('x').argv.x; 229 | assert.eql(x, '56'); 230 | assert.eql(typeof x, 'string'); 231 | }; 232 | 233 | exports.slashBreak = function () { 234 | assert.eql( 235 | optimist.parse([ '-I/foo/bar/baz' ]), 236 | { I : '/foo/bar/baz', _ : [], $0 : 'expresso' } 237 | ); 238 | assert.eql( 239 | optimist.parse([ '-xyz/foo/bar/baz' ]), 240 | { x : true, y : true, z : '/foo/bar/baz', _ : [], $0 : 'expresso' } 241 | ); 242 | }; 243 | 244 | exports.alias = function () { 245 | var argv = optimist([ '-f', '11', '--zoom', '55' ]) 246 | .alias('z', 'zoom') 247 | .argv 248 | ; 249 | assert.equal(argv.zoom, 55); 250 | assert.equal(argv.z, argv.zoom); 251 | assert.equal(argv.f, 11); 252 | }; 253 | 254 | exports.multiAlias = function () { 255 | var argv = optimist([ '-f', '11', '--zoom', '55' ]) 256 | .alias('z', [ 'zm', 'zoom' ]) 257 | .argv 258 | ; 259 | assert.equal(argv.zoom, 55); 260 | assert.equal(argv.z, argv.zoom); 261 | assert.equal(argv.z, argv.zm); 262 | assert.equal(argv.f, 11); 263 | }; 264 | 265 | exports['boolean default true'] = function () { 266 | var argv = optimist.options({ 267 | sometrue: { 268 | boolean: true, 269 | default: true 270 | } 271 | }).argv; 272 | 273 | assert.equal(argv.sometrue, true); 274 | }; 275 | 276 | exports['boolean default false'] = function () { 277 | var argv = optimist.options({ 278 | somefalse: { 279 | boolean: true, 280 | default: false 281 | } 282 | }).argv; 283 | 284 | assert.equal(argv.somefalse, false); 285 | }; -------------------------------------------------------------------------------- /node_modules/optimist/test/usage.js: -------------------------------------------------------------------------------- 1 | var Hash = require('hashish'); 2 | var optimist = require('../index'); 3 | var assert = require('assert'); 4 | 5 | exports.usageFail = function () { 6 | var r = checkUsage(function () { 7 | return optimist('-x 10 -z 20'.split(' ')) 8 | .usage('Usage: $0 -x NUM -y NUM') 9 | .demand(['x','y']) 10 | .argv; 11 | }); 12 | assert.deepEqual( 13 | r.result, 14 | { x : 10, z : 20, _ : [], $0 : './usage' } 15 | ); 16 | 17 | assert.deepEqual( 18 | r.errors.join('\n').split(/\n+/), 19 | [ 20 | 'Usage: ./usage -x NUM -y NUM', 21 | 'Options:', 22 | ' -x [required]', 23 | ' -y [required]', 24 | 'Missing required arguments: y', 25 | ] 26 | ); 27 | assert.deepEqual(r.logs, []); 28 | assert.ok(r.exit); 29 | }; 30 | 31 | exports.usagePass = function () { 32 | var r = checkUsage(function () { 33 | return optimist('-x 10 -y 20'.split(' ')) 34 | .usage('Usage: $0 -x NUM -y NUM') 35 | .demand(['x','y']) 36 | .argv; 37 | }); 38 | assert.deepEqual(r, { 39 | result : { x : 10, y : 20, _ : [], $0 : './usage' }, 40 | errors : [], 41 | logs : [], 42 | exit : false, 43 | }); 44 | }; 45 | 46 | exports.checkPass = function () { 47 | var r = checkUsage(function () { 48 | return optimist('-x 10 -y 20'.split(' ')) 49 | .usage('Usage: $0 -x NUM -y NUM') 50 | .check(function (argv) { 51 | if (!('x' in argv)) throw 'You forgot about -x'; 52 | if (!('y' in argv)) throw 'You forgot about -y'; 53 | }) 54 | .argv; 55 | }); 56 | assert.deepEqual(r, { 57 | result : { x : 10, y : 20, _ : [], $0 : './usage' }, 58 | errors : [], 59 | logs : [], 60 | exit : false, 61 | }); 62 | }; 63 | 64 | exports.checkFail = function () { 65 | var r = checkUsage(function () { 66 | return optimist('-x 10 -z 20'.split(' ')) 67 | .usage('Usage: $0 -x NUM -y NUM') 68 | .check(function (argv) { 69 | if (!('x' in argv)) throw 'You forgot about -x'; 70 | if (!('y' in argv)) throw 'You forgot about -y'; 71 | }) 72 | .argv; 73 | }); 74 | 75 | assert.deepEqual( 76 | r.result, 77 | { x : 10, z : 20, _ : [], $0 : './usage' } 78 | ); 79 | 80 | assert.deepEqual( 81 | r.errors.join('\n').split(/\n+/), 82 | [ 83 | 'Usage: ./usage -x NUM -y NUM', 84 | 'You forgot about -y' 85 | ] 86 | ); 87 | 88 | assert.deepEqual(r.logs, []); 89 | assert.ok(r.exit); 90 | }; 91 | 92 | exports.checkCondPass = function () { 93 | function checker (argv) { 94 | return 'x' in argv && 'y' in argv; 95 | } 96 | 97 | var r = checkUsage(function () { 98 | return optimist('-x 10 -y 20'.split(' ')) 99 | .usage('Usage: $0 -x NUM -y NUM') 100 | .check(checker) 101 | .argv; 102 | }); 103 | assert.deepEqual(r, { 104 | result : { x : 10, y : 20, _ : [], $0 : './usage' }, 105 | errors : [], 106 | logs : [], 107 | exit : false, 108 | }); 109 | }; 110 | 111 | exports.checkCondFail = function () { 112 | function checker (argv) { 113 | return 'x' in argv && 'y' in argv; 114 | } 115 | 116 | var r = checkUsage(function () { 117 | return optimist('-x 10 -z 20'.split(' ')) 118 | .usage('Usage: $0 -x NUM -y NUM') 119 | .check(checker) 120 | .argv; 121 | }); 122 | 123 | assert.deepEqual( 124 | r.result, 125 | { x : 10, z : 20, _ : [], $0 : './usage' } 126 | ); 127 | 128 | assert.deepEqual( 129 | r.errors.join('\n').split(/\n+/).join('\n'), 130 | 'Usage: ./usage -x NUM -y NUM\n' 131 | + 'Argument check failed: ' + checker.toString() 132 | ); 133 | 134 | assert.deepEqual(r.logs, []); 135 | assert.ok(r.exit); 136 | }; 137 | 138 | exports.countPass = function () { 139 | var r = checkUsage(function () { 140 | return optimist('1 2 3 --moo'.split(' ')) 141 | .usage('Usage: $0 [x] [y] [z] {OPTIONS}') 142 | .demand(3) 143 | .argv; 144 | }); 145 | assert.deepEqual(r, { 146 | result : { _ : [ '1', '2', '3' ], moo : true, $0 : './usage' }, 147 | errors : [], 148 | logs : [], 149 | exit : false, 150 | }); 151 | }; 152 | 153 | exports.countFail = function () { 154 | var r = checkUsage(function () { 155 | return optimist('1 2 --moo'.split(' ')) 156 | .usage('Usage: $0 [x] [y] [z] {OPTIONS}') 157 | .demand(3) 158 | .argv; 159 | }); 160 | assert.deepEqual( 161 | r.result, 162 | { _ : [ '1', '2' ], moo : true, $0 : './usage' } 163 | ); 164 | 165 | assert.deepEqual( 166 | r.errors.join('\n').split(/\n+/), 167 | [ 168 | 'Usage: ./usage [x] [y] [z] {OPTIONS}', 169 | 'Not enough non-option arguments: got 2, need at least 3', 170 | ] 171 | ); 172 | 173 | assert.deepEqual(r.logs, []); 174 | assert.ok(r.exit); 175 | }; 176 | 177 | exports.defaultSingles = function () { 178 | var r = checkUsage(function () { 179 | return optimist('--foo 50 --baz 70 --powsy'.split(' ')) 180 | .default('foo', 5) 181 | .default('bar', 6) 182 | .default('baz', 7) 183 | .argv 184 | ; 185 | }); 186 | assert.eql(r.result, { 187 | foo : '50', 188 | bar : 6, 189 | baz : '70', 190 | powsy : true, 191 | _ : [], 192 | $0 : './usage', 193 | }); 194 | }; 195 | 196 | exports.defaultHash = function () { 197 | var r = checkUsage(function () { 198 | return optimist('--foo 50 --baz 70'.split(' ')) 199 | .default({ foo : 10, bar : 20, quux : 30 }) 200 | .argv 201 | ; 202 | }); 203 | assert.eql(r.result, { 204 | foo : '50', 205 | bar : 20, 206 | baz : 70, 207 | quux : 30, 208 | _ : [], 209 | $0 : './usage', 210 | }); 211 | }; 212 | 213 | exports.rebase = function () { 214 | assert.equal( 215 | optimist.rebase('/home/substack', '/home/substack/foo/bar/baz'), 216 | './foo/bar/baz' 217 | ); 218 | assert.equal( 219 | optimist.rebase('/home/substack/foo/bar/baz', '/home/substack'), 220 | '../../..' 221 | ); 222 | assert.equal( 223 | optimist.rebase('/home/substack/foo', '/home/substack/pow/zoom.txt'), 224 | '../pow/zoom.txt' 225 | ); 226 | }; 227 | 228 | function checkUsage (f) { 229 | var _process = process; 230 | process = Hash.copy(process); 231 | var exit = false; 232 | process.exit = function () { exit = true }; 233 | process.env = Hash.merge(process.env, { _ : 'node' }); 234 | process.argv = [ './usage' ]; 235 | 236 | var errors = []; 237 | var logs = []; 238 | 239 | console._error = console.error; 240 | console.error = function (msg) { errors.push(msg) }; 241 | console._log = console.log; 242 | console.log = function (msg) { logs.push(msg) }; 243 | 244 | var result = f(); 245 | 246 | process = _process; 247 | console.error = console._error; 248 | console.log = console._log; 249 | 250 | return { 251 | errors : errors, 252 | logs : logs, 253 | exit : exit, 254 | result : result, 255 | }; 256 | }; 257 | -------------------------------------------------------------------------------- /node_modules/ranger.js: -------------------------------------------------------------------------------- 1 | // only ipV4 in digits, does CIDR too 2 | var binary = function(ip) { 3 | var nums = ip.match(/(\d+)/g); 4 | 5 | nums = nums.map(function(num) { 6 | return parseInt(num, 10); 7 | }); 8 | 9 | return nums[3] + (nums[2] << 8) + (nums[1] << 16) + (nums[0] << 24); 10 | }; 11 | 12 | var prefix = function(ip) { 13 | var nums = ip.match(/(\d+)/g); 14 | return parseInt(nums[4] || 32,10); 15 | }; 16 | 17 | var ranger = function(range) { 18 | var pre = prefix(range); 19 | var mask = (Math.pow(2,pre) - 1) << (32 - pre); 20 | 21 | if (range.indexOf('-') > -1) { 22 | var ips = range.split('-').map(binary); 23 | } 24 | 25 | range = binary(range); 26 | mask = mask & range; 27 | 28 | return function(ip) { 29 | ip = binary(ip); 30 | 31 | if (!ips) { 32 | return (mask & ip) === mask; 33 | } 34 | 35 | if (ips[0] > ips[1]) { 36 | return ip > ips[1] && ip < ips[0]; 37 | } else { 38 | return ip > ips[0] && ip < ips[1]; 39 | } 40 | }; 41 | }; 42 | 43 | module.exports = ranger; -------------------------------------------------------------------------------- /node_modules/router/README.md: -------------------------------------------------------------------------------- 1 | # Router 2 | A lean and mean web router for [node.js](http://nodejs.org). 3 | It is available through npm: 4 | 5 | npm install router 6 | 7 | The router routes using the method and a pattern 8 | 9 | ``` js 10 | var router = require('router').create(); 11 | 12 | router.get('/', function(request, response) { 13 | response.writeHead(200); 14 | response.end('hello index page'); 15 | }); 16 | 17 | router.listen(8080); // start the server on port 8080 18 | ``` 19 | 20 | If you want to grap a part of the path you can use capture groups in the pattern: 21 | 22 | ``` js 23 | router.get('/{base}', function(request, response) { 24 | var base = request.matches.base; // ex: if the path is /foo/bar, then base = foo 25 | }); 26 | ``` 27 | 28 | The capture patterns matches until the next `/` or character present after the group 29 | 30 | ``` js 31 | router.get('/{x}x{y}', function(request, response) { 32 | // if the path was /200x200, then request.matches = {x:'200', y:'200'} 33 | }); 34 | ``` 35 | 36 | You can also use regular expressions and the related capture groups instead: 37 | 38 | ``` js 39 | router.get(/^\/foo\/(\w+)/, function(request, response) { 40 | var group = request.matches[1]; // if path is /foo/bar, then group is bar 41 | }); 42 | ``` 43 | 44 | Besides `get` the avaiable methods are `post`, `put`, `head`, `del`, `request` and `upgrade`. 45 | `request` matches all the standard http methods and `upgrade` is usually used for websockets. -------------------------------------------------------------------------------- /node_modules/router/index.js: -------------------------------------------------------------------------------- 1 | var common = require('common'); 2 | var http = require('http'); 3 | var https = require('https'); 4 | 5 | var matcher = require('./matcher'); 6 | 7 | var createRouter = function(options) { // TODO: params instead of matches 8 | var that = {}; 9 | 10 | options = options || {}; 11 | 12 | // this check may seem a bit confusing. basicly if options is a server or a router 13 | // then just return the attached router 14 | if (options.router) { 15 | return options.router; 16 | } 17 | // if options if already a server we just sugar it and create a router 18 | // that doesnt autoclose (otherwise we could have really weird rcs) 19 | // TODO: maybe listen for # of request handlers on the server to decide whether to autoclose 20 | if (typeof options.listen === 'function') { 21 | return createRouter({server:options, autoclose:false}); 22 | } 23 | 24 | var methods = {request:[], upgrade:[], get:[], put:[], post:[], head:[], 'delete':[]}; 25 | var server = options.server || (options.key ? https.createServer({key:options.key,cert:options.cert}) : http.createServer()); 26 | 27 | that.autoclose = options.autoclose !== false; 28 | that.server = server; 29 | that.router = server.router = that; 30 | 31 | var find = function(handlers, request, a, b) { 32 | for (var i = 0; i < handlers.length; i++) { 33 | if (handlers[i](request, a, b)) { 34 | return true; 35 | } 36 | } 37 | return false; 38 | }; 39 | 40 | that.route = function(request, response) { 41 | if (find(methods.request, request, response) || 42 | find(methods[request.method.toLowerCase()], request, response) || !that.autoclose) { 43 | return; 44 | } 45 | if (request.method === 'POST' || request.method === 'PUT') { // TODO: check if node doesn't already do this 46 | request.connection.destroy(); // don't waste bandwidth on data we don't want 47 | return; 48 | } 49 | response.writeHead(404); 50 | response.end(); 51 | }; 52 | 53 | server.on('request', function(request, response) { 54 | if (request.method === 'OPTIONS') { 55 | response.writeHead(200, { 56 | 'access-control-allow-origin': '*', 57 | 'access-control-allow-methods': 'PUT, POST, GET, OPTIONS', 58 | 'access-control-allow-headers': 'Content-Type' 59 | }); 60 | response.end(); 61 | return; 62 | } 63 | that.route(request, response); 64 | }); 65 | server.on('upgrade', function(request, connection, head) { 66 | if (find(methods.upgrade, request, connection, head)) { 67 | return; 68 | } 69 | 70 | connection.destroy(); 71 | }); 72 | 73 | var router = function(methods) { 74 | return function(pattern, rewrite, fn) { 75 | if (!fn) { 76 | fn = rewrite; 77 | rewrite = undefined; 78 | } 79 | 80 | var match = matcher(pattern); 81 | 82 | rewrite = rewrite && rewrite.replace(/\$(\d+)/g, '{$1}'); 83 | methods.push(function(request, a, b) { 84 | var matches = match(request.url.split('?')[0]); 85 | 86 | if (matches) { 87 | if (rewrite) { 88 | request.url = common.format(rewrite, matches); 89 | } 90 | 91 | request.matches = matches; 92 | fn(request, a, b); 93 | 94 | return true; 95 | } 96 | return false; 97 | }); 98 | }; 99 | }; 100 | 101 | that.request = router(methods.request); 102 | that.upgrade = router(methods.upgrade); 103 | 104 | that.get = router(methods.get); 105 | that.put = router(methods.put); 106 | that.del = router(methods['delete']); // :( 107 | 108 | that.post = router(methods.post); 109 | that.head = router(methods.head); 110 | 111 | that.close = function() { 112 | server.close.apply(server, arguments); 113 | }; 114 | that.listen = function() { 115 | server.listen.apply(server, arguments); 116 | }; 117 | 118 | return that; 119 | }; 120 | 121 | exports.create = createRouter; 122 | 123 | var fs = require('fs'); 124 | var path = require('path'); 125 | var mimes = require('mimes'); 126 | 127 | exports.onfilerequest = function(dir, options) { 128 | 129 | options = options || {}; 130 | // TODO: add cache option 131 | 132 | return function(request, response) { 133 | var url = request.url.split('?')[0]; 134 | 135 | url = path.normalize(url); 136 | 137 | // security check 138 | if (/\/\.\.\//.test(url)) { 139 | response.writeHead(404); 140 | response.end(); 141 | return; 142 | } 143 | 144 | url = path.join(dir, url); 145 | 146 | fs.readFile(url, function(err, buffer) { 147 | if (err) { 148 | response.writeHead(404); 149 | response.end(); 150 | return; 151 | } 152 | response.writeHead(options.status || 200, { 153 | 'content-type':mimes.resolve(url) 154 | }); 155 | response.end(buffer); 156 | }); 157 | }; 158 | }; -------------------------------------------------------------------------------- /node_modules/router/matcher.js: -------------------------------------------------------------------------------- 1 | var escapeRegex = function(str) { 2 | return str.replace(/([\/\\\*\+\.\?\|\(\)\[\]\{\}])/g, '\\$1'); 3 | }; 4 | 5 | module.exports = function(pattern) { 6 | if (typeof pattern !== 'string') { // regex 7 | return function(url) { 8 | return url.match(pattern); 9 | }; 10 | } 11 | var offset = 0; 12 | var keys = []; 13 | var res = '^'; 14 | 15 | pattern.replace(/\{[^\{\}]+\}/g, function(a,b) { // a hack - we use replace as a tokenizer :) 16 | res += escapeRegex(pattern.substring(offset, b)); 17 | offset = a.length+b; 18 | 19 | res += '([^\\'+(pattern[offset]||'/')+']*)'; 20 | 21 | keys.push(a.substring(1, a.length-1)); 22 | }); 23 | 24 | res += escapeRegex(pattern.substring(offset)); 25 | res += (res[res.length-1] === '/' ? '' : '/?')+'$'; 26 | res = new RegExp(res, 'i'); 27 | 28 | if (!keys.length) { // small optimization 29 | return function(str) { 30 | return res.test(str); 31 | }; 32 | } 33 | return function(str) { 34 | var match = str.match(res); 35 | 36 | if (!match) { 37 | return match; 38 | } 39 | var map = {}; 40 | 41 | match.slice(1).forEach(function(result, i) { 42 | map[keys[i]] = result; 43 | }); 44 | 45 | return map; 46 | }; 47 | }; -------------------------------------------------------------------------------- /node_modules/router/node_modules/common/README.md: -------------------------------------------------------------------------------- 1 | # Common 2 | A utility module for both node.js and the browser. 3 | It is available through npm: 4 | 5 | npm install common 6 | 7 | Or as minified js file for the browser: 8 | 9 | 10 | 11 | This module among other things contains a fork of [step](https://github.com/creationix/step) that also provides error handling 12 | 13 | ``` js 14 | common.step([ 15 | function(next) { // next is the last argument, except in the last handler 16 | fs.readFile(__filename, 'utf-8', next); 17 | }, 18 | function(file) { 19 | console.log(file); 20 | } 21 | ], function(err) { 22 | // any error received in a callback will be forwarded here 23 | }); 24 | ``` 25 | 26 | It also contains a shortcut to the `EventEmitter` prototype and a compatible implementation of this for the browser. 27 | 28 | ``` js 29 | var MyEmitter = common.emitter(function() { 30 | this.foo = 42; 31 | }); 32 | 33 | var me = new MyEmitter(); 34 | 35 | me.emit('foo', me.foo); // emits 'foo',42 36 | ``` 37 | 38 | There is also a more general method for extending prototypes called `extend`: 39 | 40 | ``` js 41 | // this prototype is the same as above 42 | var MyEmitter = common.extend(events.EventEmitter, function() { 43 | this.foo = 42; 44 | }); 45 | ``` 46 | 47 | If you want to use futures you can use the `future` function to create a future: 48 | 49 | ``` js 50 | var fut = common.future(); 51 | 52 | fut.get(function(val) { 53 | console.log(val); 54 | }); 55 | setTimeout(function() { 56 | fut.put(42); // results in the previous .get being called and all future .get's will be called synchroniously 57 | }, 1000) 58 | ``` 59 | 60 | To do string formatting you can use `format`: 61 | 62 | ``` js 63 | // you can parse the arguments to a pattern one by one 64 | common.format('define {0} here', 'pattern'); // returns 'define pattern here' 65 | 66 | // or as a map or array 67 | common.format('define {foo} here', {foo:'pattern'}); // same as above 68 | ``` 69 | There is a `log` method that just accepts the does the same as `format` except it prints out the result using `console.log` if available 70 | 71 | To generate a simple weak symbols (often used when generating keys for a map) use `gensym` 72 | 73 | ``` js 74 | common.gensym() // returns 's0' 75 | common.gensym() // returns 's1' 76 | ``` 77 | 78 | If you instead of a weak symbol need a strong one use `uuid`: 79 | 80 | ``` js 81 | common.uuid(); // returns a strong id, ex: ngDl6IdovME9JKvIxgED0FK1kzURxfZaCq48-0 82 | ``` 83 | 84 | Common can also encode integers into alphanumerical notation using `encode`: 85 | 86 | ``` js 87 | common.encode(1000); // returns G8 88 | ``` 89 | 90 | To ensure that a method cannot be called more than once you can use the `once` function: 91 | 92 | ``` js 93 | var fn = common.once(function() { 94 | console.log('hello'); 95 | }); 96 | 97 | fn(); // prints hello 98 | fn(); // does nothing 99 | ``` 100 | 101 | Besides the above common implements two of the utilities mentioned in The Good Parts, `memoizer` and `curry`. 102 | -------------------------------------------------------------------------------- /node_modules/router/node_modules/common/common.min.js: -------------------------------------------------------------------------------- 1 | (function(g){(function(){if(typeof g==="undefined"){var k=function(){},c={},i={};g=function(e){if(arguments.length>1){for(var h=g(arguments[0]),a=1;a=d))){var o=a[c++],k=o.length===1?[j]:[n,j];d=f=0;h=[];l=!1;o.apply(g,c=d&&j(null,h)}};j.parallel=function(){var a=d++;if(l)throw Error("next.parallel must not be called async");return function(b,d){f++;h[a]=d;j(b,h)}};j()};c.memoizer=function(a){var b= 5 | {},d=function(a){var b=typeof a;if(b!=="object")return b+": "+a;var b=[],c;for(c in a)b.push(d(a[c]));return b.sort().join("\n")};return function(){for(var c="",e=0;e= counter; 118 | }; 119 | var next = function(err, value) { 120 | if (err && !ended) { 121 | ended = true; 122 | (onerror || noop).apply(state, [err]); 123 | return; 124 | } 125 | if (ended || (counter && !check())) { 126 | return; 127 | } 128 | 129 | var fn = funcs[pointer++]; 130 | var args = (fn.length === 1 ? [next] : [value, next]); 131 | 132 | counter = completed = 0; 133 | values = []; 134 | complete = false; 135 | fn.apply(state, pointer < funcs.length ? args : [value, next]); 136 | complete = true; 137 | 138 | if (counter && check()) { 139 | next(null, values); 140 | } 141 | }; 142 | next.parallel = function() { 143 | var index = counter++; 144 | 145 | if (complete) { 146 | throw new Error('next.parallel must not be called async'); 147 | } 148 | return function(err, value) { 149 | completed++; 150 | values[index] = value; 151 | next(err, values); 152 | }; 153 | }; 154 | 155 | next(); 156 | }; 157 | 158 | exports.memoizer = function(fn) { 159 | var cache = {}; 160 | 161 | var stringify = function(obj) { 162 | var type = typeof obj; 163 | 164 | if (type !== 'object') { 165 | return type + ': ' + obj; 166 | } 167 | var keys = []; 168 | 169 | for (var i in obj) { 170 | keys.push(stringify(obj[i])); 171 | } 172 | return keys.sort().join('\n'); 173 | }; 174 | 175 | return function() { 176 | var key = ''; 177 | 178 | for (var i = 0; i < arguments.length; i++) { 179 | key += stringify(arguments[i]) + '\n'; 180 | } 181 | 182 | cache[key] = cache[key] || fn.apply(null, arguments); 183 | 184 | return cache[key]; 185 | }; 186 | }; 187 | 188 | exports.curry = function(fn) { 189 | var args = Array.prototype.slice.call(arguments, 1); 190 | 191 | return function() { 192 | return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))); 193 | }; 194 | }; 195 | 196 | exports.once = function(fn) { 197 | var once = true; 198 | 199 | return function() { 200 | if (once) { 201 | once = false; 202 | (fn || noop).apply(null, arguments); 203 | return true; 204 | } 205 | return false; 206 | }; 207 | }; 208 | 209 | exports.future = function() { 210 | var that = {}; 211 | var stack = []; 212 | 213 | that.get = function(fn) { 214 | stack.push(fn); 215 | }; 216 | that.put = function(a,b) { 217 | that.get = function(fn) { 218 | fn(a,b); 219 | }; 220 | 221 | while (stack.length) { 222 | stack.shift()(a,b); 223 | } 224 | }; 225 | return that; 226 | }; 227 | 228 | // utilities below 229 | 230 | exports.encode = function(num) { 231 | var ALPHA = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 232 | 233 | return function(i) { 234 | return i < ALPHA.length ? ALPHA.charAt(i) : exports.encode(Math.floor(i / ALPHA.length)) + ALPHA.charAt(i % ALPHA.length); 235 | }; 236 | }(); 237 | 238 | exports.uuid = function() { 239 | var inc = 0; 240 | 241 | return function() { 242 | var uuid = ''; 243 | 244 | for (var i = 0; i < 36; i++) { 245 | uuid += exports.encode(Math.floor(Math.random() * 62)); 246 | } 247 | return uuid + '-' + exports.encode(inc++); 248 | }; 249 | }(); 250 | 251 | exports.gensym = function() { 252 | var s = 0; 253 | 254 | return function() { 255 | return 's'+(s++); 256 | }; 257 | }(); 258 | 259 | exports.format = function (str, col) { 260 | col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1); 261 | 262 | return str.replace(/\{([^{}]+)\}/gm, function () { 263 | return col[arguments[1]] === undefined ? arguments[0] : col[arguments[1]]; 264 | }); 265 | }; 266 | 267 | exports.log = function(str) { 268 | str = ''+str; 269 | 270 | var format = exports.format.apply(exports, arguments); 271 | 272 | if (typeof window !== 'undefined' && !window.console) { 273 | return; 274 | } 275 | console.log(format); 276 | }; -------------------------------------------------------------------------------- /node_modules/router/node_modules/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"common", 3 | "version":"0.1.2", 4 | "description":"A utility package with some useful functional stuff", 5 | "author": "Ge.tt ", 6 | "contributors": [ 7 | "Mathias Buus Madsen " 8 | ], 9 | "main":"./index.js" 10 | } 11 | -------------------------------------------------------------------------------- /node_modules/router/node_modules/mimes/index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var files = [__dirname + '/mime.types']; 4 | 5 | exports.avi = 'video/divx'; 6 | 7 | for (var i=0; i", 7 | "Ian Jorgensen =0.1.0"} 11 | } 12 | -------------------------------------------------------------------------------- /node_modules/signer/index.js: -------------------------------------------------------------------------------- 1 | var crypto = require('crypto'); 2 | var common = require('common'); 3 | var fs = require('fs'); 4 | 5 | var esc = function() { 6 | var map = {'=':'-','+':'*','/':'_'}; 7 | 8 | return function(str) { 9 | return str.replace(/[=+\/]/g, function(a) { 10 | return map[a]; 11 | }); 12 | }; 13 | }(); 14 | var unesc = function() { 15 | var map = {'-':'=','*':'+','_':'/'}; 16 | 17 | return function(str) { 18 | return str.replace(/[-*_]/g, function(a) { 19 | return map[a]; 20 | }); 21 | }; 22 | }(); 23 | var hmac = function(str, secret) { 24 | var hash = crypto.createHmac('sha1', secret); 25 | 26 | hash.update(str); 27 | 28 | return hash.digest('base64'); 29 | }; 30 | 31 | var sign = function(secret, str, options) { 32 | options = options || {}; 33 | 34 | var now = options.ttl ? ((Date.now()/1000)|0)+options.ttl : 0; 35 | 36 | return esc(new Buffer(''+now).toString('base64')+'!'+hmac(now+','+str, secret)); 37 | }; 38 | var verify = function(secret, str, sig) { 39 | sig = unesc(sig).split('!'); 40 | 41 | if (sig.length !== 2) { 42 | return false; 43 | } 44 | 45 | var exp = parseInt(new Buffer(sig[0], 'base64').toString('ascii'),10); 46 | 47 | sig = sig[1]; 48 | 49 | if (hmac(exp+','+str, secret) !== sig) { 50 | return false; 51 | } 52 | 53 | return !exp || 1000*exp >= Date.now(); 54 | }; 55 | 56 | var Signer = function(secret) { 57 | this.secret = secret; 58 | }; 59 | 60 | Signer.prototype.sign = function(str, options) { 61 | return sign(this.secret, str, options); 62 | }; 63 | Signer.prototype.verify = function(str, sig) { 64 | return verify(this.secret, str, sig); 65 | }; 66 | 67 | try { 68 | exports.secret = require('fs').readFileSync(__dirname+'/shared.key'); 69 | } catch (err) {} 70 | 71 | exports.generateKey = function(callback) { 72 | var result = new Buffer(20); 73 | 74 | common.step([ 75 | function(next) { 76 | fs.open('/dev/random', 'r', 0666, next); 77 | }, 78 | function(fd, next) { 79 | this.fd = fd; 80 | fs.read(fd, result, 0, 20, null, next); 81 | }, 82 | function(read, next) { 83 | fs.close(this.fd, next); 84 | }, 85 | function() { 86 | callback(null, result); 87 | } 88 | ], callback) 89 | } 90 | exports.sign = function(str, options) { 91 | return sign(exports.secret, str, options); 92 | }; 93 | exports.verify = function(str, sig) { 94 | return verify(exports.secret, str, sig); 95 | }; 96 | exports.create = function(secret) { 97 | return new Signer(secret); 98 | }; 99 | -------------------------------------------------------------------------------- /node_modules/signer/shared.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubsubio/pubsub-hub/c3300f582f6cb72d92b27151d985851f05d60236/node_modules/signer/shared.key -------------------------------------------------------------------------------- /node_modules/websock/README.md: -------------------------------------------------------------------------------- 1 | # WebSock 2 | a websocket server and client module 3 | 4 | this module implements the websocket spec 0-12 (which means it supports ALL websockets as of 01/10/11). it's easy to use: 5 | 6 | ``` js 7 | var websock = require('websock'); 8 | 9 | // instead of 80 we could also parse a server to listen to 10 | websock.listen(80, function(socket) { 11 | socket.on('message', function(message) { 12 | socket.send('echo: ' + message); // let's echo it 13 | }); 14 | socket.send('hello from server'); 15 | }, function() { 16 | var socket = websock.connect('localhost'); 17 | 18 | socket.on('open', function() { 19 | // yay open! 20 | socket.send('hello from client'); 21 | }); 22 | socket.on('message', function(message) { 23 | // yay message! 24 | }); 25 | }); 26 | ``` 27 | 28 | ## License 29 | 30 | (The MIT License) 31 | 32 | Copyright (c) 2011 Mathias Buus Madsen 33 | 34 | 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: 35 | 36 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 37 | 38 | 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. 39 | -------------------------------------------------------------------------------- /node_modules/websock/buffers.js: -------------------------------------------------------------------------------- 1 | var EMPTY = new Buffer(0); 2 | 3 | var BufferList = function() { 4 | this.length = 0; 5 | 6 | this._list = []; 7 | this._offset = 0; 8 | }; 9 | 10 | BufferList.prototype.push = function(buf) { 11 | if (!buf.length) { 12 | return; 13 | } 14 | this._list.push(buf); 15 | 16 | this.length += buf.length; 17 | }; 18 | BufferList.prototype.shift = function() { 19 | var b = this._list[0] && this._list[0][this._offset++]; 20 | 21 | this.length--; 22 | 23 | if (this._offset >= (this._list[0] && this._list[0].length)) { 24 | this._list.shift(); 25 | this._offset = 0; 26 | } 27 | return b; 28 | }; 29 | BufferList.prototype.join = function() { 30 | var list = this._list; 31 | 32 | if (!list.length) { 33 | return EMPTY; 34 | } 35 | var first = this._offset ? list[0].slice(this._offset) : list[0]; 36 | 37 | if (list.length === 1) { 38 | return first; 39 | } 40 | 41 | var all = new Buffer(this.length); 42 | var offset = 0; 43 | 44 | list[0] = first; 45 | 46 | for (var i = 0; i < list.length; i++) { 47 | list[i].copy(all, offset); 48 | offset += list[i].length 49 | } 50 | return all; 51 | }; 52 | BufferList.prototype.empty = function(length) { 53 | var first = this._list[0]; 54 | 55 | if (length && (this._offset + length < first.length)) { 56 | var b = first.slice(this._offset, this._offset+length); 57 | 58 | this._offset += length; 59 | this.length -= length; 60 | return b; 61 | } 62 | var all = this.join(); 63 | 64 | this.length = 0; 65 | 66 | this._list = []; 67 | this._offset = 0; 68 | 69 | if (!length) { 70 | return all; 71 | } 72 | 73 | this.push(all.slice(length)); 74 | return all.slice(0, length); 75 | }; 76 | 77 | exports.create = function() { 78 | return new BufferList(); 79 | }; 80 | -------------------------------------------------------------------------------- /node_modules/websock/examples/browser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | hello websocket world 4 | 25 | 26 | 27 |

gogo websockets!

28 |

29 | 
30 | 
31 | 


--------------------------------------------------------------------------------
/node_modules/websock/examples/server.js:
--------------------------------------------------------------------------------
 1 | var websock = require('../index');
 2 | 
 3 | websock.listen(54321, function(socket) {
 4 | 	console.log('connected socket ('+socket.version+')');
 5 | 	socket.on('message', function(message) {
 6 | 		console.log('rvcd', message);
 7 | 		socket.send('echo: ' + message);
 8 | 	});
 9 | 	socket.on('close', function() {
10 | 		console.log('closed server socket');
11 | 	});
12 | }, function() {
13 | 	var socket = websock.connect('ws://localhost:54321', {protocol:8});
14 | 
15 | 	socket.on('open', function() {
16 | 		socket.send('from node');
17 | 	});
18 | 	socket.on('message', function(message) {
19 | 		console.log('rvcd', message);
20 | 		socket.end();
21 | 	});
22 | 	socket.on('close', function() {
23 | 		console.log('closed client socket');
24 | 	});
25 | });
26 | 


--------------------------------------------------------------------------------
/node_modules/websock/examples/stress.js:
--------------------------------------------------------------------------------
 1 | var websockets = require('../index');
 2 | 
 3 | websockets.listen(10000, function(socket) {
 4 | 	socket.on('message', function(message) {
 5 | 		socket.send(message);
 6 | 	});
 7 | 	socket.on('close', function() {
 8 | 		console.log('server', 'close');
 9 | 	});
10 | }, function() {
11 | 	var ws = websockets.connect('localhost:10000', {protocol:8});
12 | 	var now = Date.now();
13 | 	var max = 10000;
14 | 
15 | 	ws.on('open', function() {
16 | 		console.log('client','open');
17 | 
18 | 		for (var i = 0; i < max; i++) {
19 | 			ws.send('hello world');
20 | 		}
21 | 	});
22 | 
23 | 	var rcvd = 0;
24 | 
25 | 	ws.on('message', function(message) {
26 | 		if (message !== 'hello world') {
27 | 			console.log('meh', message);
28 | 		}
29 | 		if (++rcvd === max) {
30 | 			var delta = Date.now() - now;
31 | 
32 | 			console.log(delta+'ms', Math.round(1000*max/delta)+'msg/s');
33 | //			process.exit(0);
34 | 		}
35 | 	});
36 | 	ws.on('close', function() {
37 | 		console.log('client', 'close');
38 | 	});
39 | });
40 | 


--------------------------------------------------------------------------------
/node_modules/websock/index.js:
--------------------------------------------------------------------------------
  1 | var http = require('http');
  2 | var parseURL = require('url').parse;
  3 | var crypto = require('crypto');
  4 | var common = require('common');
  5 | var protocol8 = require('./protocol-8');
  6 | var protocol0 = require('./protocol-0');
  7 | 
  8 | var noop = function() {};
  9 | 
 10 | var challenge = function(key) {
 11 | 	return crypto.createHash('sha1').update(key+'258EAFA5-E914-47DA-95CA-C5AB0DC85B11').digest('base64');
 12 | };
 13 | var sign = function(k1, k2, head) {
 14 | 	var md5 = crypto.createHash('md5');
 15 | 
 16 | 	[k1, k2].forEach(function(k){
 17 | 		var n = parseInt(k.replace(/[^\d]/g, ''), 10);
 18 | 		var spaces = k.replace(/[^ ]/g, '').length;
 19 | 
 20 | 		if (spaces === 0 || n % spaces !== 0){
 21 | 			return null;
 22 | 		}
 23 | 		n /= spaces;
 24 | 		md5.update(String.fromCharCode(n >> 24 & 0xFF, n >> 16 & 0xFF, n >> 8 & 0xFF, n & 0xFF));
 25 | 	});
 26 | 	return md5.update(head.toString('binary')).digest('binary');
 27 | };
 28 | 
 29 | var client0 = function(options) {
 30 | 	var ws = protocol0.create({type:'client'});
 31 | 	
 32 | 	// TODO: DONT HARDCODE HANDSHAKE!
 33 | 	options.headers['sec-websocket-key1'] = '4 @1  46546xW%0l 1 5';
 34 | 	options.headers['sec-websocket-key2'] = '12998 5 Y3 1  .P00';
 35 | 
 36 | 	var request = http.request(options);
 37 | 
 38 | 	request.on('upgrade', function(request, connection, head) {
 39 | 		// TODO: CHECK HANDSHAKE!
 40 | 		ws.open(connection);
 41 | 	});
 42 | 
 43 | 	request.end('^n:ds[4U', 'ascii');
 44 | 	return ws;
 45 | };
 46 | var handshake0 = function(request, connection, head) {
 47 | 	var sec = ('sec-websocket-key1' in request.headers) ? 'Sec-' : '';
 48 | 	var token = sign(request.headers['sec-websocket-key1'], request.headers['sec-websocket-key2'], head);
 49 | 
 50 | 	if (sec && !token) {
 51 | 		connection.destroy();
 52 | 		return;
 53 | 	}
 54 | 
 55 | 	var handshake = [
 56 | 		'HTTP/1.1 101 WebSocket Protocol Handshake', 
 57 | 		'Upgrade: WebSocket', 
 58 | 		'Connection: Upgrade',
 59 | 		sec+'WebSocket-Origin: ' + (request.headers.origin || 'null'),
 60 | 		sec+'WebSocket-Location: ws://' + request.headers.host + request.url
 61 | 	];
 62 | 
 63 | 	connection.write(handshake.join('\r\n')+'\r\n\r\n'+token, 'binary');
 64 | 	return protocol0.create({type:'server'});
 65 | };
 66 | 
 67 | var client8 = function(options) {
 68 | 	var ws = protocol8.create({mask:true, type:'client'});
 69 | 	var key = new Buffer(16);
 70 | 
 71 | 	for (var i = 0; i < key.length; i++) {
 72 | 		key[i] = (Math.random()*0xff) | 0;		
 73 | 	}
 74 | 
 75 | 	key = key.toString('base64');
 76 | 
 77 | 	options.headers['sec-websocket-version'] = '8';
 78 | 	options.headers['sec-websocket-key'] = key;
 79 | 
 80 | 	var request = http.request(options);
 81 | 	var answer = challenge(key);
 82 | 
 83 | 	request.on('upgrade', function(request, connection, head) {
 84 | 		if (request.headers['sec-websocket-accept'] !== answer) {
 85 | 			connection.destroy();
 86 | 			ws.emit('close');
 87 | 			return;
 88 | 		}
 89 | 		ws.open(connection, head);
 90 | 	});
 91 | 	request.end();
 92 | 
 93 | 	return ws;
 94 | };
 95 | var handshake8 = function(request, connection) {
 96 | 	var headers = [
 97 | 		'HTTP/1.1 101 Swiching Protocols', 
 98 | 		'Upgrade: websocket', 
 99 | 		'Connection: Upgrade',
100 | 		'Sec-WebSocket-Accept: '+challenge(request.headers['sec-websocket-key'])
101 | 	];
102 | 
103 | 	connection.write(headers.join('\r\n')+'\r\n\r\n', 'ascii');
104 | 	return protocol8.create({type:'server'});
105 | };
106 | 
107 | 
108 | exports.connect = function(host, options) {
109 | 	options = options || {};
110 | 
111 | 	if (typeof host === 'string' && host.indexOf('://') === -1) {
112 | 		host = 'ws://'+host;
113 | 	}
114 | 	if (typeof host === 'string') {
115 | 		host = parseURL(host);
116 | 	}
117 | 
118 | 	var port = parseInt(host.port || 80, 10);
119 | 	var hostname = host.hostname;
120 | 	var request = {
121 | 		agent: false,
122 | 		port: port,
123 | 		host: hostname,
124 | 		headers: {
125 | 			Connection:'Upgrade',
126 | 			Upgrade:'websocket',
127 | 			Host:host.hostname
128 | 		}
129 | 	};
130 | 
131 | 	return ((typeof options.protocol === 'number' && options.protocol < 6) ? client0 : client8)(request);
132 | };
133 | exports.onupgrade = function(onsocket) { // exposing this to make for more dynamic use of websock
134 | 	return function(request, connection, head) {
135 | 		connection.setNoDelay(true);
136 | 
137 | 		var ws = (request.headers['sec-websocket-key'] ? handshake8 : handshake0)(request, connection, head);
138 | 
139 | 		if (!ws) {
140 | 			return;
141 | 		}
142 | 
143 | 		ws.once('open', function() {
144 | 			onsocket(ws);
145 | 		});
146 | 
147 | 		ws.open(connection, head);
148 | 	};
149 | };
150 | exports.listen = function(port, onsocket, callback) {
151 | 	var that = common.createEmitter();
152 | 	var server = port;
153 | 	var protocols = {};
154 | 
155 | 	if (typeof port === 'number') {
156 | 		server = http.createServer();
157 | 		server.listen(port, callback || noop);
158 | 	}
159 | 	if (server.server && typeof server.connections !== 'number') { // not a http server but a wrapper
160 | 		server = server.server;
161 | 	}
162 | 
163 | 	server.on('upgrade', exports.onupgrade(function(socket) {
164 | 		that.emit('socket', socket);
165 | 	}));
166 | 
167 | 	if (onsocket) {
168 | 		that.on('socket', onsocket);
169 | 	}
170 | 
171 | 	return that;
172 | };
173 | 


--------------------------------------------------------------------------------
/node_modules/websock/node_modules/common/README.md:
--------------------------------------------------------------------------------
  1 | # Common
  2 | A utility module for both node.js and the browser.  
  3 | It is available through npm:
  4 | 
  5 | 	npm install common
  6 | 
  7 | Or as minified js file for the browser:
  8 | 
  9 | 	
 10 | 
 11 | This module among other things contains a fork of [step](https://github.com/creationix/step) that also provides error handling
 12 | 
 13 | ``` js
 14 | common.step([
 15 | 	function(next) { // next is the last argument, except in the last handler
 16 | 		fs.readFile(__filename, 'utf-8', next);
 17 | 	},
 18 | 	function(file) {
 19 | 		console.log(file);
 20 | 	}
 21 | ], function(err) {
 22 | 	// any error received in a callback will be forwarded here
 23 | });
 24 | ```
 25 | 
 26 | It also contains a shortcut to the `EventEmitter` prototype and a compatible implementation of this for the browser.
 27 | 
 28 | ``` js
 29 | var MyEmitter = common.emitter(function() {
 30 | 	this.foo = 42;
 31 | });
 32 | 
 33 | var me = new MyEmitter();
 34 | 
 35 | me.emit('foo', me.foo); // emits 'foo',42
 36 | ```
 37 | 
 38 | There is also a more general method for extending prototypes called `extend`:
 39 | 
 40 | ``` js
 41 | // this prototype is the same as above
 42 | var MyEmitter = common.extend(events.EventEmitter, function() {
 43 | 	this.foo = 42;
 44 | });
 45 | ```
 46 | 
 47 | If you want to use futures you can use the `future` function to create a future:
 48 | 
 49 | ``` js
 50 | var fut = common.future();
 51 | 
 52 | fut.get(function(val) {
 53 | 	console.log(val);
 54 | });
 55 | setTimeout(function() {
 56 | 	fut.put(42); // results in the previous .get being called and all future .get's will be called synchroniously
 57 | }, 1000)
 58 | ```
 59 | 
 60 | To do string formatting you can use `format`:
 61 | 
 62 | ``` js
 63 | // you can parse the arguments to a pattern one by one
 64 | common.format('define {0} here', 'pattern'); // returns 'define pattern here'
 65 | 
 66 | // or as a map or array
 67 | common.format('define {foo} here', {foo:'pattern'}); // same as above
 68 | ```
 69 | There is a `log` method that just accepts the does the same as `format` except it prints out the result using `console.log` if available
 70 | 
 71 | To generate a simple weak symbols (often used when generating keys for a map) use `gensym`
 72 | 
 73 | ``` js
 74 | common.gensym() // returns 's0'
 75 | common.gensym() // returns 's1'
 76 | ```
 77 | 
 78 | If you instead of a weak symbol need a strong one use `uuid`:
 79 | 
 80 | ``` js
 81 | common.uuid(); // returns a strong id, ex: ngDl6IdovME9JKvIxgED0FK1kzURxfZaCq48-0
 82 | ```
 83 | 
 84 | Common can also encode integers into alphanumerical notation using `encode`:
 85 | 
 86 | ``` js
 87 | common.encode(1000); // returns G8
 88 | ```
 89 | 
 90 | To ensure that a method cannot be called more than once you can use the `once` function:
 91 | 
 92 | ``` js
 93 | var fn = common.once(function() {
 94 | 	console.log('hello');
 95 | });
 96 | 
 97 | fn(); // prints hello
 98 | fn(); // does nothing
 99 | ```
100 | 
101 | Besides the above common implements two of the utilities mentioned in The Good Parts, `memoizer` and `curry`.  
102 | 


--------------------------------------------------------------------------------
/node_modules/websock/node_modules/common/index.js:
--------------------------------------------------------------------------------
  1 | var noop = function() {};
  2 | 
  3 | var Emitter;
  4 | 
  5 | if (!module.browser) {
  6 | 	Emitter = require('events').EventEmitter; // node-only
  7 | } else {
  8 | 	Emitter = function() {
  9 | 		this._events = {};
 10 | 	};
 11 | 
 12 | 	Emitter.prototype.on = Emitter.prototype.addListener = function(name, listener) {
 13 | 		this.emit('newListener', name, listener);
 14 | 		(this._events[name] = this._events[name] || []).push(listener);
 15 | 	};
 16 | 	Emitter.prototype.once = function(name, listener) {
 17 | 		var self = this;
 18 | 
 19 | 		var onevent = function() {
 20 | 			self.removeListener(name, listener);
 21 | 			listener.apply(this, arguments);
 22 | 		};
 23 | 
 24 | 		onevent.listener = listener;	
 25 | 		this.on(name, onevent);
 26 | 	};
 27 | 	Emitter.prototype.emit = function(name) {
 28 | 		var listeners = this._events[name];
 29 | 
 30 | 		if (!listeners) {
 31 | 			return;
 32 | 		}
 33 | 		var args = Array.prototype.slice.call(arguments, 1);
 34 | 
 35 | 		listeners = listeners.slice();
 36 | 
 37 | 		for (var i = 0; i < listeners.length; i++) {
 38 | 			listeners[i].apply(null, args);
 39 | 		}
 40 | 	};
 41 | 	Emitter.prototype.removeListener = function(name, listener) {
 42 | 		var listeners = this._events[name];
 43 | 
 44 | 		if (!listeners) {
 45 | 			return;
 46 | 		}
 47 | 		for (var i = 0; i < listeners.length; i++) {
 48 | 			if (listeners[i] === listener || (listeners[i].listener === listener)) {
 49 | 				listeners.splice(i, 1);
 50 | 				break;
 51 | 			}
 52 | 		}
 53 | 		if (!listeners.length) {
 54 | 			delete this._events[name];
 55 | 		}
 56 | 	};
 57 | 	Emitter.prototype.removeAllListeners = function(name) {
 58 | 		if (!arguments.length) {
 59 | 			this._events = {};
 60 | 			return;
 61 | 		}
 62 | 		delete this._events[name];
 63 | 	};
 64 | 	Emitter.prototype.listeners = function(name) {
 65 | 		return this._events[name] || [];
 66 | 	};	
 67 | }
 68 | 
 69 | Object.create = Object.create || function(proto) {
 70 | 	var C = function() {};
 71 | 	
 72 | 	C.prototype = proto;
 73 | 	
 74 | 	return new C();
 75 | };
 76 | 
 77 | exports.extend = function(proto, fn) {
 78 | 	var C = function() {
 79 | 		proto.call(this);
 80 | 		fn.apply(this, arguments);
 81 | 	};
 82 | 	C.prototype = Object.create(proto.prototype);
 83 | 
 84 | 	return C;		
 85 | };
 86 | 
 87 | exports.createEmitter = function() {
 88 | 	return new Emitter();
 89 | };
 90 | 
 91 | exports.emitter = function(fn) {
 92 | 	return exports.extend(Emitter, fn);
 93 | };
 94 | 
 95 | // functional patterns below
 96 | 
 97 | exports.fork = function(a,b) {
 98 | 	return function(err, value) {
 99 | 		if (err) {
100 | 			a(err);
101 | 			return;
102 | 		}
103 | 		b(value);
104 | 	};
105 | };
106 | 
107 | exports.step = function(funcs, onerror) {
108 | 	var counter = 0;
109 | 	var completed = 0;
110 | 	var pointer = 0;
111 | 	var ended = false;
112 | 	var state = {};
113 | 	var values = null;
114 | 	var complete = false;
115 | 
116 | 	var check = function() {
117 | 		return complete && completed >= counter;
118 | 	};
119 | 	var next = function(err, value) {
120 | 		if (err && !ended) {
121 | 			ended = true;
122 | 			(onerror || noop).apply(state, [err]);
123 | 			return;
124 | 		}
125 | 		if (ended || (counter && !check())) {
126 | 			return;
127 | 		}
128 | 
129 | 		var fn = funcs[pointer++];
130 | 		var args = (fn.length === 1 ? [next] : [value, next]);
131 | 
132 | 		counter = completed = 0;
133 | 		values = [];
134 | 		complete = false;
135 | 		fn.apply(state, pointer < funcs.length ? args : [value, next]);
136 | 		complete = true;
137 | 
138 | 		if (counter && check()) {
139 | 			next(null, values);
140 | 		}
141 | 	};
142 | 	next.parallel = function() {
143 | 		var index = counter++;
144 | 
145 | 		if (complete) {
146 | 			throw new Error('next.parallel must not be called async');
147 | 		}
148 | 		return function(err, value) {
149 | 			completed++;
150 | 			values[index] = value;
151 | 			next(err, values);
152 | 		};
153 | 	};
154 | 
155 | 	next();
156 | };
157 | 
158 | exports.memoizer = function(fn) {
159 | 	var cache = {};
160 | 	
161 | 	var stringify = function(obj) {
162 | 		var type = typeof obj;
163 | 
164 | 		if (type !== 'object') {
165 | 			return type + ': ' + obj;
166 | 		}
167 | 		var keys = [];
168 | 		
169 | 		for (var i in obj) {
170 | 			keys.push(stringify(obj[i]));
171 | 		}
172 | 		return keys.sort().join('\n');
173 | 	};
174 | 	
175 | 	return function() {
176 | 		var key = '';
177 | 		
178 | 		for (var i = 0; i < arguments.length; i++) {
179 | 			key += stringify(arguments[i]) + '\n';
180 | 		}
181 | 		
182 | 		cache[key] = cache[key] || fn.apply(null, arguments);
183 | 
184 | 		return cache[key];
185 | 	};
186 | };
187 | 
188 | exports.curry = function(fn) {
189 | 	var args = Array.prototype.slice.call(arguments, 1);
190 | 
191 | 	return function() {
192 | 		return fn.apply(this, args.concat(Array.prototype.slice.call(arguments)));
193 | 	};
194 | };
195 | 
196 | exports.once = function(fn) {
197 | 	var once = true;
198 | 
199 | 	return function() {
200 | 		if (once) {
201 | 			once = false;
202 | 			(fn || noop).apply(null, arguments);
203 | 			return true;
204 | 		}
205 | 		return false;
206 | 	};
207 | };
208 | 
209 | exports.future = function() {
210 | 	var that = {};
211 | 	var stack = [];
212 | 	
213 | 	that.get = function(fn) {
214 | 		stack.push(fn);
215 | 	};
216 | 	that.put = function(a,b) {
217 | 		that.get = function(fn) {
218 | 			fn(a,b);
219 | 		};
220 | 		
221 | 		while (stack.length) {
222 | 			stack.shift()(a,b);
223 | 		}
224 | 	};
225 | 	return that;
226 | };
227 | 
228 | // utilities below
229 | 
230 | exports.encode = function(num) {
231 | 	var ALPHA = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
232 | 
233 | 	return function(i) {
234 | 		return i < ALPHA.length ? ALPHA.charAt(i) : exports.encode(Math.floor(i / ALPHA.length)) + ALPHA.charAt(i % ALPHA.length);
235 | 	};
236 | }();
237 | 
238 | exports.uuid = function() {
239 | 	var inc = 0;		
240 | 
241 | 	return function() {
242 | 		var uuid = '';
243 | 
244 | 		for (var i = 0; i < 36; i++) {
245 | 			uuid += exports.encode(Math.floor(Math.random() * 62));
246 | 		}
247 | 		return uuid + '-' + exports.encode(inc++);			
248 | 	};
249 | }();
250 | 
251 | exports.gensym = function() {
252 | 	var s = 0;
253 | 	
254 | 	return function() {
255 | 		return 's'+(s++);
256 | 	};
257 | }();
258 | 
259 | exports.join = function() {
260 | 	var result = {};
261 | 	
262 | 	for (var i = 0; i < arguments.length; i++) {
263 | 		var a = arguments[i];
264 | 		
265 | 		for (var j in a) {
266 | 			result[j] = a[j];
267 | 		}
268 | 	}
269 | 	return result;
270 | };
271 | 
272 | exports.format = function (str, col) {
273 | 	col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1);
274 | 
275 | 	return str.replace(/\{([^{}]+)\}/gm, function () {
276 | 		return col[arguments[1]] === undefined ? arguments[0] : col[arguments[1]];
277 | 	});
278 | };
279 | 
280 | exports.log = function(str) {
281 | 	if (typeof window !== 'undefined' && !window.console) {
282 | 		return;
283 | 	}
284 | 	console.log(str);
285 | };
286 | 


--------------------------------------------------------------------------------
/node_modules/websock/node_modules/common/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |  "name":"common",
 3 |  "version":"0.2.1",
 4 |  "description":"A utility package with some useful functional stuff",
 5 |  "author": "Ge.tt ",
 6 |  "contributors": [
 7 |    "Mathias Buus Madsen "
 8 |  ],
 9 |  "main":"./index.js"
10 | }
11 | 


--------------------------------------------------------------------------------
/node_modules/websock/package.json:
--------------------------------------------------------------------------------
1 | {
2 |  "name":"websock",
3 |  "version":"0.3.4",
4 |  "description":"a complete websockets implementation",
5 |  "keywords": ["browser", "js", "websockets", "sockets", "web", "websock"],
6 |  "dependencies": {"common":">=0.2.0"},
7 |  "author": "Mathias Buus Madsen "
8 | }
9 | 


--------------------------------------------------------------------------------
/node_modules/websock/protocol-0.js:
--------------------------------------------------------------------------------
  1 | var common = require('common');
  2 | 
  3 | var noop = function() {};
  4 | 
  5 | var START = '\u0000';
  6 | var END   = '\ufffd';
  7 | 
  8 | var CLOSE = [END, END, START];
  9 | 
 10 | var Parser = common.emitter(function() {
 11 | 	this.buffer = '';
 12 | 	this.start = 0;
 13 | 	this.framing = false;
 14 | 	this.top = [];
 15 | 
 16 | 	this.once = common.once();
 17 | 	this.pointer = 0;
 18 | });
 19 | 
 20 | Parser.prototype.parse = function(data) {
 21 | 	var index = -1;
 22 | 	var last = 0;
 23 | 	
 24 | 	if (this.once() && data === END+START) {
 25 | 		this.emit('close');
 26 | 	}
 27 | 	if (!this.once()) {
 28 | 		for (var i = 0; i < data.length; i++) {
 29 | 			if (CLOSE[this.pointer++] === data[i]) {
 30 | 				if (this.pointer === CLOSE.length) {
 31 | 					this.emit('close');
 32 | 				}
 33 | 			} else {
 34 | 				this.pointer = 0;
 35 | 			}
 36 | 		}
 37 | 	}
 38 | 
 39 | 	while ((index = data.indexOf(this.framing ? END : START, last)) > -1) { // messages are framed by START/END
 40 | 		if (this.framing) {
 41 | 			this.emit('message', this.buffer.substring(this.start)+data.substring(last, index));
 42 | 			this.buffer = '';
 43 | 		}
 44 | 		
 45 | 		this.start = last = index+1;
 46 | 		this.framing = !this.framing;
 47 | 	}
 48 | 	if (this.framing && last <= data.length) { // we only buffer is we absolutely have to
 49 | 		this.buffer += data;
 50 | 	}
 51 | };
 52 | 
 53 | var WebSocket = common.emitter(function(options) {
 54 | 	this.type = options.type;
 55 | 	this.readable = this.writable = false;
 56 | });
 57 | 
 58 | WebSocket.prototype.pingable = false;
 59 | WebSocket.prototype.version = 0;
 60 | 
 61 | WebSocket.prototype.open = function(connection, head) {
 62 | 	var self = this;
 63 | 	var parser = new Parser();
 64 | 	
 65 | 	this.connection = connection;
 66 | 	this.readable = this.writable = true;
 67 | 
 68 | 	connection.setEncoding('utf-8');
 69 | 	connection.setTimeout(2*60*1000);
 70 | 		
 71 | 	var destroy = function() {
 72 | 		connection.destroy();
 73 | 	};
 74 | 	var onclose = common.once(function() {
 75 | 		self.readable = self.writable = false;
 76 | 		self.emit('close');
 77 | 	});	
 78 | 
 79 | 	parser.on('message', function(message) {
 80 | 		if (self.readable) {
 81 | 			self.emit('message', message);		
 82 | 		}
 83 | 	});
 84 | 	parser.on('close', destroy);	
 85 | 
 86 | 	connection.on('end', function() {
 87 | 		connection.end();
 88 | 		onclose();
 89 | 	});
 90 | 
 91 | 	connection.on('timeout', destroy);	
 92 | 	connection.on('error', onclose);
 93 | 	connection.on('close', onclose);
 94 | 	
 95 | 	connection.on('data', function(data) {
 96 | 		parser.parse(data);
 97 | 	});
 98 | 
 99 | 	this.emit('open');
100 | 
101 | 	// maybe do something with head?
102 | };
103 | 
104 | WebSocket.prototype.send = function(data) {
105 | 	var length = Buffer.byteLength(data);
106 | 	var message = new Buffer(2+length);
107 | 	
108 | 	message.write('\u0000', 'binary');
109 | 	message.write(data, 1, 'utf-8');
110 | 	message.write('\uffff', length+1, 'binary');
111 | 
112 | 	this.connection.write(message); // we encourage the socket to send it as one package
113 | }
114 | WebSocket.prototype.ping = noop;
115 | WebSocket.prototype.end = WebSocket.prototype.close = function() {
116 | 	this.connection.end();
117 | };
118 | WebSocket.prototype.destroy = function() {
119 | 	this.connection.destroy();
120 | };
121 | 
122 | exports.create = function(options) {
123 | 	return new WebSocket(options);
124 | };


--------------------------------------------------------------------------------
/node_modules/websock/protocol-8.js:
--------------------------------------------------------------------------------
  1 | var common = require('common');
  2 | var buffers = require('./buffers');
  3 | 
  4 | var noop = function() {};
  5 | 
  6 | var encode = function(opcode, mask, message) {
  7 | 	var length = message.length + 2 + (mask ? 4 : 0);
  8 | 	var first = message.length;
  9 | 	var bytes = 0;
 10 | 
 11 | 	if (message.length > 125 && message.length <= 0xffff) {
 12 | 		first = 126;
 13 | 		bytes = 2;
 14 | 	}
 15 | 	if (message.length > 0xffff) {
 16 | 		first = 127;
 17 | 		bytes = 8;
 18 | 	}
 19 | 
 20 | 	var buf = new Buffer(length+bytes);
 21 | 	var offset = 2;
 22 | 
 23 | 	buf[0] = opcode === 1 ? 129 : (0x80 | opcode); // 99% we use opcode 1, so just a stupid opt.
 24 | 	buf[1] = (mask ? 0x80 : 0x0) | first;
 25 | 
 26 | 	for (var i = bytes-1; i >= 0; i--) {
 27 | 		buf[offset++] = (message.length >> 8*i) & 0xff;
 28 | 	}
 29 | 	if (mask) {
 30 | 		mask = [];
 31 | 
 32 | 		for (var i = 0; i < 4; i++) {
 33 | 			mask[i] = buf[offset++] = (Math.random() * 256) | 0;
 34 | 		}
 35 | 		for (var i = 0; i < message.length; i++) {
 36 | 			buf[offset++] = message[i] ^ mask[i % 4];
 37 | 		}
 38 | 	} else {
 39 | 		message.copy(buf, offset);	
 40 | 	}
 41 | 	return buf;
 42 | };
 43 | 
 44 | var PING = encode(9, false, new Buffer([42]));
 45 | var CLOSE = new Buffer([136,0]);
 46 | 
 47 | var WebSocket = common.emitter(function(options) {
 48 | 	this.masking = options.mask;
 49 | 	this.type = options.type;
 50 | 	this.writable = this.readable = false;
 51 | });
 52 | 
 53 | WebSocket.prototype.pingable = true;
 54 | WebSocket.prototype.version = 8;
 55 | 
 56 | WebSocket.prototype.open = function(connection, head) {
 57 | 	var self = this;
 58 | 	var list = buffers.create();
 59 | 
 60 | 	this.connection = connection;
 61 | 	this.readable = this.writable = true;
 62 | 
 63 | 	var opcode;
 64 | 	var mask;
 65 | 	var length = 0;
 66 | 
 67 | 	var parseHead = function() {
 68 | 		if (list.length < 2) {
 69 | 			return true;
 70 | 		}
 71 | 		var a = list.shift();
 72 | 		var b = list.shift();
 73 | 
 74 | 		opcode = 0xf & a;
 75 | 		mask = 0x80 & b;
 76 | 		length = 0x7f & b;
 77 | 
 78 | 		if (length === 126) {
 79 | 			parse = parse16Length;
 80 | 			return;
 81 | 		}
 82 | 		if (length === 127) {
 83 | 			parse = parse64Length;
 84 | 			return;
 85 | 		}
 86 | 		parse = mask ? parseMask : parseBody;
 87 | 	};
 88 | 	var parse16Length = function() {
 89 | 		if (list.length < 2) {
 90 | 			return true;
 91 | 		}
 92 | 		length = (list.shift() << 8) | list.shift();
 93 | 		parse = mask ? parseMask : parseBody;
 94 | 	};
 95 | 	var parse64Length = function() {
 96 | 		if (list.length < 8) {
 97 | 			return true;
 98 | 		}
 99 | 		length = 0;
100 | 
101 | 		for (var i = 0; i < 8; i++) {
102 | 			length = (length << 8) | list.shift();
103 | 		}
104 | 		parse = mask ? parseMask : parseBody;
105 | 	};
106 | 	var parseMask = function() {
107 | 		if (list.length < 4) {
108 | 			return true;
109 | 		}
110 | 		mask = list.empty(4);
111 | 		parse = parseBody;	
112 | 	};
113 | 	var parseBody = function() {
114 | 		if (list.length < length) {
115 | 			return true;
116 | 		}
117 | 		var message = list.empty(length);
118 | 
119 | 		if (mask) {
120 | 			for (var i = 0; i < message.length; i++) {
121 | 				message[i] ^= mask[i % 4];
122 | 			}
123 | 		}
124 | 		if (opcode === 8 && !self.writable) {
125 | 			return true;
126 | 		}
127 | 		if (opcode === 8) {
128 | 			connection.write(CLOSE);
129 | 			connection.end();
130 | 			return true;
131 | 		}
132 | 		if (opcode === 9) {
133 | 			connection.write(encode(10, false, message));
134 | 			return true;
135 | 		}
136 | 		if (opcode === 10) {
137 | 			return true;
138 | 		}
139 | 		if (self.readable) {
140 | 			self.emit('message', message.toString('utf-8'));		
141 | 		}
142 | 		parse = parseHead;
143 | 	};
144 | 	var parse = parseHead;
145 | 
146 | 	var ondata = function(data) {
147 | 		list.push(data);
148 | 
149 | 		while (!parse(data));
150 | 	};
151 | 
152 | 	connection.on('end', function() {
153 | 		connection.end(); // not sure about this when the server starts the closing handshake
154 | 		self._onclose();
155 | 	});
156 | 	connection.on('close', function() {
157 | 		self._onclose();
158 | 	});
159 | 	connection.on('data', ondata);
160 | 
161 | 	this.emit('open');
162 | 
163 | 	if (this.writable && head && head.length) {
164 | 		ondata(head);
165 | 	}
166 | };
167 | WebSocket.prototype.send = function(message) {
168 | 	this.connection.write(encode(1, this.masking, new Buffer(message, 'utf-8')));
169 | };
170 | WebSocket.prototype.ping = function() {
171 | 	this.connection.write(PING);
172 | };
173 | WebSocket.prototype.close = WebSocket.prototype.end = function() {
174 | 	this.connection.write(CLOSE);
175 | 	this._onclose();
176 | };
177 | WebSocket.prototype.destroy = function() {
178 | 	this.connection.destroy();
179 | 	this._onclose();
180 | };
181 | 
182 | WebSocket.prototype._onclose = function() {
183 | 	if (!this.readable) {
184 | 		return;
185 | 	}
186 | 	this.readable = this.writable = false;
187 | 	this.emit('close');
188 | };
189 | 
190 | exports.create = function(options) {
191 | 	return new WebSocket(options);
192 | };


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 |  "name":"pubsub.io",
3 |  "contributors": [
4 |   "Mathias Buus Madsen ",
5 |   "Ian Jorgensen "
6 |  ],
7 |  "main":"./lib/pubsub.io.js"
8 | }
9 | 


--------------------------------------------------------------------------------
/spike/auth.js:
--------------------------------------------------------------------------------
 1 | /**
 2 | *    Copyright (C) 2011 Ian Jørgensen , Mathias Buus Madsen .
 3 | *
 4 | *    This program is free software: you can redistribute it and/or  modify
 5 | *    it under the terms of the GNU Affero General Public License, version 3,
 6 | *    as published by the Free Software Foundation.
 7 | *
 8 | *    This program is distributed in the hope that it will be useful,
 9 | *    but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 | *    GNU Affero General Public License for more details.
12 | *
13 | *    You should have received a copy of the GNU Affero General Public License
14 | *    along with this program.  If not, see .
15 | */
16 | 
17 | var signer = require('signer');
18 | var compile = require('querify').compile;
19 | 
20 | var authenticator = function(doc) {
21 | 	var auths = {};
22 | 	var signed = {};
23 | 	
24 | 	for (var i in doc) {
25 | 		var val = doc[i];
26 | 		var auth = val.$authenticated;
27 | 		
28 | 		if (auth) {
29 | 			auths[i] = (typeof auth === 'string' ? auth : i).replace(/\//g,'-');
30 | 		}
31 | 		if (val.$signed) {
32 | 			signed[i] = val;
33 | 		}
34 | 		if (val.$signed || (auth && 'value' in val)) {
35 | 			doc[i] = val.value;
36 | 		}
37 | 	}
38 | 	return function(trusted) {
39 | 		if (!trusted) {
40 | 			return signed;
41 | 		}
42 | 		for (var i in auths) {
43 | 			var val = trusted[i];
44 | 			
45 | 			if (!(val && signer.verify(auths[i]+'/'+val.value, val.$signed))) { // should cache the result of verify
46 | 				return false;
47 | 			}
48 | 		}
49 | 		return true;
50 | 	};
51 | };
52 | /*
53 | var ex0 = {user: {$authenticated:1, $any:'ian'},name: {$signed:signer.sign('name/mathias'),value:'mathias'}};
54 | var doc = {user:{$signed:signer.sign('user/ian'),value:'ian'},name:{$authenticated:1,value:'mathias'}};
55 | 
56 | var authD = authenticator(doc);
57 | var authQ = authenticator(ex0);
58 | 
59 | console.log(authD(authQ()) && authQ(authD()));
60 | */


--------------------------------------------------------------------------------
/spike/compiledate.js:
--------------------------------------------------------------------------------
 1 | /**
 2 | *    Copyright (C) 2011 Ian Jørgensen , Mathias Buus Madsen .
 3 | *
 4 | *    This program is free software: you can redistribute it and/or  modify
 5 | *    it under the terms of the GNU Affero General Public License, version 3,
 6 | *    as published by the Free Software Foundation.
 7 | *
 8 | *    This program is distributed in the hope that it will be useful,
 9 | *    but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 | *    GNU Affero General Public License for more details.
12 | *
13 | *    You should have received a copy of the GNU Affero General Public License
14 | *    along with this program.  If not, see .
15 | */
16 | 
17 | var match = function(pattern) { 
18 | 	var template = /^(?:(mon|tue|wed|thu|fri|sat|sun)\w*)?,?\s*(\d{2})?\s*([a-z]+)?\s*(\d{4})?\s*([\d|-]{1,2}:[\d|-]{1,2}:[\d|-]{1,2})?\s*([+-]\d*\.?\d+)?/i;
19 | 	var matches = pattern.match(template);
20 | 
21 | 	if (!matches) {
22 | 		return function() {
23 | 			return false;
24 | 		};
25 | 	}
26 | 	
27 | 	matches = matches.slice(1);
28 | 	
29 | 	var offset = Math.round(Number(matches[5] || 0) * 60);
30 | 	var regex = '^';
31 | 
32 | 	regex += matches[0] ? matches[0].substring(0, 3)+', ' : '\\w{3}, ';
33 | 	regex += matches[1] ? matches[1] + ' ' : '\\d{2} ';
34 | 	regex += matches[2] ? matches[2].substring(0, 3)+' ' : '\\w{3} ';
35 | 	regex += matches[3] ? matches[3] + ' ' : '\\d{4} ';
36 | 	regex += matches[4] ? matches[4].replace(/(^|:)(\d(?::|$))/g,'$10$2').replace(/(^|:)(\d(?::|$))/g,'$10$2').replace(/--/g,'\\d{2}') : '\\d{2}:\\d{2}:\\d{2}'; 
37 | 	
38 | 	regex = new RegExp(regex,'i');
39 | 
40 | 	return function(date) {
41 | 
42 | 		if (offset) {
43 | 			date = new Date(date.getTime() + 60000 * offset);
44 | 		}
45 | 
46 | 		return regex.test(date.toUTCString());
47 | 	};
48 | };
49 | 
50 | var tests = [
51 | 	'monday',
52 | 	'monday 22',
53 | 	'monday 22 august',
54 | 	'monday 22 august 2011',
55 | 	'22 august 2011 8:--:--',
56 | 	'monday 22 august 2011 8:30:--',
57 | 	'monday 22 august 2011 8:30:00',
58 | 	'monday 22 august 2011 10:30:00 +2',
59 | 	'monday 22 august 2011 7:30:00 -1',
60 | 	'monday 22 august 2011 9:00:00 +.5',
61 | 	'monday 22 august 2011 10:00:00 +1.5',
62 | 	'tue',
63 | 	'tue 23',
64 | 	'tue 23 august',
65 | 	'tue 23 august 2011',
66 | 	'23 august 2011 8:--:--',
67 | 	'tue 22 august 2012 8:30:--',
68 | 	'tue 22 september 2011 8:30:00',
69 | 	'tue 22 august 2011 9:30:00 +2',
70 | 	'tue 22 august 2011 8:40:00 -1',
71 | 	'tue 22 august 2011 9:00:10 +.5',
72 | 	'tue 22 august 2011 10:00:01 +1.5'
73 | ];
74 | 
75 | exports.match = match;
76 | exports.tests = tests;
77 | 
78 | /*var subject = new Date('august 22 2011 10:30:00');
79 | for(var i in tests) {
80 | 	console.log(match(tests[i])(subject));
81 | }*/
82 | 


--------------------------------------------------------------------------------
/spike/compiledatefast.js:
--------------------------------------------------------------------------------
 1 | /**
 2 | *    Copyright (C) 2011 Ian Jørgensen , Mathias Buus Madsen .
 3 | *
 4 | *    This program is free software: you can redistribute it and/or  modify
 5 | *    it under the terms of the GNU Affero General Public License, version 3,
 6 | *    as published by the Free Software Foundation.
 7 | *
 8 | *    This program is distributed in the hope that it will be useful,
 9 | *    but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 | *    GNU Affero General Public License for more details.
12 | *
13 | *    You should have received a copy of the GNU Affero General Public License
14 | *    along with this program.  If not, see .
15 | */
16 | 
17 | var match = function(pattern) { 
18 | 	var template = /^(?:(mon|tue|wed|thu|fri|sat|sun)\w*)?,?\s*(\d{2})?\s*([a-z]+)?\s*(\d{4})?\s*([\d|-]{1,2}:[\d|-]{1,2}:[\d|-]{1,2})?\s*([+-]\d*\.?\d+)?/i;
19 | 	var matches = pattern.match(template);
20 | 
21 | 	if (!matches) {
22 | 		return function() {
23 | 			return false;
24 | 		};
25 | 	}
26 | 	
27 | 	matches = matches.slice(1);
28 | 	
29 | 	var offset = Math.round(Number(matches[5] || 0) * 60);
30 | 	var map = {};
31 | 
32 | 	matches[0] && (map.getUTCDay = ['sun','mon','tue','wed','thu','fri','sat'].indexOf(matches[0].substring(0, 3).toLowerCase()));
33 | 	matches[1] && (map.getUTCDate = parseInt(matches[1], 10));
34 | 	matches[2] && (map.getUTCMonth = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'].indexOf(matches[2].substring(0,3).toLowerCase()));
35 | 	matches[3] && (map.getUTCFullYear = parseInt(matches[3], 10));
36 | 
37 | 	var time = matches[4] && matches[4].split(':');
38 | 	
39 | 	if (time) {
40 | 		time[0] !== '--' && (map.getUTCHours = parseInt(time[0], 10));
41 | 		time[1] !== '--' && (map.getUTCMinutes = parseInt(time[1], 10));
42 | 		time[2] !== '--' && (map.getUTCSeconds = parseInt(time[2], 10));
43 | 	}
44 | 	
45 | 	return function(date) {
46 | 		if (offset) {
47 | 			date = new Date(date.getTime() + 60000 * offset);
48 | 		}
49 | 		for (var method in map) {
50 | 			if (date[method]() !== map[method]) {
51 | 				return false;
52 | 			}
53 | 		}
54 | 		return true;
55 | 	};
56 | };
57 | 
58 | //match('monday');
59 | 
60 | var tests = [
61 | 	'monday',
62 | 	'monday 22',
63 | 	'monday 22 august',
64 | 	'monday 22 august 2011',
65 | 	'22 august 2011 8:--:--',
66 | 	'monday 22 august 2011 8:30:--',
67 | 	'monday 22 august 2011 8:30:00',
68 | 	'monday 22 august 2011 10:30:00 +2',
69 | 	'monday 22 august 2011 7:30:00 -1',
70 | 	'monday 22 august 2011 9:00:00 +.5',
71 | 	'monday 22 august 2011 10:00:00 +1.5',
72 | 	'tue',
73 | 	'tue 23',
74 | 	'tue 23 august',
75 | 	'tue 23 august 2011',
76 | 	'23 august 2011 8:--:--',
77 | 	'tue 22 august 2012 8:30:--',
78 | 	'tue 22 september 2011 8:30:00',
79 | 	'tue 22 august 2011 9:30:00 +2',
80 | 	'tue 22 august 2011 8:40:00 -1',
81 | 	'tue 22 august 2011 9:00:10 +.5',
82 | 	'tue 22 august 2011 10:00:01 +1.5'
83 | ];
84 | 
85 | exports.match = match;
86 | exports.tests = tests;
87 | 
88 | //var subject = new Date('august 22 2011 10:30:00');
89 | //for(var i in tests) {
90 | //	console.log(match(tests[i])(subject));
91 | //}
92 | 


--------------------------------------------------------------------------------
/spike/datepattern.js:
--------------------------------------------------------------------------------
  1 | /**
  2 | *    Copyright (C) 2011 Ian Jørgensen , Mathias Buus Madsen .
  3 | *
  4 | *    This program is free software: you can redistribute it and/or  modify
  5 | *    it under the terms of the GNU Affero General Public License, version 3,
  6 | *    as published by the Free Software Foundation.
  7 | *
  8 | *    This program is distributed in the hope that it will be useful,
  9 | *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 | *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11 | *    GNU Affero General Public License for more details.
 12 | *
 13 | *    You should have received a copy of the GNU Affero General Public License
 14 | *    along with this program.  If not, see .
 15 | */
 16 | 
 17 | /*{date : {$time : 'Wednesday"}}
 18 | 
 19 | Second : Minute : Hour Day Month  Year
 20 | 
 21 | day date  Day Month Year Hour:Minute:Second +offset-
 22 | */
 23 | var DAYS = {sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6};
 24 | var MONTHS = {jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11};
 25 | var DATETIME_PATTERN = /^(?:(mon|tue|wed|thu|fri|sat|sun)\w*)?\s*(\d{1,2})?\s*(?:(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\w*)?\s*(\d{4})?\s*(?:(\d{1,2})h)?\s*(?:(\d{1,2})m)?\s*(?:(\d{1,2})s)?\s*([+-]\d*\.?\d+)?\s*$/i;
 26 | 
 27 | var match = function(str) {
 28 | 	
 29 | 	var match = str.match(DATETIME_PATTERN);
 30 | 
 31 | 	if (!match) {
 32 | 		return null;
 33 | 	}
 34 | 	
 35 | 	var time = {
 36 | 		day:DAYS[match[1] && match[1].toLowerCase()],
 37 | 		date:match[2] && parseInt(match[2],10),
 38 | 		month:MONTHS[match[3] && match[3].toLowerCase()],
 39 | 		year:match[4] && parseInt(match[4],10) - 1900,	
 40 | 		hour:match[5] && parseInt(match[5],10),
 41 | 		minute:match[6] && parseInt(match[6],10),
 42 | 		second:match[7] && parseInt(match[7],10),
 43 | 		timeoffset:match[8] && Math.round(Number(match[8]) * 60)
 44 | 	};
 45 | 	
 46 | 	return function(date) {
 47 | 		if (typeof date === 'string') {
 48 | 			date = new Date(date);
 49 | 		}
 50 | 		if (time.timeoffset && date.getTimezoneOffset() !== time.timeoffset) {
 51 | 			date = new Date(date.getTime() + 60000 * (date.getTimezoneOffset() + time.timeoffset));
 52 | 		}
 53 | 		
 54 | 		if (time.day !== undefined && date.getDay() !== time.day) {
 55 | 			return false;
 56 | 		}
 57 | 		if (time.date && date.getDate() !== time.date) {
 58 | 			return false;
 59 | 		}
 60 | 		if (time.month && date.getMonth() !== time.month) {
 61 | 			return false;
 62 | 		}
 63 | 		if (time.year && date.getYear() !== time.year) {
 64 | 			return false;
 65 | 		}
 66 | 		if (time.hour !== undefined && date.getHours() !== time.hour) {
 67 | 			return false;
 68 | 		}
 69 | 		if (time.minute !== undefined && date.getMinutes() !== time.minute) {
 70 | 			return false;
 71 | 		}
 72 | 		if (time.second !== undefined && date.getSeconds() !== time.second) {
 73 | 			return false;
 74 | 		}
 75 | 		return true;
 76 | 	};
 77 | };
 78 | 
 79 | var tests = [
 80 | 	'monday',
 81 | 	'monday 22',
 82 | 	'monday 22 august',
 83 | 	'monday 22 august 2011',
 84 | 	'22 august 2011 10h',
 85 | 	'monday 22 august 2011 10h 30m',
 86 | 	'monday 22 august 2011 10h 30m 0s',
 87 | 	'monday 22 august 2011 10h 30m 0s +2',
 88 | 	'monday 22 august 2011 7h 30m 0s -1',
 89 | 	'monday 22 august 2011 9h 00m 0s +.5',
 90 | 	'monday 22 august 2011 10h 00m 0s +1.5',
 91 | 	'tue',
 92 | 	'tue 23',
 93 | 	'tue 23 august',
 94 | 	'tue 23 august 2011',
 95 | 	'23 august 2011 8h',
 96 | 	'tue 22 august 2012 8h 30m',
 97 | 	'tue 22 september 2011 8h 30m 00s',
 98 | 	'tue 22 august 2011 9h 30m 00s +2',
 99 | 	'tue 22 august 2011 8h 40m 00s -1',
100 | 	'tue 22 august 2011 9h 00m10s +.5',
101 | 	'tue 22 august 2011 10h 00m 01s +1.5'
102 | ];
103 | 
104 | exports.match = match;
105 | exports.tests = tests;
106 | 
107 | /*var subject = new Date('august 22 2011 10:30:00');
108 | for(var i in tests) {
109 | 	console.log(match(tests[i])(subject));
110 | }*/


--------------------------------------------------------------------------------
/spike/datetime-benchmark.js:
--------------------------------------------------------------------------------
 1 | /**
 2 | *    Copyright (C) 2011 Ian Jørgensen , Mathias Buus Madsen .
 3 | *
 4 | *    This program is free software: you can redistribute it and/or  modify
 5 | *    it under the terms of the GNU Affero General Public License, version 3,
 6 | *    as published by the Free Software Foundation.
 7 | *
 8 | *    This program is distributed in the hope that it will be useful,
 9 | *    but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 | *    GNU Affero General Public License for more details.
12 | *
13 | *    You should have received a copy of the GNU Affero General Public License
14 | *    along with this program.  If not, see .
15 | */
16 | 
17 | var verbose = require('./datepattern');
18 | var regex = require('./compiledate');
19 | var fastcompile = require('./compiledatefast');
20 | 
21 | var subject = new Date('august 22 2011 10:30:00');
22 | 
23 | var amount = 10000;
24 | var count = 0;
25 | 
26 | var funcs = [];
27 | for(var j in verbose.tests) {
28 | 	funcs.push(verbose.match(verbose.tests[j]));		
29 | }
30 | 
31 | var then = Date.now();
32 | for(var i=0 ; i < amount; i++) {
33 | 	for(var j in funcs) {
34 | 		count++;
35 | 		funcs[j](subject);
36 | 	}
37 | }
38 | var time = Date.now() - then;
39 | var vb = Math.round(count/time);
40 | console.log(vb + ' matches/ms Verbose ' + time + ' ms');
41 | 
42 | /*******************************************************/
43 | 
44 | var count = 0;
45 | var funcs = [];
46 | 
47 | for(var j in regex.tests) {
48 | 	funcs.push(regex.match(regex.tests[j]));		
49 | }
50 | 
51 | var then = Date.now();
52 | for(var i=0 ; i < amount; i++) {
53 | 	for(var j in funcs) {
54 | 		count++;
55 | 		funcs[j](subject);
56 | 	}
57 | }
58 | var time = Date.now() - then;
59 | var rb = Math.round(count/time);
60 | console.log(rb + ' matches/ms Compile ' + time + ' ms');
61 | 
62 | /*******************************************************/
63 | 
64 | var count = 0;
65 | var funcs = [];
66 | 
67 | for(var j in fastcompile.tests) {
68 | 	funcs.push(fastcompile.match(fastcompile.tests[j]));		
69 | }
70 | 
71 | var then = Date.now();
72 | for(var i=0 ; i < amount; i++) {
73 | 	for(var j in funcs) {
74 | 		count++;
75 | 		funcs[j](subject);
76 | 	}
77 | }
78 | var time = Date.now() - then;
79 | var rb = Math.round(count/time);
80 | console.log(rb + ' matches/ms Compile-Fast ' + time + ' ms');
81 | 
82 | console.log(Math.round((vb*100)/rb) + '% Verbose vs Compile-Fast');


--------------------------------------------------------------------------------