mirror of
https://github.com/Hopiu/postal.js.git
synced 2026-03-16 22:20:23 +00:00
Adding working rough draft of node sample application
This commit is contained in:
parent
57410d175a
commit
30a3995f27
815 changed files with 242567 additions and 693 deletions
|
|
@ -1,8 +1,9 @@
|
|||
build-browser-diags.json
|
||||
build-browser.json
|
||||
build-node-diags.json
|
||||
build-node.json
|
||||
build-all.sh
|
||||
nodetesthost.js
|
||||
example/
|
||||
node_modules/
|
||||
spec/
|
||||
src/
|
||||
ext/
|
||||
|
|
|
|||
10
build-all.sh
10
build-all.sh
|
|
@ -5,10 +5,8 @@ anvil -b build-browser-diags.json
|
|||
|
||||
mv ./lib/standard/postal.amd.js ./lib/amd/postal.js
|
||||
mv ./lib/standard/postal.amd.min.js ./lib/amd/postal.min.js
|
||||
mv ./lib/standard/postal.amd.min.gz.js ./lib/amd/postal.min.gz.js
|
||||
mv ./lib/standard/postal.diagnostics.amd.js ./lib/amd/postal.diagnostics.js
|
||||
mv ./lib/standard/postal.diagnostics.amd.min.js ./lib/amd/postal.diagnostics.min.js
|
||||
mv ./lib/standard/postal.diagnostics.amd.min.gz.js ./lib/amd/postal.diagnostics.min.gz.js
|
||||
|
||||
mv ./lib/standard/postal.diagnostics.node.js ./lib/node/postal.diagnostics.js
|
||||
mv ./lib/standard/postal.node.js ./lib/node/postal.js
|
||||
|
|
@ -17,10 +15,12 @@ rm ./lib/standard/postal.node*
|
|||
|
||||
mv ./lib/standard/postal.standard.js ./lib/standard/postal.js
|
||||
mv ./lib/standard/postal.standard.min.js ./lib/standard/postal.min.js
|
||||
mv ./lib/standard/postal.standard.min.gz.js ./lib/standard/postal.min.gz.js
|
||||
mv ./lib/standard/postal.diagnostics.standard.js ./lib/standard/postal.diagnostics.js
|
||||
mv ./lib/standard/postal.diagnostics.standard.min.js ./lib/standard/postal.diagnostics.min.js
|
||||
mv ./lib/standard/postal.diagnostics.standard.min.gz.js ./lib/standard/postal.diagnostics.min.gz.js
|
||||
|
||||
cp ./lib/standard/postal.* ./example/standard/js
|
||||
cp ./lib/amd/postal.* ./example/amd/js/libs/postal
|
||||
cp ./lib/amd/postal.* ./example/amd/js/libs/postal
|
||||
cp ./lib/amd/postal.js ./example/node/client/js/lib
|
||||
cp ./lib/amd/postal.diagnostics.js ./example/node/client/js/lib
|
||||
cp ./lib/node/postal.diagnostics.js ./example/node/messaging
|
||||
cp ./lib/node/postal.js ./example/node/messaging
|
||||
|
|
@ -3,6 +3,5 @@
|
|||
"output": "lib/standard",
|
||||
"lint": {},
|
||||
"uglify": {},
|
||||
"gzip": {},
|
||||
"extensions": { "uglify": "min", "gzip": "gz" }
|
||||
"extensions": { "uglify": "min" }
|
||||
}
|
||||
|
|
@ -3,6 +3,9 @@
|
|||
"output": "lib/standard",
|
||||
"lint": {},
|
||||
"uglify": {},
|
||||
"gzip": {},
|
||||
"extensions": { "uglify": "min", "gzip": "gz" }
|
||||
"extensions": { "uglify": "min" },
|
||||
"hosts": {
|
||||
"/" : "./"
|
||||
},
|
||||
"port" : 8080
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"source": "src/diags",
|
||||
"output": "lib/node",
|
||||
"lint": {}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"source": "src/main",
|
||||
"output": "lib/node",
|
||||
"lint": {}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -51,7 +51,7 @@ ChannelDefinition.prototype = {
|
|||
var envelope = {
|
||||
channel: this.channel,
|
||||
topic: this._topic,
|
||||
data: obj
|
||||
data: obj || {}
|
||||
};
|
||||
// If this is an envelope....
|
||||
if( obj.topic && obj.data ) {
|
||||
|
|
@ -60,6 +60,7 @@ ChannelDefinition.prototype = {
|
|||
}
|
||||
envelope.timeStamp = new Date();
|
||||
postal.configuration.bus.publish(envelope);
|
||||
return envelope;
|
||||
},
|
||||
|
||||
topic: function(topic) {
|
||||
|
|
@ -241,7 +242,7 @@ var localBus = {
|
|||
_.each(this.subscriptions[envelope.channel], function(topic) {
|
||||
_.each(topic, function(subDef){
|
||||
if(postal.configuration.resolver.compare(subDef.topic, envelope.topic)) {
|
||||
if(_.all(subDef.constraints, function(constraint) { return constraint(envelope.data); })) {
|
||||
if(_.all(subDef.constraints, function(constraint) { return constraint(envelope.data,envelope); })) {
|
||||
if(typeof subDef.callback === 'function') {
|
||||
subDef.callback.apply(subDef.context, [envelope.data, envelope]);
|
||||
subDef.onHandled();
|
||||
|
|
@ -303,21 +304,53 @@ var localBus = {
|
|||
};
|
||||
|
||||
var publishPicker = {
|
||||
"1" : function(envelope) {
|
||||
if(!envelope) {
|
||||
throw new Error("publishing from the 'global' postal.publish call requires a valid envelope.");
|
||||
"1" : function(envelope) {
|
||||
if(!envelope) {
|
||||
throw new Error("publishing from the 'global' postal.publish call requires a valid envelope.");
|
||||
}
|
||||
envelope.channel = envelope.channel || DEFAULT_CHANNEL;
|
||||
envelope.timeStamp = new Date();
|
||||
postal.configuration.bus.publish(envelope);
|
||||
return envelope;
|
||||
},
|
||||
"2" : function(topic, data) {
|
||||
var envelope = { channel: DEFAULT_CHANNEL, topic: topic, timeStamp: new Date(), data: data };
|
||||
postal.configuration.bus.publish( envelope );
|
||||
return envelope;
|
||||
},
|
||||
"3" : function(channel, topic, data) {
|
||||
var envelope = { channel: channel, topic: topic, timeStamp: new Date(), data: data };
|
||||
postal.configuration.bus.publish( envelope );
|
||||
return envelope;
|
||||
}
|
||||
envelope.channel = envelope.channel || DEFAULT_CHANNEL;
|
||||
envelope.timeStamp = new Date();
|
||||
postal.configuration.bus.publish(envelope);
|
||||
},
|
||||
"2" : function(topic, data) {
|
||||
postal.configuration.bus.publish({ channel: DEFAULT_CHANNEL, topic: topic, timeStamp: new Date(), data: data });
|
||||
},
|
||||
"3" : function(channel, topic, data) {
|
||||
postal.configuration.bus.publish({ channel: channel, topic: topic, timeStamp: new Date(), data: data });
|
||||
}
|
||||
};
|
||||
channelPicker = {
|
||||
"1" : function( chn ) {
|
||||
var channel = chn, topic, options = {};
|
||||
if( Object.prototype.toString.call( channel ) === "[object String]" ) {
|
||||
channel = DEFAULT_CHANNEL;
|
||||
topic = chn;
|
||||
}
|
||||
else {
|
||||
channel = chn.channel || DEFAULT_CHANNEL;
|
||||
topic = chn.topic;
|
||||
options = chn.options || options;
|
||||
}
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
},
|
||||
"2" : function( chn, tpc ) {
|
||||
var channel = chn, topic = tpc, options = {};
|
||||
if( Object.prototype.toString.call( tpc ) === "[object Object]" ) {
|
||||
channel = DEFAULT_CHANNEL;
|
||||
topic = chn;
|
||||
options = tpc;
|
||||
}
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
},
|
||||
"3" : function( channel, topic, options ) {
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
}
|
||||
};
|
||||
|
||||
// save some setup time, albeit tiny
|
||||
localBus.subscriptions[SYSTEM_CHANNEL] = {};
|
||||
|
|
@ -325,24 +358,22 @@ localBus.subscriptions[SYSTEM_CHANNEL] = {};
|
|||
var postal = {
|
||||
configuration: {
|
||||
bus: localBus,
|
||||
resolver: bindingsResolver
|
||||
resolver: bindingsResolver,
|
||||
DEFAULT_CHANNEL: DEFAULT_CHANNEL,
|
||||
DEFAULT_PRIORITY: DEFAULT_PRIORITY,
|
||||
DEFAULT_DISPOSEAFTER: DEFAULT_DISPOSEAFTER,
|
||||
SYSTEM_CHANNEL: SYSTEM_CHANNEL
|
||||
},
|
||||
|
||||
channelTypes: {
|
||||
LocalChannel: ChannelDefinition
|
||||
},
|
||||
|
||||
channel: function() {
|
||||
var len = arguments.length,
|
||||
channel = arguments[0],
|
||||
tpc = arguments[1];
|
||||
if(len === 1) {
|
||||
if(Object.prototype.toString.call(channel) === "[object String]") {
|
||||
channel = DEFAULT_CHANNEL;
|
||||
tpc = arguments[0];
|
||||
}
|
||||
else {
|
||||
channel = arguments[0].channel || DEFAULT_CHANNEL;
|
||||
tpc = arguments[0].topic;
|
||||
}
|
||||
var len = arguments.length;
|
||||
if(channelPicker[len]) {
|
||||
return channelPicker[len].apply(this, arguments);
|
||||
}
|
||||
return new ChannelDefinition(channel, tpc);
|
||||
},
|
||||
|
||||
subscribe: function(options) {
|
||||
|
|
@ -355,7 +386,7 @@ var postal = {
|
|||
publish: function() {
|
||||
var len = arguments.length;
|
||||
if(publishPicker[len]) {
|
||||
publishPicker[len].apply(this, arguments);
|
||||
return publishPicker[len].apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
Binary file not shown.
2
example/amd/js/libs/postal/postal.min.js
vendored
2
example/amd/js/libs/postal/postal.min.js
vendored
File diff suppressed because one or more lines are too long
51
example/node/client/css/style.css
Normal file
51
example/node/client/css/style.css
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
body {
|
||||
font-family: Tahoma, Arial;
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
width: 285px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.images {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
border: .5pt solid black;
|
||||
}
|
||||
|
||||
.scrollableDiv {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 570px;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
float: left;
|
||||
margin: 0px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.nav-menu li {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.search {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.search input[type='text'] {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#stats {
|
||||
|
||||
}
|
||||
BIN
example/node/client/images/default_profile_1_normal.png
Normal file
BIN
example/node/client/images/default_profile_1_normal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
example/node/client/images/pattern.png
Normal file
BIN
example/node/client/images/pattern.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
13
example/node/client/index.html
Normal file
13
example/node/client/index.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="/">
|
||||
<title>Twitter Hash Tag Stats Demo</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script data-main="js/main" src="js/lib/require-jquery.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
56
example/node/client/js/infrastructure/app.js
Normal file
56
example/node/client/js/infrastructure/app.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
define([
|
||||
'jquery',
|
||||
'backbone',
|
||||
'bus',
|
||||
'infrastructure/router',
|
||||
'infrastructure/view-manager',
|
||||
'views/container',
|
||||
'views/menu',
|
||||
'views/tweet-count',
|
||||
'views/mention-count',
|
||||
'views/mentioner-count',
|
||||
'views/hash-tag-count',
|
||||
'views/profanity-percentage'
|
||||
], function( $, Backbone, bus, Router, ViewManager, ContainerView, MenuView, TweetCountView, MentionCountView,
|
||||
MentionerCountView, HashTagCountView, ProfanityPercentage ) {
|
||||
var app = {
|
||||
bus: bus,
|
||||
router: new Router()
|
||||
};
|
||||
|
||||
postal.configuration.getSessionIdentifier(
|
||||
function( id ) {
|
||||
console.log("SessionID: " + id);
|
||||
}
|
||||
);
|
||||
|
||||
// Set up UI concerns
|
||||
app.viewManager = new ViewManager();
|
||||
app.bus.viewManager.subscribe( "ui.show", function( data, env ) {
|
||||
app.viewManager.UI[ data.name ].activate( data.context );
|
||||
});
|
||||
|
||||
app.viewManager.registerViews([
|
||||
{ name: "container", ctor: ContainerView },
|
||||
{ name: "menu", ctor: MenuView },
|
||||
{ name: "tweetCount", ctor: TweetCountView },
|
||||
{ name: "mentionCount", ctor: MentionCountView },
|
||||
{ name: "mentionerCount", ctor: MentionerCountView },
|
||||
{ name: "hashTagCount", ctor: HashTagCountView },
|
||||
{ name: "profanityPercentage", ctor: ProfanityPercentage }
|
||||
]);
|
||||
app.viewManager.defineUIs([
|
||||
{ name: "homeUI", dependencies: [ "container", "menu", "tweetCount", "mentionCount", "mentionerCount", "hashTagCount", "profanityPercentage" ] },
|
||||
{ name: "statSelectionUI", dependencies: [ "container", "menu" ] },
|
||||
{ name: "wireTapLogUI", dependencies: [ "menu" ], options: { noHide: true } }
|
||||
]);
|
||||
|
||||
$(function() {
|
||||
Backbone.history.start({
|
||||
pushState: true,
|
||||
root: $( "base" ).attr( "href" )
|
||||
});
|
||||
});
|
||||
|
||||
return app;
|
||||
});
|
||||
11
example/node/client/js/infrastructure/bus.js
Normal file
11
example/node/client/js/infrastructure/bus.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
define([
|
||||
'postal'
|
||||
], function ( postal ) {
|
||||
return {
|
||||
router : postal.channel( "router", "*" ),
|
||||
viewManager : postal.channel( "viewmanager", "*" ),
|
||||
data : postal.channel( "data", "*" ),
|
||||
app : postal.channel( "statsApp", "*", { type: "websocket" } ),
|
||||
stats : postal.channel( "stats", "*", { type: "websocket" } )
|
||||
}
|
||||
});
|
||||
316
example/node/client/js/infrastructure/postal.socket-client.js
Normal file
316
example/node/client/js/infrastructure/postal.socket-client.js
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/*
|
||||
postal.socket
|
||||
Author: Jim Cowart
|
||||
License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license)
|
||||
Version 0.1.0
|
||||
*/
|
||||
|
||||
(function( root, doc, factory ) {
|
||||
if ( typeof define === "function" && define.amd ) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define( [ "underscore", "machina", "postal" ], function( _, machina, postal ) {
|
||||
return factory( _, machina, postal, root, doc );
|
||||
});
|
||||
} else {
|
||||
// Browser globals
|
||||
factory( root._, root.machina, root.postal, root, doc );
|
||||
}
|
||||
}(this, document, function( _, machina, postal, global, document, undefined ) {
|
||||
|
||||
var sessionId = undefined;
|
||||
|
||||
// Default implementation passes back undefined, which means
|
||||
// the socket.io socket sessionid will be used....
|
||||
postal.configuration.getSessionIdentifier = function( callback ) {
|
||||
callback( sessionId );
|
||||
};
|
||||
|
||||
postal.configuration.setSessionIdentifier = function( value ) {
|
||||
sessionId = value;
|
||||
};
|
||||
|
||||
postal.configuration.lastSessionId = null;
|
||||
|
||||
postal.getSubscribersFor = function() {
|
||||
var channel = arguments[ 0 ],
|
||||
tpc = arguments[ 1 ],
|
||||
result = [];
|
||||
if( arguments.length === 1 ) {
|
||||
if( Object.prototype.toString.call( channel ) === "[object String]" ) {
|
||||
channel = postal.configuration.DEFAULT_CHANNEL;
|
||||
tpc = arguments[ 0 ];
|
||||
}
|
||||
else {
|
||||
channel = arguments[ 0 ].channel || postal.configuration.DEFAULT_CHANNEL;
|
||||
tpc = arguments[ 0 ].topic;
|
||||
}
|
||||
}
|
||||
if( postal.configuration.bus.subscriptions[ channel ] &&
|
||||
postal.configuration.bus.subscriptions[ channel ].hasOwnProperty( tpc )) {
|
||||
result = postal.configuration.bus.subscriptions[ channel ][ tpc ];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/*
|
||||
adding a socket namespace to postal
|
||||
which provides the following members:
|
||||
1.) config - provides values used to manage the socket connection
|
||||
2.) goOffline() - tells the manager to close the connection intentionally
|
||||
3.) goOnline() - tells the manager to try to connect.
|
||||
4.) manifest - an array of objects describing the subscriptions that have been
|
||||
set up on the remote end.
|
||||
5.) publish() - takes a valid postal envelope and pushes it through the socket
|
||||
to be published to the server instance of postal.
|
||||
6.) socketMgr - the FSM managing the socket connection
|
||||
7.) socketNamespace - exposed currently for debugging only
|
||||
8.) subscribe() - passes an object through the socket to the server
|
||||
which contains data necessary to set up a remote subscription. The
|
||||
options passed to the socket would look similar to this:
|
||||
{
|
||||
"channel":"SomeChannel",
|
||||
"topic":"my.topic",
|
||||
"correlationId":"2073383865318591267"
|
||||
}
|
||||
The "correlationId" is used on the remote side to apply a constraint to
|
||||
the subscription, enabling just this specific client to be targeted on
|
||||
and otherwise public channel.
|
||||
9.) unsubscribe() - passes an object through the socket to the server
|
||||
which contains data necessary to remove a remote subscription. The options
|
||||
passed would look similar to the example above in #8.
|
||||
*/
|
||||
postal.connections = postal.connections || {};
|
||||
|
||||
var postalSocket = postal.connections.socket = (function(){
|
||||
var socketNamespace,
|
||||
fsm = new machina.Fsm({
|
||||
retryFn: undefined,
|
||||
wireUpSocketEvents: function() {
|
||||
var self = this;
|
||||
_.each([ "connect", "connecting", "connect_failed", "disconnect", "reconnect", "reconnect_failed",
|
||||
"reconnecting", "postal.socket.remote", "postal.socket.identified", "postal.socket.migration" ],
|
||||
function( evnt ) {
|
||||
socketNamespace.on( evnt, function( data ) {
|
||||
self.handle( evnt, data );
|
||||
});
|
||||
});
|
||||
},
|
||||
states: {
|
||||
uninitialized: {
|
||||
tryConnect: function() {
|
||||
this.transition("initializing");
|
||||
}
|
||||
},
|
||||
initializing: {
|
||||
_onEnter: function() {
|
||||
socketNamespace = io.connect(postalSocket.config.url, { "auto connect": false });
|
||||
this.wireUpSocketEvents();
|
||||
this.transition("probing");
|
||||
},
|
||||
socketTransmit: function() {
|
||||
this.deferUntilTransition("online");
|
||||
}
|
||||
},
|
||||
probing: {
|
||||
_onEnter: function() {
|
||||
clearTimeout(this.retryFn);
|
||||
if(!socketNamespace.socket.connecting && !socketNamespace.socket.reconnecting) {
|
||||
socketNamespace.socket.connect();
|
||||
}
|
||||
},
|
||||
connect: function(){
|
||||
this.transition("identifying");
|
||||
},
|
||||
connect_failed: function() {
|
||||
this.transition("disconnected");
|
||||
},
|
||||
maxAttempts: function() {
|
||||
this.transition("offline");
|
||||
},
|
||||
"postal.socket.remote" : function() {
|
||||
this.deferUntilTransition("online");
|
||||
},
|
||||
reconnect: function(){
|
||||
this.transition("identifying");
|
||||
},
|
||||
reconnect_failed: function() {
|
||||
this.transition("disconnected");
|
||||
},
|
||||
socketTransmit: function() {
|
||||
this.deferUntilTransition("online");
|
||||
}
|
||||
},
|
||||
identifying: {
|
||||
_onEnter: function() {
|
||||
var self = this;
|
||||
self.retryFn = setTimeout(function() {
|
||||
self.handle( "timeout.identifying" );
|
||||
},postalSocket.config.reconnectInterval );
|
||||
postal.configuration.getSessionIdentifier( function( id ) {
|
||||
if( !id ) {
|
||||
postal.configuration.setSessionIdentifier( socketNamespace.socket.sessionid );
|
||||
}
|
||||
self.handle( "client.identifier", { sessionId: id || socketNamespace.socket.sessionid } );
|
||||
});
|
||||
},
|
||||
"client.identifier" : function( data ) {
|
||||
clearTimeout( this.retryFn );
|
||||
var lastSessionId = postal.configuration.lastSessionId;
|
||||
postal.configuration.lastSessionId = data.sessionId;
|
||||
socketNamespace.emit( "postal.clientId", { sessionId: postal.configuration.lastSessionId, lastSessionId: lastSessionId } );
|
||||
},
|
||||
connect_failed: function() {
|
||||
this.transition("disconnected");
|
||||
},
|
||||
disconnect: function() {
|
||||
this.transition("probing");
|
||||
},
|
||||
"postal.socket.identified" : function( data ) {
|
||||
this.transition("online");
|
||||
},
|
||||
"postal.socket.migration" : function() {
|
||||
_.each(postal.socket.manifest, function( sub ) {
|
||||
fsm.handle( "socketTransmit", "postal.subscribe", sub );
|
||||
});
|
||||
socketNamespace.emit( "postal.migrationComplete", {} );
|
||||
},
|
||||
"postal.socket.remote" : function() {
|
||||
this.deferUntilTransition("online");
|
||||
},
|
||||
reconnect_failed: function() {
|
||||
this.transition("disconnected");
|
||||
},
|
||||
socketTransmit: function( evntName, envelope ) {
|
||||
if( evntName === "postal.subscribe" ){
|
||||
// we risk mutating the message here, so extend
|
||||
// and add the correlationId to the extended copy
|
||||
var socketEnv = _.extend( {}, envelope );
|
||||
socketEnv.correlationId = postal.configuration.lastSessionId;
|
||||
socketNamespace.emit(evntName, socketEnv);
|
||||
}
|
||||
else {
|
||||
this.deferUntilTransition("online");
|
||||
}
|
||||
},
|
||||
"timeout.identifying" : function() {
|
||||
this.transition("probing");
|
||||
}
|
||||
},
|
||||
online: {
|
||||
disconnect: function() {
|
||||
this.transition("probing");
|
||||
},
|
||||
goOffline: function() {
|
||||
this.transition("offline");
|
||||
},
|
||||
"postal.socket.remote" : function( envelope ) {
|
||||
postal.publish( envelope );
|
||||
},
|
||||
socketTransmit: function( evntName, envelope ) {
|
||||
// we risk mutating the message here, so extend
|
||||
// and add the correlationId to the extended copy
|
||||
var socketEnv = _.extend( {}, envelope );
|
||||
socketEnv.correlationId = postal.configuration.lastSessionId;
|
||||
socketNamespace.emit(evntName, socketEnv);
|
||||
}
|
||||
},
|
||||
offline: {
|
||||
_onEnter: function() {
|
||||
socketNamespace.socket.disconnect();
|
||||
},
|
||||
socketTransmit: function() {
|
||||
this.deferUntilTransition("online");
|
||||
},
|
||||
"tryConnect": function() {
|
||||
this.transition("probing");
|
||||
}
|
||||
},
|
||||
disconnected: {
|
||||
_onEnter: function() {
|
||||
var self = this;
|
||||
self.retryFn = setTimeout(function() {
|
||||
self.transition("probing");
|
||||
},postalSocket.config.reconnectInterval);
|
||||
},
|
||||
connecting: function() {
|
||||
this.transition("probing");
|
||||
},
|
||||
reconnecting: function() {
|
||||
this.transition("probing");
|
||||
},
|
||||
socketTransmit: function() {
|
||||
this.deferUntilTransition("online");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return {
|
||||
config : {
|
||||
url: window.location.origin,
|
||||
reconnectInterval: 4000
|
||||
},
|
||||
goOffline: function() {
|
||||
fsm.handle( "goOffline" );
|
||||
},
|
||||
goOnline: function() {
|
||||
fsm.handle( "tryConnect" );
|
||||
},
|
||||
manifest: [],
|
||||
publish: function( envelope ) {
|
||||
fsm.handle( "socketTransmit", "postal.publish", envelope );
|
||||
},
|
||||
subscribe: function( options ) {
|
||||
options.channel = options.channel || postal.configuration.DEFAULT_CHANNEL;
|
||||
options.topic = options.topic || "*";
|
||||
if( !_.any( this.manifest, function( item ){
|
||||
return item.channel === options.channel && item.topic === options.topic;
|
||||
})) {
|
||||
this.manifest.push( options );
|
||||
fsm.handle( "socketTransmit", "postal.subscribe", options );
|
||||
}
|
||||
},
|
||||
socketMgr: fsm,
|
||||
socketNamespace: socketNamespace,
|
||||
unsubscribe: function( options ) {
|
||||
options.channel = options.channel || postal.configuration.DEFAULT_CHANNEL;
|
||||
options.topic = options.topic || "*";
|
||||
if( !postal.getSubscribersFor( options.channel, options.topic ).length ) {
|
||||
fsm.handle( "socketTransmit", "postal.unsubscribe", options);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
postal.connections.socket.goOnline();
|
||||
var SocketChannel = postal.channelTypes.websocket = function( channelName, defaultTopic ) {
|
||||
var channel = postal.channel( channelName, defaultTopic ),
|
||||
localSubscribe = channel.subscribe,
|
||||
localPublish = channel.publish,
|
||||
localTopic = channel.topic;
|
||||
|
||||
channel.publish = function() {
|
||||
postalSocket.publish( localPublish.apply( channel, arguments) );
|
||||
};
|
||||
|
||||
channel.subscribe = function() {
|
||||
var sub = localSubscribe.apply( channel, arguments),
|
||||
origUnsubscribe;
|
||||
origUnsubscribe = sub.unsubscribe;
|
||||
sub.unsubscribe = function() {
|
||||
origUnsubscribe.call(sub);
|
||||
postalSocket.unsubscribe({ channel: sub.channel, topic: sub.topic });
|
||||
};
|
||||
postalSocket.subscribe({ channel: sub.channel, topic: sub.topic });
|
||||
return sub;
|
||||
};
|
||||
|
||||
channel.topic = function( topic ) {
|
||||
if(topic === channel._topic) {
|
||||
return this;
|
||||
}
|
||||
return new SocketChannel(this.channel, topic);
|
||||
};
|
||||
|
||||
return channel;
|
||||
};
|
||||
|
||||
}));
|
||||
52
example/node/client/js/infrastructure/router.js
Normal file
52
example/node/client/js/infrastructure/router.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
define([
|
||||
'jquery',
|
||||
'backbone',
|
||||
'bus'
|
||||
], function( $, Backbone, bus ){
|
||||
|
||||
return Backbone.Router.extend({
|
||||
routes: {
|
||||
"" : "home",
|
||||
"select" : "select",
|
||||
"wiretap" : "wiretap",
|
||||
"*anything" : "redirect"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var self = this;
|
||||
_.bindAll( self );
|
||||
|
||||
$( document ).delegate( "a.ps-nav", "click", function( e ){
|
||||
e.preventDefault();
|
||||
self.navigate( $( this ).attr( 'href' ), { trigger: true });
|
||||
});
|
||||
bus.router.publish( "initialized" );
|
||||
},
|
||||
|
||||
activateUI: function( uiName, context ) {
|
||||
bus.viewManager.publish({
|
||||
topic: "ui.show",
|
||||
data: {
|
||||
name: uiName,
|
||||
context: context
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
home: function() {
|
||||
this.activateUI( "homeUI" );
|
||||
},
|
||||
|
||||
select: function() {
|
||||
this.activateUI( "statSelectionUI" );
|
||||
},
|
||||
|
||||
wiretap: function() {
|
||||
this.activateUI( "wireTapLogUI" );
|
||||
},
|
||||
|
||||
redirect: function() {
|
||||
this.navigate( "/", { trigger: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
121
example/node/client/js/infrastructure/view-manager.js
Normal file
121
example/node/client/js/infrastructure/view-manager.js
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
define([
|
||||
'underscore',
|
||||
'bus'
|
||||
], function( _, bus ){
|
||||
var ViewManager = function() {
|
||||
this.views = {}; // holds the views that are registered with the manager
|
||||
this.UI = {}; // holds the UI configurations that are defined
|
||||
this.priorContext = undefined; // holds the name of the last UI configuration
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// registerView - registers a view with the manager, under the name provided.
|
||||
// The handle to the constructor function (second arg) is used to create an
|
||||
// instance of the view the first time getInstance is called. The rendered
|
||||
// and visible booleans are used by the ViewManager to track state of the view.
|
||||
// The getInstance call can take an options object. If options.forceNew = true,
|
||||
// then the ViewManager will create a new instance of the view. If options.args
|
||||
// exists, it will be passed into the constructor function of the view.
|
||||
//----------------------------------------------------------------------------
|
||||
ViewManager.prototype.registerView = function(name, viewCtor) {
|
||||
this.views[name] = {
|
||||
rendered: false,
|
||||
visible: false,
|
||||
getInstance: (function(){
|
||||
var _instance;
|
||||
return function(options){
|
||||
var _options = options || {};
|
||||
if(!_instance || _options.forceNew) {
|
||||
_instance = new viewCtor(_options.args || {});
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
})()
|
||||
}
|
||||
};
|
||||
|
||||
ViewManager.prototype.registerViews = function(views) {
|
||||
_.each( views, function( view ){
|
||||
this.registerView( view.name, view.ctor );
|
||||
}, this );
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// defineUI - defines a UI configuration, which is effectively a named group
|
||||
// of views that need to be stood up, in order. The first argument is the UI
|
||||
// name, second arg is the array of view names (in the order they need to be
|
||||
// instantiated/rendered/shown)
|
||||
//----------------------------------------------------------------------------
|
||||
ViewManager.prototype.defineUI = function( name, dependencies, options ) {
|
||||
var self = this;
|
||||
self.UI[ name ] = {
|
||||
options: options || {},
|
||||
dependencies: dependencies,
|
||||
activate: function( data ) {
|
||||
data = data || {};
|
||||
data.priorContext = self.priorContext;
|
||||
data.targetContext = name;
|
||||
|
||||
if( !this.options.noHide ) {
|
||||
// hide anything visible that's not in the dependencies for this UI configuration
|
||||
var shouldHide = _.reduce( self.views, function( memo, val, key ){
|
||||
if( val.visible && !_.include( this.dependencies, key ) ){
|
||||
memo.push( key );
|
||||
}
|
||||
return memo;
|
||||
}, [], this );
|
||||
|
||||
_.each( shouldHide, function( viewName ){
|
||||
var instance = self.views[ viewName ].getInstance();
|
||||
if( instance.hide ) {
|
||||
instance.hide();
|
||||
}
|
||||
self.views[ viewName ].visible = false;
|
||||
});
|
||||
}
|
||||
|
||||
// set up, render & show the dependencies for this UI configuration
|
||||
_.each(this.dependencies, function(viewName){
|
||||
var instance = self.views[viewName].getInstance(data);
|
||||
if(!self.views[viewName].rendered) {
|
||||
instance.render(data);
|
||||
self.views[viewName].rendered = true;
|
||||
}
|
||||
if(!self.views[viewName].visible) {
|
||||
if(instance.show) {
|
||||
instance.show(data);
|
||||
}
|
||||
self.views[viewName].visible = true;
|
||||
}
|
||||
|
||||
if(instance.update) {
|
||||
instance.update(data);
|
||||
}
|
||||
});
|
||||
self.priorContext = name;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ViewManager.prototype.defineUIs = function( uis ) {
|
||||
_.each( uis, function( ui ){
|
||||
this.defineUI( ui.name, ui.dependencies, ui.options );
|
||||
}, this );
|
||||
};
|
||||
|
||||
ViewManager.prototype.addViewToUI = function( uiName, viewName, viewCtor ) {
|
||||
var uis = _.isArray( uiName ) ? uiName : [ uiName ];
|
||||
|
||||
if( !this.views[ viewName ] ) {
|
||||
this.registerView( viewName, viewCtor );
|
||||
}
|
||||
|
||||
_.each( uis, function( ui ) {
|
||||
if( this.UI[ ui ] ) {
|
||||
this.UI[ ui ].dependencies.push( viewName );
|
||||
}
|
||||
}, this );
|
||||
};
|
||||
|
||||
return ViewManager;
|
||||
});
|
||||
10
example/node/client/js/lib/amplify.js
Normal file
10
example/node/client/js/lib/amplify.js
Normal file
File diff suppressed because one or more lines are too long
39
example/node/client/js/lib/backbone.js
Normal file
39
example/node/client/js/lib/backbone.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Backbone.js 0.9.2
|
||||
|
||||
// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||
// Backbone may be freely distributed under the MIT license.
|
||||
// For all details and documentation:
|
||||
// http://backbonejs.org
|
||||
(function(h,g){typeof exports!=="undefined"?g(h,exports,require("underscore")):typeof define==="function"&&define.amd?define(["underscore","jquery","exports"],function(f,i,p){h.Backbone=g(h,p,f,i)}):h.Backbone=g(h,{},h._,h.jQuery||h.Zepto||h.ender)})(this,function(h,g,f,i){var p=h.Backbone,y=Array.prototype.slice,z=Array.prototype.splice;g.VERSION="0.9.2";g.setDomLibrary=function(a){i=a};g.noConflict=function(){h.Backbone=p;return g};g.emulateHTTP=false;g.emulateJSON=false;var q=/\s+/,l=g.Events=
|
||||
{on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(q);for(d=this._callbacks||(this._callbacks={});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,k,g,j,h;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(q):f.keys(e);d=a.shift();)if(k=e[d],delete e[d],k&&(b||c))for(g=k.tail;(k=k.next)!==g;)if(j=k.callback,h=k.context,b&&j!==b||c&&h!==c)this.on(d,j,h);return this}},
|
||||
trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(q);for(g=y.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};l.bind=l.on;l.unbind=l.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);if(b&&b.collection)this.collection=b.collection;
|
||||
this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent={};this._pending={};this.set(a,{silent:true});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,l,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;
|
||||
if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(b==null?"":""+b)},has:function(a){return this.get(a)!=null},set:function(a,b,c){var d,e;f.isObject(a)||a==null?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;if(d instanceof o)d=d.attributes;if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return false;if(this.idAttribute in d)this.id=d[this.idAttribute];var b=c.changes={},g=this.attributes,h=this._escapedAttributes,j=this._previousAttributes||
|
||||
{};for(e in d){a=d[e];if(!f.isEqual(g[e],a)||c.unset&&f.has(g,e))delete h[e],(c.silent?this._silent:b)[e]=true;c.unset?delete g[e]:g[e]=a;!f.isEqual(j[e],a)||f.has(g,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=true)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=true;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=true;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=
|
||||
a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return false;c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||a==null?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return false;e=f.clone(this.attributes)}a=f.extend({},c,{silent:true});if(d&&!this.set(d,c.wait?a:c))return false;var k=this,h=c.success;c.success=function(a,b,e){b=k.parse(a,e);
|
||||
c.wait&&(delete c.wait,b=f.extend(d||{},b));if(!k.set(b,c))return false;h?h(k,a):k.trigger("sync",k,a,c)};c.error=g.wrapError(c.error,k,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),false;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||
|
||||
g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t();return this.isNew()?a:a+(a.charAt(a.length-1)=="/"?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return this.id==null},change:function(a){a||(a={});var b=this._changing;this._changing=true;for(var c in this._silent)this._pending[c]=true;var d=f.extend({},a.changes,this._silent);
|
||||
this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending={};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=false;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):
|
||||
false;var b,c=false,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length||!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return true;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return true;b&&b.error?
|
||||
b.error(this,c,b):this.trigger("error",this,c,b);return false}});var r=g.Collection=function(a,b){b||(b={});if(b.model)this.model=b.model;if(b.comparator)this.comparator=b.comparator;this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:true,parse:b.parse})};f.extend(r.prototype,l,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,h,j={},i={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];for(c=0,d=
|
||||
a.length;c<d;c++){if(!(e=a[c]=this._prepareModel(a[c],b)))throw Error("Can't add an invalid model to a collection");g=e.cid;h=e.id;j[g]||this._byCid[g]||h!=null&&(i[h]||this._byId[h])?l.push(c):j[g]=i[h]=e}for(c=l.length;c--;)a.splice(l[c],1);for(c=0,d=a.length;c<d;c++)(e=a[c]).on("all",this._onModelEvent,this),this._byCid[e.cid]=e,e.id!=null&&(this._byId[e.id]=e);this.length+=d;z.apply(this.models,[b.at!=null?b.at:this.models.length,0].concat(a));this.comparator&&this.sort({silent:true});if(b.silent)return this;
|
||||
for(c=0,d=this.models.length;c<d;c++)if(j[(e=this.models[c]).cid])b.index=c,e.trigger("add",e,this,b);return this},remove:function(a,b){var c,d,e,g;b||(b={});a=f.isArray(a)?a.slice():[a];for(c=0,d=a.length;c<d;c++)if(g=this.getByCid(a[c])||this.get(a[c])){delete this._byId[g.id];delete this._byCid[g.cid];e=this.indexOf(g);this.models.splice(e,1);this.length--;if(!b.silent)b.index=e,g.trigger("remove",g,this,b);this._removeReference(g)}return this},push:function(a,b){a=this._prepareModel(a,b);this.add(a,
|
||||
b);return a},pop:function(a){var b=this.at(this.length-1);this.remove(b,a);return b},unshift:function(a,b){a=this._prepareModel(a,b);this.add(a,f.extend({at:0},b));return a},shift:function(a){var b=this.at(0);this.remove(b,a);return b},get:function(a){return a==null?void 0:this._byId[a.id!=null?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},where:function(a){return f.isEmpty(a)?[]:this.filter(function(b){for(var c in a)if(a[c]!==b.get(c))return false;
|
||||
return true})},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");var b=f.bind(this.comparator,this);this.comparator.length==1?this.models=this.sortBy(b):this.models.sort(b);a.silent||this.trigger("reset",this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},reset:function(a,b){a||(a=[]);b||(b={});for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);this._reset();this.add(a,f.extend({silent:true},
|
||||
b));b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?f.clone(a):{};if(a.parse===void 0)a.parse=true;var b=this,c=a.success;a.success=function(d,e,f){b[a.add?"add":"reset"](b.parse(d,f),a);c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},create:function(a,b){var c=this,b=b?f.clone(b):{},a=this._prepareModel(a,b);if(!a)return false;b.wait||c.add(a,b);var d=b.success;b.success=function(e,f){b.wait&&c.add(e,b);d?d(e,f):e.trigger("sync",
|
||||
a,f,b)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId={};this._byCid={}},_prepareModel:function(a,b){b||(b={});if(a instanceof o){if(!a.collection)a.collection=this}else{var c;b.collection=this;a=new this.model(a,b);a._validate(a.attributes,b)||(a=false)}return a},_removeReference:function(a){this==a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,
|
||||
b,c,d){(a=="add"||a=="remove")&&c!=this||(a=="destroy"&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this,arguments))}});f.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),function(a){r.prototype[a]=function(){return f[a].apply(f,
|
||||
[this.models].concat(f.toArray(arguments)))}});var u=g.Router=function(a){a||(a={});if(a.routes)this.routes=a.routes;this._bindRoutes();this.initialize.apply(this,arguments)},A=/:\w+/g,B=/\*\w+/g,C=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(u.prototype,l,{initialize:function(){},route:function(a,b,c){g.history||(g.history=new m);f.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+
|
||||
b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b,this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(C,"\\$&").replace(A,"([^/]+)").replace(B,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});var m=g.History=function(){this.handlers=
|
||||
[];f.bindAll(this,"checkUrl")},s=/^[#\/]/,D=/msie [\w.]+/;m.started=false;f.extend(m.prototype,l,{interval:50,getHash:function(a){return(a=(a?a.location:window.location).href.match(/#(.*)$/))?a[1]:""},getFragment:function(a,b){if(a==null)if(this._hasPushState||b){var a=window.location.pathname,c=window.location.search;c&&(a+=c)}else a=this.getHash();a.indexOf(this.options.root)||(a=a.substr(this.options.root.length));return a.replace(s,"")},start:function(a){if(m.started)throw Error("Backbone.history has already been started");
|
||||
m.started=true;this.options=f.extend({},{root:"/"},this.options,a);this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!(!this.options.pushState||!window.history||!window.history.pushState);var a=this.getFragment(),b=document.documentMode;if(b=D.exec(navigator.userAgent.toLowerCase())&&(!b||b<=7))this.iframe=i('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);if(this._hasPushState)i(window).bind("popstate",
|
||||
this.checkUrl);else if(this._wantsHashChange&&"onhashchange"in window&&!b)i(window).bind("hashchange",this.checkUrl);else if(this._wantsHashChange)this._checkUrlInterval=setInterval(this.checkUrl,this.interval);this.fragment=a;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,true),window.location.replace(this.options.root+"#"+this.fragment),true;else if(this._wantsPushState&&this._hasPushState&&
|
||||
b&&a.hash)this.fragment=this.getHash().replace(s,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment);if(!this.options.silent)return this.loadUrl()},stop:function(){i(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);m.started=false},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.getHash(this.iframe)));
|
||||
if(a==this.fragment)return false;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers,function(a){if(a.route.test(b))return a.callback(b),true})},navigate:function(a,b){if(!m.started)return false;if(!b||b===true)b={trigger:b};var c=(a||"").replace(s,"");if(this.fragment!=c)this._hasPushState?(c.indexOf(this.options.root)!=0&&(c=this.options.root+c),this.fragment=c,window.history[b.replace?
|
||||
"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.getHash(this.iframe))&&(b.replace||this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a)},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,"")+"#"+b):a.hash=b}});var v=g.View=function(a){this.cid=
|
||||
f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()},E=/^(\S+)\s*(.*)$/,w="model,collection,el,id,attributes,className,tagName".split(",");f.extend(v.prototype,l,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);b&&i(a).attr(b);c!=null&&i(a).html(c);return a},setElement:function(a,
|
||||
b){this.$el&&this.undelegateEvents();this.$el=a instanceof i?a:i(a);this.el=this.$el[0];b!==false&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=n(this,"events"))){this.undelegateEvents();for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Method "'+a[b]+'" does not exist');var d=b.match(E),e=d[1],d=d[2],c=f.bind(c,this);e+=".delegateEvents"+this.cid;d===""?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+
|
||||
this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=w.length;b<c;b++){var d=w[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el)this.setElement(this.el,false);else{var a=n(this,"attributes")||{};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.setElement(this.make(this.tagName,a),false)}}});o.extend=r.extend=u.extend=v.extend=function(a,b){var c=F(this,a,b);c.extend=this.extend;return c};var G={create:"POST",
|
||||
update:"PUT","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=G[a];c||(c={});var e={type:d,dataType:"json"};if(!c.url)e.url=n(b,"url")||t();if(!c.data&&b&&(a=="create"||a=="update"))e.contentType="application/json",e.data=JSON.stringify(b.toJSON());if(g.emulateJSON)e.contentType="application/x-www-form-urlencoded",e.data=e.data?{model:e.data}:{};if(g.emulateHTTP&&(d==="PUT"||d==="DELETE")){if(g.emulateJSON)e.data._method=d;e.type="POST";e.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",
|
||||
d)}}if(e.type!=="GET"&&!g.emulateJSON)e.processData=false;return i.ajax(f.extend(e,c))};g.wrapError=function(a,b,c){return function(d,e){e=d===b?e:d;a?a(b,e,c):b.trigger("error",b,e,c)}};var x=function(){},F=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){a.apply(this,arguments)};f.extend(d,a);x.prototype=a.prototype;d.prototype=new x;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},n=function(a,b){return!a||
|
||||
!a[b]?null:f.isFunction(a[b])?a[b]():a[b]},t=function(){throw Error('A "url" property or function must be specified');};return g});
|
||||
212
example/node/client/js/lib/machina.js
Normal file
212
example/node/client/js/lib/machina.js
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
machina.js
|
||||
Author: Jim Cowart
|
||||
License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license)
|
||||
Version 0.1.0
|
||||
*/
|
||||
|
||||
(function(root, doc, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(["underscore"], function(_) {
|
||||
return factory(_, root, doc);
|
||||
});
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(root._, root, doc);
|
||||
}
|
||||
}(this, document, function(_, global, document, undefined) {
|
||||
|
||||
var slice = [].slice,
|
||||
NEXT_TRANSITION = "transition",
|
||||
NEXT_HANDLER = "handler",
|
||||
transformEventListToObject = function(eventList){
|
||||
var obj = {};
|
||||
_.each(eventList, function(evntName) {
|
||||
obj[evntName] = [];
|
||||
});
|
||||
return obj;
|
||||
},
|
||||
parseEventListeners = function(evnts) {
|
||||
var obj = evnts;
|
||||
if(_.isArray(evnts)) {
|
||||
obj = transformEventListToObject(evnts);
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
var utils = {
|
||||
makeFsmNamespace: (function(){
|
||||
var machinaCount = 0;
|
||||
return function() {
|
||||
return "fsm." + machinaCount++;
|
||||
};
|
||||
})(),
|
||||
getDefaultOptions: function() {
|
||||
return {
|
||||
initialState: "uninitialized",
|
||||
eventListeners: {
|
||||
"*" : []
|
||||
},
|
||||
states: {},
|
||||
eventQueue: [],
|
||||
namespace: utils.makeFsmNamespace()
|
||||
};
|
||||
}
|
||||
};
|
||||
var Fsm = function(options) {
|
||||
var opt, initialState, defaults = utils.getDefaultOptions();
|
||||
if(options) {
|
||||
if(options.eventListeners) {
|
||||
options.eventListeners = parseEventListeners(options.eventListeners);
|
||||
}
|
||||
if(options.messaging) {
|
||||
options.messaging = _.extend({}, defaults.messaging, options.messaging);
|
||||
}
|
||||
}
|
||||
opt = _.extend(defaults , options || {});
|
||||
initialState = opt.initialState;
|
||||
delete opt.initialState;
|
||||
_.extend(this,opt);
|
||||
|
||||
this.state = undefined;
|
||||
this._priorAction = "";
|
||||
this._currentAction = "";
|
||||
if(initialState) {
|
||||
this.transition(initialState);
|
||||
}
|
||||
machina.fireEvent("newFsm", this);
|
||||
};
|
||||
|
||||
Fsm.prototype.fireEvent = function(eventName) {
|
||||
var args = arguments;
|
||||
_.each(this.eventListeners["*"], function(callback) {
|
||||
try {
|
||||
callback.apply(this,slice.call(args, 0));
|
||||
} catch(exception) {
|
||||
if(console && typeof console.log !== "undefined") {
|
||||
console.log(exception.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
if(this.eventListeners[eventName]) {
|
||||
_.each(this.eventListeners[eventName], function(callback) {
|
||||
try {
|
||||
callback.apply(this,slice.call(args, 1));
|
||||
} catch(exception) {
|
||||
if(console && typeof console.log !== "undefined") {
|
||||
console.log(exception.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Fsm.prototype.handle = function(msgType) {
|
||||
// vars to avoid a "this." fest
|
||||
var states = this.states, current = this.state, args = slice.call(arguments,0), handlerName;
|
||||
this.currentActionArgs = args;
|
||||
if(states[current] && (states[current][msgType] || states[current]["*"])) {
|
||||
handlerName = states[current][msgType] ? msgType : "*";
|
||||
this._currentAction = current + "." + handlerName;
|
||||
this.fireEvent.apply(this, ["Handling"].concat(args));
|
||||
states[current][handlerName].apply(this, args.slice(1));
|
||||
this.fireEvent.apply(this, ["Handled"].concat(args));
|
||||
this._priorAction = this._currentAction;
|
||||
this._currentAction = "";
|
||||
this.processQueue(NEXT_HANDLER);
|
||||
}
|
||||
else {
|
||||
this.fireEvent.apply(this, ["NoHandler"].concat(args));
|
||||
}
|
||||
this.currentActionArgs = undefined;
|
||||
};
|
||||
|
||||
Fsm.prototype.transition = function(newState) {
|
||||
if(this.states[newState]){
|
||||
var oldState = this.state;
|
||||
this.state = newState;
|
||||
if(this.states[newState]._onEnter) {
|
||||
this.states[newState]._onEnter.call( this );
|
||||
}
|
||||
this.fireEvent.apply(this, ["Transitioned", oldState, this.state ]);
|
||||
this.processQueue(NEXT_TRANSITION);
|
||||
return;
|
||||
}
|
||||
this.fireEvent.apply(this, ["InvalidState", this.state, newState ]);
|
||||
};
|
||||
|
||||
Fsm.prototype.processQueue = function(type) {
|
||||
var filterFn = type === NEXT_TRANSITION ?
|
||||
function(item){
|
||||
return item.type === NEXT_TRANSITION && ((!item.untilState) || (item.untilState === this.state));
|
||||
} :
|
||||
function(item) {
|
||||
return item.type === NEXT_HANDLER;
|
||||
},
|
||||
toProcess = _.filter(this.eventQueue, filterFn, this);
|
||||
this.eventQueue = _.difference(this.eventQueue, toProcess);
|
||||
_.each(toProcess, function(item, index){
|
||||
this.handle.apply(this, item.args);
|
||||
}, this);
|
||||
};
|
||||
|
||||
Fsm.prototype.deferUntilTransition = function(stateName) {
|
||||
if(this.currentActionArgs) {
|
||||
var queued = { type: NEXT_TRANSITION, untilState: stateName, args: this.currentActionArgs };
|
||||
this.eventQueue.push(queued);
|
||||
this.fireEvent.apply(this, [ "Deferred", this.state, queued ]);
|
||||
}
|
||||
};
|
||||
|
||||
Fsm.prototype.deferUntilNextHandler = function() {
|
||||
if(this.currentActionArgs) {
|
||||
var queued = { type: NEXT_TRANSITION, args: this.currentActionArgs };
|
||||
this.eventQueue.push(queued);
|
||||
this.fireEvent.apply(this, [ "Deferred", this.state, queued ]);
|
||||
}
|
||||
};
|
||||
|
||||
Fsm.prototype.on = function(eventName, callback) {
|
||||
if(!this.eventListeners[eventName]) {
|
||||
this.eventListeners[eventName] = [];
|
||||
}
|
||||
this.eventListeners[eventName].push(callback);
|
||||
};
|
||||
|
||||
Fsm.prototype.off = function(eventName, callback) {
|
||||
if(this.eventListeners[eventName]){
|
||||
this.eventListeners[eventName] = _.without(this.eventListeners[eventName], callback);
|
||||
}
|
||||
};
|
||||
|
||||
var machina = {
|
||||
Fsm: Fsm,
|
||||
bus: undefined,
|
||||
utils: utils,
|
||||
on: function(eventName, callback) {
|
||||
if(!this.eventListeners[eventName]) {
|
||||
this.eventListeners[eventName] = [];
|
||||
}
|
||||
this.eventListeners[eventName].push(callback);
|
||||
},
|
||||
off: function(eventName, callback) {
|
||||
if(this.eventListeners[eventName]){
|
||||
this.eventListeners[eventName] = _.without(this.eventListeners[eventName], callback);
|
||||
}
|
||||
},
|
||||
fireEvent: function(eventName) {
|
||||
var i = 0, len, args = arguments, listeners = this.eventListeners[eventName];
|
||||
if(listeners && listeners.length) {
|
||||
_.each(listeners, function(callback) {
|
||||
callback.apply(null,slice.call(args, 1));
|
||||
});
|
||||
}
|
||||
},
|
||||
eventListeners: {
|
||||
newFsm : []
|
||||
}
|
||||
};
|
||||
|
||||
global.machina = machina;
|
||||
return machina;
|
||||
}));
|
||||
27
example/node/client/js/lib/postal.diagnostics.js
Normal file
27
example/node/client/js/lib/postal.diagnostics.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// This is the amd module version of postal.diagnostics.js
|
||||
// If you need the standard lib version, go to http://github.com/ifandelse/postal.js
|
||||
define(["postal", "underscore"], function(postal, _, undefined) {
|
||||
|
||||
|
||||
// this returns a callback that, if invoked, removes the wireTap
|
||||
postal.diagnostics = postal.addWireTap(function(data, envelope) {
|
||||
var all = _.extend(envelope, { data: data });
|
||||
if(!JSON) {
|
||||
throw "This browser or environment does not provide JSON support";
|
||||
}
|
||||
try {
|
||||
//console.log(JSON.stringify(all));
|
||||
}
|
||||
catch(exception) {
|
||||
try {
|
||||
all.data = "ERROR: " + exception.message;
|
||||
//console.log(JSON.stringify(all));
|
||||
}
|
||||
catch(ex) {
|
||||
//console.log("Unable to parse data to JSON: " + exception);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
441
example/node/client/js/lib/postal.js
Normal file
441
example/node/client/js/lib/postal.js
Normal file
|
|
@ -0,0 +1,441 @@
|
|||
/*
|
||||
postal.js
|
||||
Author: Jim Cowart
|
||||
License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license)
|
||||
Version 0.6.0
|
||||
*/
|
||||
|
||||
// This is the amd-module version of postal.js
|
||||
// If you need the standard lib style version, go to http://github.com/ifandelse/postal.js
|
||||
define(["underscore"], function(_, undefined) {
|
||||
|
||||
var DEFAULT_CHANNEL = "/",
|
||||
DEFAULT_PRIORITY = 50,
|
||||
DEFAULT_DISPOSEAFTER = 0,
|
||||
SYSTEM_CHANNEL = "postal",
|
||||
NO_OP = function() { };
|
||||
|
||||
var DistinctPredicate = function() {
|
||||
var previous;
|
||||
return function(data) {
|
||||
var eq = false;
|
||||
if(_.isString(data)) {
|
||||
eq = data === previous;
|
||||
previous = data;
|
||||
}
|
||||
else {
|
||||
eq = _.isEqual(data, previous);
|
||||
previous = _.clone(data);
|
||||
}
|
||||
return !eq;
|
||||
};
|
||||
};
|
||||
|
||||
var ChannelDefinition = function(channelName, defaultTopic) {
|
||||
this.channel = channelName || DEFAULT_CHANNEL;
|
||||
this._topic = defaultTopic || "";
|
||||
};
|
||||
|
||||
ChannelDefinition.prototype = {
|
||||
subscribe: function() {
|
||||
var len = arguments.length;
|
||||
if(len === 1) {
|
||||
return new SubscriptionDefinition(this.channel, this._topic, arguments[0]);
|
||||
}
|
||||
else if (len === 2) {
|
||||
return new SubscriptionDefinition(this.channel, arguments[0], arguments[1]);
|
||||
}
|
||||
},
|
||||
|
||||
publish: function(obj) {
|
||||
var envelope = {
|
||||
channel: this.channel,
|
||||
topic: this._topic,
|
||||
data: obj || {}
|
||||
};
|
||||
// If this is an envelope....
|
||||
if( obj.topic && obj.data ) {
|
||||
envelope = obj;
|
||||
envelope.channel = envelope.channel || this.channel;
|
||||
}
|
||||
envelope.timeStamp = new Date();
|
||||
postal.configuration.bus.publish(envelope);
|
||||
return envelope;
|
||||
},
|
||||
|
||||
topic: function(topic) {
|
||||
if(topic === this._topic) {
|
||||
return this;
|
||||
}
|
||||
return new ChannelDefinition(this.channel, topic);
|
||||
}
|
||||
};
|
||||
|
||||
var SubscriptionDefinition = function(channel, topic, callback) {
|
||||
this.channel = channel;
|
||||
this.topic = topic;
|
||||
this.callback = callback;
|
||||
this.priority = DEFAULT_PRIORITY;
|
||||
this.constraints = new Array(0);
|
||||
this.maxCalls = DEFAULT_DISPOSEAFTER;
|
||||
this.onHandled = NO_OP;
|
||||
this.context = null;
|
||||
postal.configuration.bus.publish({
|
||||
channel: SYSTEM_CHANNEL,
|
||||
topic: "subscription.created",
|
||||
timeStamp: new Date(),
|
||||
data: {
|
||||
event: "subscription.created",
|
||||
channel: channel,
|
||||
topic: topic
|
||||
}
|
||||
});
|
||||
|
||||
postal.configuration.bus.subscribe(this);
|
||||
|
||||
};
|
||||
|
||||
SubscriptionDefinition.prototype = {
|
||||
unsubscribe: function() {
|
||||
postal.configuration.bus.unsubscribe(this);
|
||||
postal.configuration.bus.publish({
|
||||
channel: SYSTEM_CHANNEL,
|
||||
topic: "subscription.removed",
|
||||
timeStamp: new Date(),
|
||||
data: {
|
||||
event: "subscription.removed",
|
||||
channel: this.channel,
|
||||
topic: this.topic
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
defer: function() {
|
||||
var fn = this.callback;
|
||||
this.callback = function(data) {
|
||||
setTimeout(fn,0,data);
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
disposeAfter: function(maxCalls) {
|
||||
if(_.isNaN(maxCalls) || maxCalls <= 0) {
|
||||
throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero.";
|
||||
}
|
||||
|
||||
var fn = this.onHandled;
|
||||
var dispose = _.after(maxCalls, _.bind(function() {
|
||||
this.unsubscribe(this);
|
||||
}, this));
|
||||
|
||||
this.onHandled = function() {
|
||||
fn.apply(this.context, arguments);
|
||||
dispose();
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
ignoreDuplicates: function() {
|
||||
this.withConstraint(new DistinctPredicate());
|
||||
return this;
|
||||
},
|
||||
|
||||
withConstraint: function(predicate) {
|
||||
if(! _.isFunction(predicate)) {
|
||||
throw "Predicate constraint must be a function";
|
||||
}
|
||||
this.constraints.push(predicate);
|
||||
return this;
|
||||
},
|
||||
|
||||
withConstraints: function(predicates) {
|
||||
var self = this;
|
||||
if(_.isArray(predicates)) {
|
||||
_.each(predicates, function(predicate) { self.withConstraint(predicate); } );
|
||||
}
|
||||
return self;
|
||||
},
|
||||
|
||||
withContext: function(context) {
|
||||
this.context = context;
|
||||
return this;
|
||||
},
|
||||
|
||||
withDebounce: function(milliseconds) {
|
||||
if(_.isNaN(milliseconds)) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = _.debounce(fn, milliseconds);
|
||||
return this;
|
||||
},
|
||||
|
||||
withDelay: function(milliseconds) {
|
||||
if(_.isNaN(milliseconds)) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = function(data) {
|
||||
setTimeout(function(){
|
||||
fn(data);
|
||||
}, milliseconds);
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
withPriority: function(priority) {
|
||||
if(_.isNaN(priority)) {
|
||||
throw "Priority must be a number";
|
||||
}
|
||||
this.priority = priority;
|
||||
return this;
|
||||
},
|
||||
|
||||
withThrottle: function(milliseconds) {
|
||||
if(_.isNaN(milliseconds)) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = _.throttle(fn, milliseconds);
|
||||
return this;
|
||||
},
|
||||
|
||||
subscribe: function(callback) {
|
||||
this.callback = callback;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
var bindingsResolver = {
|
||||
cache: { },
|
||||
|
||||
compare: function(binding, topic) {
|
||||
if(this.cache[topic] && this.cache[topic][binding]) {
|
||||
return true;
|
||||
}
|
||||
// binding.replace(/\./g,"\\.") // escape actual periods
|
||||
// .replace(/\*/g, ".*") // asterisks match any value
|
||||
// .replace(/#/g, "[A-Z,a-z,0-9]*"); // hash matches any alpha-numeric 'word'
|
||||
var rgx = new RegExp("^" + binding.replace(/\./g,"\\.").replace(/\*/g, ".*").replace(/#/g, "[A-Z,a-z,0-9]*") + "$"),
|
||||
result = rgx.test(topic);
|
||||
if(result) {
|
||||
if(!this.cache[topic]) {
|
||||
this.cache[topic] = {};
|
||||
}
|
||||
this.cache[topic][binding] = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
var localBus = {
|
||||
|
||||
subscriptions: {},
|
||||
|
||||
wireTaps: new Array(0),
|
||||
|
||||
publish: function(envelope) {
|
||||
_.each(this.wireTaps,function(tap) {
|
||||
tap(envelope.data, envelope);
|
||||
});
|
||||
|
||||
_.each(this.subscriptions[envelope.channel], function(topic) {
|
||||
_.each(topic, function(subDef){
|
||||
if(postal.configuration.resolver.compare(subDef.topic, envelope.topic)) {
|
||||
if(_.all(subDef.constraints, function(constraint) { return constraint(envelope.data,envelope); })) {
|
||||
if(typeof subDef.callback === 'function') {
|
||||
subDef.callback.apply(subDef.context, [envelope.data, envelope]);
|
||||
subDef.onHandled();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
subscribe: function(subDef) {
|
||||
var idx, found, fn, channel = this.subscriptions[subDef.channel], subs;
|
||||
|
||||
if(!channel) {
|
||||
channel = this.subscriptions[subDef.channel] = {};
|
||||
}
|
||||
subs = this.subscriptions[subDef.channel][subDef.topic];
|
||||
if(!subs) {
|
||||
subs = this.subscriptions[subDef.channel][subDef.topic] = new Array(0);
|
||||
}
|
||||
|
||||
idx = subs.length - 1;
|
||||
for(; idx >= 0; idx--) {
|
||||
if(subs[idx].priority <= subDef.priority) {
|
||||
subs.splice(idx + 1, 0, subDef);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
subs.unshift(subDef);
|
||||
}
|
||||
return subDef;
|
||||
},
|
||||
|
||||
unsubscribe: function(config) {
|
||||
if(this.subscriptions[config.channel][config.topic]) {
|
||||
var len = this.subscriptions[config.channel][config.topic].length,
|
||||
idx = 0;
|
||||
for ( ; idx < len; idx++ ) {
|
||||
if (this.subscriptions[config.channel][config.topic][idx] === config) {
|
||||
this.subscriptions[config.channel][config.topic].splice( idx, 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
addWireTap: function(callback) {
|
||||
var self = this;
|
||||
self.wireTaps.push(callback);
|
||||
return function() {
|
||||
var idx = self.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
self.wireTaps.splice(idx,1);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var publishPicker = {
|
||||
"1" : function(envelope) {
|
||||
if(!envelope) {
|
||||
throw new Error("publishing from the 'global' postal.publish call requires a valid envelope.");
|
||||
}
|
||||
envelope.channel = envelope.channel || DEFAULT_CHANNEL;
|
||||
envelope.timeStamp = new Date();
|
||||
postal.configuration.bus.publish(envelope);
|
||||
return envelope;
|
||||
},
|
||||
"2" : function(topic, data) {
|
||||
var envelope = { channel: DEFAULT_CHANNEL, topic: topic, timeStamp: new Date(), data: data };
|
||||
postal.configuration.bus.publish( envelope );
|
||||
return envelope;
|
||||
},
|
||||
"3" : function(channel, topic, data) {
|
||||
var envelope = { channel: channel, topic: topic, timeStamp: new Date(), data: data };
|
||||
postal.configuration.bus.publish( envelope );
|
||||
return envelope;
|
||||
}
|
||||
},
|
||||
channelPicker = {
|
||||
"1" : function( chn ) {
|
||||
var channel = chn, topic, options = {};
|
||||
if( Object.prototype.toString.call( channel ) === "[object String]" ) {
|
||||
channel = DEFAULT_CHANNEL;
|
||||
topic = chn;
|
||||
}
|
||||
else {
|
||||
channel = chn.channel || DEFAULT_CHANNEL;
|
||||
topic = chn.topic;
|
||||
options = chn.options || options;
|
||||
}
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
},
|
||||
"2" : function( chn, tpc ) {
|
||||
var channel = chn, topic = tpc, options = {};
|
||||
if( Object.prototype.toString.call( tpc ) === "[object Object]" ) {
|
||||
channel = DEFAULT_CHANNEL;
|
||||
topic = chn;
|
||||
options = tpc;
|
||||
}
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
},
|
||||
"3" : function( channel, topic, options ) {
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
}
|
||||
};
|
||||
|
||||
// save some setup time, albeit tiny
|
||||
localBus.subscriptions[SYSTEM_CHANNEL] = {};
|
||||
|
||||
var postal = {
|
||||
configuration: {
|
||||
bus: localBus,
|
||||
resolver: bindingsResolver,
|
||||
DEFAULT_CHANNEL: DEFAULT_CHANNEL,
|
||||
DEFAULT_PRIORITY: DEFAULT_PRIORITY,
|
||||
DEFAULT_DISPOSEAFTER: DEFAULT_DISPOSEAFTER,
|
||||
SYSTEM_CHANNEL: SYSTEM_CHANNEL
|
||||
},
|
||||
|
||||
channelTypes: {
|
||||
LocalChannel: ChannelDefinition
|
||||
},
|
||||
|
||||
channel: function() {
|
||||
var len = arguments.length;
|
||||
if(channelPicker[len]) {
|
||||
return channelPicker[len].apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
subscribe: function(options) {
|
||||
var callback = options.callback,
|
||||
topic = options.topic,
|
||||
channel = options.channel || DEFAULT_CHANNEL;
|
||||
return new SubscriptionDefinition(channel, topic, callback);
|
||||
},
|
||||
|
||||
publish: function() {
|
||||
var len = arguments.length;
|
||||
if(publishPicker[len]) {
|
||||
return publishPicker[len].apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
addWireTap: function(callback) {
|
||||
return this.configuration.bus.addWireTap(callback);
|
||||
},
|
||||
|
||||
linkChannels: function(sources, destinations) {
|
||||
var result = [];
|
||||
if(!_.isArray(sources)) {
|
||||
sources = [sources];
|
||||
}
|
||||
if(!_.isArray(destinations)) {
|
||||
destinations = [destinations];
|
||||
}
|
||||
_.each(sources, function(source){
|
||||
var sourceTopic = source.topic || "*";
|
||||
_.each(destinations, function(destination) {
|
||||
var destChannel = destination.channel || DEFAULT_CHANNEL;
|
||||
result.push(
|
||||
postal.subscribe({
|
||||
channel: source.channel || DEFAULT_CHANNEL,
|
||||
topic: source.topic || "*",
|
||||
callback : function(data, env) {
|
||||
var newEnv = env;
|
||||
newEnv.topic = _.isFunction(destination.topic) ? destination.topic(env.topic) : destination.topic || env.topic;
|
||||
newEnv.channel = destChannel;
|
||||
newEnv.data = data;
|
||||
postal.publish(newEnv);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
// we check first in case a custom bus or resolver
|
||||
// doesn't expose subscriptions or a resolver cache
|
||||
if(postal.configuration.bus.subscriptions) {
|
||||
postal.configuration.bus.subscriptions = {};
|
||||
}
|
||||
if(postal.configuration.resolver.cache) {
|
||||
postal.configuration.resolver.cache = {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return postal;
|
||||
});
|
||||
11457
example/node/client/js/lib/require-jquery.js
Normal file
11457
example/node/client/js/lib/require-jquery.js
Normal file
File diff suppressed because it is too large
Load diff
11
example/node/client/js/lib/requirejs-text-1.0.2.js
Normal file
11
example/node/client/js/lib/requirejs-text-1.0.2.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
RequireJS text 1.0.2 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/jrburke/requirejs for details
|
||||
*/
|
||||
(function(){var k=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"],n=/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,o=/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,i=typeof location!=="undefined"&&location.href,p=i&&location.protocol&&location.protocol.replace(/\:/,""),q=i&&location.hostname,r=i&&(location.port||void 0),j=[];define(function(){var g,h,l;typeof window!=="undefined"&&window.navigator&&window.document?h=function(a,c){var b=g.createXhr();b.open("GET",a,!0);b.onreadystatechange=
|
||||
function(){b.readyState===4&&c(b.responseText)};b.send(null)}:typeof process!=="undefined"&&process.versions&&process.versions.node?(l=require.nodeRequire("fs"),h=function(a,c){c(l.readFileSync(a,"utf8"))}):typeof Packages!=="undefined"&&(h=function(a,c){var b=new java.io.File(a),e=java.lang.System.getProperty("line.separator"),b=new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(b),"utf-8")),d,f,g="";try{d=new java.lang.StringBuffer;(f=b.readLine())&&f.length()&&
|
||||
f.charAt(0)===65279&&(f=f.substring(1));for(d.append(f);(f=b.readLine())!==null;)d.append(e),d.append(f);g=String(d.toString())}finally{b.close()}c(g)});return g={version:"1.0.2",strip:function(a){if(a){var a=a.replace(n,""),c=a.match(o);c&&(a=c[1])}else a="";return a},jsEscape:function(a){return a.replace(/(['\\])/g,"\\$1").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r")},createXhr:function(){var a,c,b;if(typeof XMLHttpRequest!==
|
||||
"undefined")return new XMLHttpRequest;else for(c=0;c<3;c++){b=k[c];try{a=new ActiveXObject(b)}catch(e){}if(a){k=[b];break}}if(!a)throw Error("createXhr(): XMLHttpRequest not available");return a},get:h,parseName:function(a){var c=!1,b=a.indexOf("."),e=a.substring(0,b),a=a.substring(b+1,a.length),b=a.indexOf("!");b!==-1&&(c=a.substring(b+1,a.length),c=c==="strip",a=a.substring(0,b));return{moduleName:e,ext:a,strip:c}},xdRegExp:/^((\w+)\:)?\/\/([^\/\\]+)/,useXhr:function(a,c,b,e){var d=g.xdRegExp.exec(a),
|
||||
f;if(!d)return!0;a=d[2];d=d[3];d=d.split(":");f=d[1];d=d[0];return(!a||a===c)&&(!d||d===b)&&(!f&&!d||f===e)},finishLoad:function(a,c,b,e,d){b=c?g.strip(b):b;d.isBuild&&(j[a]=b);e(b)},load:function(a,c,b,e){if(e.isBuild&&!e.inlineText)b();else{var d=g.parseName(a),f=d.moduleName+"."+d.ext,m=c.toUrl(f),h=e&&e.text&&e.text.useXhr||g.useXhr;!i||h(m,p,q,r)?g.get(m,function(c){g.finishLoad(a,d.strip,c,b,e)}):c([f],function(a){g.finishLoad(d.moduleName+"."+d.ext,d.strip,a,b,e)})}},write:function(a,c,b){if(c in
|
||||
j){var e=g.jsEscape(j[c]);b.asModule(a+"!"+c,"define(function () { return '"+e+"';});\n")}},writeFile:function(a,c,b,e,d){var c=g.parseName(c),f=c.moduleName+"."+c.ext,h=b.toUrl(c.moduleName+"."+c.ext)+".js";g.load(f,b,function(){var b=function(a){return e(h,a)};b.asModule=function(a,b){return e.asModule(a,h,b)};g.write(a,f,b,d)},d)}}})})();
|
||||
31
example/node/client/js/lib/underscore.js
Normal file
31
example/node/client/js/lib/underscore.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Underscore.js 1.3.1
|
||||
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||
// Underscore is freely distributable under the MIT license.
|
||||
// Portions of Underscore are inspired or borrowed from Prototype,
|
||||
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
||||
// For all details and documentation:
|
||||
// http://documentcloud.github.com/underscore
|
||||
(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
|
||||
c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
|
||||
h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
|
||||
b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==
|
||||
null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
|
||||
function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
|
||||
e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
|
||||
function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
|
||||
return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
|
||||
c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=
|
||||
b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);
|
||||
return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,
|
||||
d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
|
||||
var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
|
||||
c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
|
||||
a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};
|
||||
b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
|
||||
1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
|
||||
b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
|
||||
b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),
|
||||
function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
|
||||
u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
|
||||
function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
|
||||
true;return this};m.prototype.value=function(){return this._wrapped};typeof define==="function"&&define.amd&&define("underscore",function(){return b})}).call(this);
|
||||
42
example/node/client/js/main.js
Normal file
42
example/node/client/js/main.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
var socket;
|
||||
|
||||
require.config( {
|
||||
paths : {
|
||||
'text' : 'lib/requirejs-text-1.0.2',
|
||||
'backbone' : 'lib/backbone',
|
||||
'underscore': 'lib/underscore',
|
||||
'machina' : 'lib/machina',
|
||||
'postal' : 'lib/postal',
|
||||
'amplify' : 'lib/amplify',
|
||||
'bus' : 'infrastructure/bus'
|
||||
},
|
||||
baseUrl: 'js'
|
||||
} );
|
||||
|
||||
require( [ 'backbone', 'jquery', 'underscore', 'machina', 'postal', 'lib/postal.diagnostics', 'infrastructure/postal.socket-client' ],
|
||||
function( Backbone, $, _, machina, postal ){
|
||||
|
||||
// for debugging purposes ONLY for now:
|
||||
window.postal = postal;
|
||||
|
||||
postal.addWireTap( function( d, e ){
|
||||
if( e.topic === "search.info" ) {
|
||||
console.log( JSON.stringify( e ) );
|
||||
}
|
||||
});
|
||||
|
||||
postal.connections.socket.socketMgr.on( "*", function( evnt, data ){
|
||||
var args = [].slice.call( arguments,1 );
|
||||
if( args[0] === "postal.remote" ) {
|
||||
//console.log( "FSM Event: " + evnt + " - " + JSON.stringify( args[0] ) );
|
||||
}
|
||||
else {
|
||||
//console.log( "FSM Event: " + evnt + " - " + JSON.stringify( args ) );
|
||||
}
|
||||
});
|
||||
|
||||
require([ 'infrastructure/app' ], function( app ) {
|
||||
window.app = app;
|
||||
});
|
||||
|
||||
});
|
||||
31
example/node/client/js/models/hash-tag-count-model.js
Normal file
31
example/node/client/js/models/hash-tag-count-model.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
define( [
|
||||
'backbone',
|
||||
'bus'
|
||||
],
|
||||
function( Backbone, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.Model.extend({
|
||||
defaults: {
|
||||
hashTags: []
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var self = this;
|
||||
this.subscriptions = [
|
||||
bus.stats.subscribe( "hash-tag-count", function( data, env ){
|
||||
if( data.hashTags && data.hashTags.length ) {
|
||||
self.set( "hashTags", _.sortBy( data.hashTags, function( item ) { return item.count * -1; } ) );
|
||||
}
|
||||
})
|
||||
];
|
||||
},
|
||||
|
||||
dispose: function(){
|
||||
_.each( this.subscriptions, function( subscription ){
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
this.clear( { silent: true } );
|
||||
}
|
||||
});
|
||||
});
|
||||
31
example/node/client/js/models/mention-count-model.js
Normal file
31
example/node/client/js/models/mention-count-model.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
define( [
|
||||
'backbone',
|
||||
'bus'
|
||||
],
|
||||
function( Backbone, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.Model.extend({
|
||||
defaults: {
|
||||
mentions: []
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var self = this;
|
||||
this.subscriptions = [
|
||||
bus.stats.subscribe( "mention-count", function( data, env ){
|
||||
if( data.mentions && data.mentions.length ) {
|
||||
self.set( "mentions", _.sortBy( data.mentions, function( item ) { return item.count * -1; } ) );
|
||||
}
|
||||
})
|
||||
];
|
||||
},
|
||||
|
||||
dispose: function(){
|
||||
_.each( this.subscriptions, function( subscription ){
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
this.clear( { silent: true } );
|
||||
}
|
||||
});
|
||||
});
|
||||
31
example/node/client/js/models/mentioner-count-model.js
Normal file
31
example/node/client/js/models/mentioner-count-model.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
define( [
|
||||
'backbone',
|
||||
'bus'
|
||||
],
|
||||
function( Backbone, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.Model.extend({
|
||||
defaults: {
|
||||
mentioners: []
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var self = this;
|
||||
this.subscriptions = [
|
||||
bus.stats.subscribe( "mentioner-count", function( data, env ){
|
||||
if( data.mentioners && data.mentioners.length ) {
|
||||
self.set( "mentioners", _.sortBy( data.mentioners, function( item ) { return item.count * -1; } ) );
|
||||
}
|
||||
})
|
||||
];
|
||||
},
|
||||
|
||||
dispose: function(){
|
||||
_.each( this.subscriptions, function( subscription ){
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
this.clear( { silent: true } );
|
||||
}
|
||||
});
|
||||
});
|
||||
61
example/node/client/js/models/menu-model.js
Normal file
61
example/node/client/js/models/menu-model.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
define( [
|
||||
'backbone',
|
||||
'bus'
|
||||
],
|
||||
function( Backbone, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.Model.extend({
|
||||
defaults: {
|
||||
sessionId: "",
|
||||
searchOwnership: "",
|
||||
searchTerm: "",
|
||||
requests: []
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll( this );
|
||||
this.subscriptions = [
|
||||
bus.app.subscribe( "search.info", this.setCurrentSearch ),
|
||||
bus.app.subscribe( "search.new.ask", this.updateRequests )
|
||||
];
|
||||
bus.app.publish({
|
||||
topic: "get.search.info",
|
||||
data: {}
|
||||
});
|
||||
},
|
||||
|
||||
dispose: function(){
|
||||
_.each( this.subscriptions, function( subscription ){
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
this.clear( { silent: true } );
|
||||
},
|
||||
|
||||
setCurrentSearch: function( data, env ) {
|
||||
var self = this;
|
||||
self.set( "searchTerm", data.searchTerm );
|
||||
postal.configuration.getSessionIdentifier(
|
||||
function( id ) {
|
||||
self.set( "sessionId", id, { silent: true } );
|
||||
self.set( "searchOwnership",
|
||||
(id === data.id)
|
||||
? "You own the search."
|
||||
: "You do not own the search."
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
updateRequests: function( data, env ) {
|
||||
var reqs = this.get( "requests" );
|
||||
if( !_.any( reqs, function( req ){
|
||||
return req.correlationId === data.correlationId &&
|
||||
req.searchTerm === data.searchTerm
|
||||
})) {
|
||||
reqs.push( data );
|
||||
this.set( "requests", _.sortBy( reqs, function( item ) { return item.searchTerm; } ) );
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
36
example/node/client/js/models/profanity-percentage-model.js
Normal file
36
example/node/client/js/models/profanity-percentage-model.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
define( [
|
||||
'backbone',
|
||||
'bus'
|
||||
],
|
||||
function( Backbone, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.Model.extend({
|
||||
defaults: {
|
||||
percentage: "",
|
||||
clean: "",
|
||||
explicit: "",
|
||||
total: ""
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var self = this;
|
||||
this.subscriptions = [
|
||||
bus.stats.subscribe( "profanity-percentage", function( data, env ){
|
||||
self.set("percentage", data.percentage, { silent: true });
|
||||
self.set("clean", data.clean, { silent: true });
|
||||
self.set("explicit", data.explicit, { silent: true });
|
||||
self.set("total", data.clean + data.explicit, { silent: true });
|
||||
self.change();
|
||||
})
|
||||
];
|
||||
},
|
||||
|
||||
dispose: function(){
|
||||
_.each( this.subscriptions, function( subscription ){
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
this.clear( { silent: true } );
|
||||
}
|
||||
});
|
||||
});
|
||||
31
example/node/client/js/models/tweet-count-model.js
Normal file
31
example/node/client/js/models/tweet-count-model.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
define( [
|
||||
'backbone',
|
||||
'bus'
|
||||
],
|
||||
function( Backbone, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.Model.extend({
|
||||
defaults: {
|
||||
tweeters: []
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var self = this;
|
||||
this.subscriptions = [
|
||||
bus.stats.subscribe( "tweet-count", function( data, env ){
|
||||
if( data.tweeters && data.tweeters.length ) {
|
||||
self.set( "tweeters", _.sortBy( data.tweeters, function( item ) { return item.count * -1; } ) );
|
||||
}
|
||||
})
|
||||
];
|
||||
},
|
||||
|
||||
dispose: function(){
|
||||
_.each( this.subscriptions, function( subscription ){
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
this.clear( { silent: true } );
|
||||
}
|
||||
});
|
||||
});
|
||||
30
example/node/client/js/views/container.js
Normal file
30
example/node/client/js/views/container.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
define( [
|
||||
'jquery',
|
||||
'backbone',
|
||||
'text!views/templates/container.html'
|
||||
],
|
||||
function( $, Backbone, template ) {
|
||||
// Using ECMAScript 5 strict mode during development. By default r.js will ignore that.
|
||||
"use strict";
|
||||
|
||||
return Backbone.View.extend( {
|
||||
el: "body",
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll(this, "render");
|
||||
this.template = template;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html(this.template);
|
||||
},
|
||||
|
||||
show: function( data ) {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
update: function( data ) {
|
||||
|
||||
}
|
||||
} );
|
||||
} );
|
||||
41
example/node/client/js/views/hash-tag-count.js
Normal file
41
example/node/client/js/views/hash-tag-count.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
define( [
|
||||
'jquery',
|
||||
'backbone',
|
||||
'text!views/templates/hash-tag-count.html',
|
||||
'models/hash-tag-count-model',
|
||||
'bus'
|
||||
],
|
||||
function( $, Backbone, template, HashTagCountModel, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.View.extend( {
|
||||
tagName: "div",
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll( this );
|
||||
this.template = _.template( template );
|
||||
this.model = new HashTagCountModel();
|
||||
bus.app.subscribe( "search.info", this.setCurrentSearch );
|
||||
this.model.bind( "change", this.render );
|
||||
this.inDom = false;
|
||||
bus.stats.publish({ topic: "hash-tag-count.getLatest", data: {} });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// TODO: Capture scroll position and restore after render...
|
||||
this.$el.html( this.template( this.model.toJSON() ) );
|
||||
if( !this.inDom ) {
|
||||
this.$el.appendTo( "#stats" );
|
||||
this.inDom = true;
|
||||
}
|
||||
},
|
||||
|
||||
show: function( data ) {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
hide: function( data ) {
|
||||
this.$el.hide();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
41
example/node/client/js/views/mention-count.js
Normal file
41
example/node/client/js/views/mention-count.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
define( [
|
||||
'jquery',
|
||||
'backbone',
|
||||
'text!views/templates/mention-count.html',
|
||||
'models/mention-count-model',
|
||||
'bus'
|
||||
],
|
||||
function( $, Backbone, template, MentionCountModel, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.View.extend( {
|
||||
tagName: "div",
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll( this );
|
||||
this.template = _.template( template );
|
||||
this.model = new MentionCountModel();
|
||||
bus.app.subscribe( "search.info", this.setCurrentSearch );
|
||||
this.model.bind( "change", this.render );
|
||||
this.inDom = false;
|
||||
bus.stats.publish({ topic: "mention-count.getLatest", data: {} });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// TODO: Capture scroll position and restore after render...
|
||||
this.$el.html( this.template( this.model.toJSON() ) );
|
||||
if( !this.inDom ) {
|
||||
this.$el.appendTo( "#stats" );
|
||||
this.inDom = true;
|
||||
}
|
||||
},
|
||||
|
||||
show: function( data ) {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
hide: function( data ) {
|
||||
this.$el.hide();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
41
example/node/client/js/views/mentioner-count.js
Normal file
41
example/node/client/js/views/mentioner-count.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
define( [
|
||||
'jquery',
|
||||
'backbone',
|
||||
'text!views/templates/mentioner-count.html',
|
||||
'models/mentioner-count-model',
|
||||
'bus'
|
||||
],
|
||||
function( $, Backbone, template, MentionerCountModel, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.View.extend( {
|
||||
tagName: "div",
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll( this );
|
||||
this.template = _.template( template );
|
||||
this.model = new MentionerCountModel();
|
||||
bus.app.subscribe( "search.info", this.setCurrentSearch );
|
||||
this.model.bind( "change", this.render );
|
||||
this.inDom = false;
|
||||
bus.stats.publish({ topic: "mentioner-count.getLatest", data: {} });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// TODO: Capture scroll position and restore after render...
|
||||
this.$el.html( this.template( this.model.toJSON() ) );
|
||||
if( !this.inDom ) {
|
||||
this.$el.appendTo( "#stats" );
|
||||
this.inDom = true;
|
||||
}
|
||||
},
|
||||
|
||||
show: function( data ) {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
hide: function( data ) {
|
||||
this.$el.hide();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
52
example/node/client/js/views/menu.js
Normal file
52
example/node/client/js/views/menu.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
define( [
|
||||
'jquery',
|
||||
'backbone',
|
||||
'text!views/templates/menu.html',
|
||||
'bus',
|
||||
'models/menu-model'
|
||||
],
|
||||
function( $, Backbone, template, bus, MenuModel ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.View.extend( {
|
||||
el: "#menu",
|
||||
|
||||
events: {
|
||||
"click #btnSearch" : "updateSearch"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll( this );
|
||||
this.template = _.template( template );
|
||||
this.model = new MenuModel();
|
||||
this.model.bind( "change", this.updateView );
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html( this.template( this.model.toJSON() ) );
|
||||
},
|
||||
|
||||
show: function( data ) {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
updateSearch: function() {
|
||||
var searchTerm = this.$el.find('#searchTerm').val();
|
||||
if( searchTerm ) {
|
||||
bus.app.publish({
|
||||
topic: "search.new.request",
|
||||
data: {
|
||||
searchTerm: searchTerm
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updateView: function() {
|
||||
this.$el.find( "#currentSearch" ).text( this.model.get("searchTerm") );
|
||||
this.$el.find( "#search-ownership").text( this.model.get("searchOwnership" ));
|
||||
var reqs = this.model.get("requests").length
|
||||
this.$el.find( "#request-indicator").text( reqs ? " *" : "" );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
41
example/node/client/js/views/profanity-percentage.js
Normal file
41
example/node/client/js/views/profanity-percentage.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
define( [
|
||||
'jquery',
|
||||
'backbone',
|
||||
'text!views/templates/profanity-percentage.html',
|
||||
'models/profanity-percentage-model',
|
||||
'bus'
|
||||
],
|
||||
function( $, Backbone, template, ProfanityPercentageModel, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.View.extend( {
|
||||
tagName: "div",
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll( this );
|
||||
this.template = _.template( template );
|
||||
this.model = new ProfanityPercentageModel();
|
||||
bus.app.subscribe( "search.info", this.setCurrentSearch );
|
||||
this.model.bind( "change", this.render );
|
||||
this.inDom = false;
|
||||
bus.stats.publish({ topic: "profanity-percentage.getLatest", data: {} });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// TODO: Capture scroll position and restore after render...
|
||||
this.$el.html( this.template( this.model.toJSON() ) );
|
||||
if( !this.inDom ) {
|
||||
this.$el.appendTo( "#stats" );
|
||||
this.inDom = true;
|
||||
}
|
||||
},
|
||||
|
||||
show: function( data ) {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
hide: function( data ) {
|
||||
this.$el.hide();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
7
example/node/client/js/views/templates/container.html
Normal file
7
example/node/client/js/views/templates/container.html
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<div id="menu"></div>
|
||||
|
||||
<div id="info"></div>
|
||||
|
||||
<div id="stats"></div>
|
||||
|
||||
<div id="wiretap"></div>
|
||||
13
example/node/client/js/views/templates/hash-tag-count.html
Normal file
13
example/node/client/js/views/templates/hash-tag-count.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<fieldset>
|
||||
<legend><div class="title">Associated Hash Tags:</div></legend>
|
||||
<div class="scrollableDiv">
|
||||
<table class="hashTagTable" cellspacing="0">
|
||||
<% _.each( hashTags, function( item ) { %>
|
||||
<tr>
|
||||
<td><span><%= item.hashTag %></span></td>
|
||||
<td><span><%= item.count %></span></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
14
example/node/client/js/views/templates/mention-count.html
Normal file
14
example/node/client/js/views/templates/mention-count.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<fieldset>
|
||||
<legend><span>Top Mentioned:</span></legend>
|
||||
<div class="scrollableDiv">
|
||||
<table cellspacing="0">
|
||||
<% _.each( mentions, function( mention ) { %>
|
||||
<tr>
|
||||
<td><img class="images" src="<%= mention.image %>" /></td>
|
||||
<td><span><%= mention.user %></span></td>
|
||||
<td><span><%= mention.count %></span></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
14
example/node/client/js/views/templates/mentioner-count.html
Normal file
14
example/node/client/js/views/templates/mentioner-count.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<fieldset>
|
||||
<legend><span>Top Mention-ers:</span></legend>
|
||||
<div class="scrollableDiv">
|
||||
<table cellspacing="0">
|
||||
<% _.each( mentioners, function( mentioner ) { %>
|
||||
<tr>
|
||||
<td><img class="images" src="<%= mentioner.image %>" /></td>
|
||||
<td><span><%= mentioner.user %></span></td>
|
||||
<td><span><%= mentioner.count %></span></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
15
example/node/client/js/views/templates/menu.html
Normal file
15
example/node/client/js/views/templates/menu.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<div class="top-bar">
|
||||
<ul class="nav-menu">
|
||||
<li><a class="ps-nav" href="">Home</a></li>
|
||||
<li><a class="ps-nav" href="select">Requested Searches<span id="request-indicator"></span></a></li>
|
||||
<li><a class="ps-nav" href="wiretap">Show Wiretap</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="search">Searching Twitter for: <span id="currentSearch"><%= searchTerm %></span></div>
|
||||
<div class="search">
|
||||
<input type="text" id="searchTerm">
|
||||
<input id="btnSearch" type="button" value="Search">
|
||||
</div>
|
||||
<div class="search" id="search-ownership"><%= searchOwnership %></div>
|
||||
<div style="clear:both"></div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<fieldset>
|
||||
<legend><span>Profanity Rate:</span></legend>
|
||||
<div>
|
||||
<div>
|
||||
<span>Total:</span>
|
||||
<span><%= total %></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Explicit:</span>
|
||||
<span><%= explicit %></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Profanity Rate:</span>
|
||||
<span><%= percentage %>%</span>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
14
example/node/client/js/views/templates/tweet-count.html
Normal file
14
example/node/client/js/views/templates/tweet-count.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<fieldset>
|
||||
<legend><span>Top Tweeters:</span></legend>
|
||||
<div class="scrollableDiv">
|
||||
<table cellspacing="0">
|
||||
<% _.each( tweeters, function( tweeter ) { %>
|
||||
<tr>
|
||||
<td><img class="images" src="<%= tweeter.image %>" /></td>
|
||||
<td><span><%= tweeter.user %></span></td>
|
||||
<td><span><%= tweeter.count %></span></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</table>
|
||||
</div>
|
||||
</fieldset>
|
||||
41
example/node/client/js/views/tweet-count.js
Normal file
41
example/node/client/js/views/tweet-count.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
define( [
|
||||
'jquery',
|
||||
'backbone',
|
||||
'text!views/templates/tweet-count.html',
|
||||
'models/tweet-count-model',
|
||||
'bus'
|
||||
],
|
||||
function( $, Backbone, template, TweetCountModel, bus ) {
|
||||
"use strict";
|
||||
|
||||
return Backbone.View.extend( {
|
||||
tagName: "div",
|
||||
|
||||
initialize: function() {
|
||||
_.bindAll( this );
|
||||
this.template = _.template( template );
|
||||
this.model = new TweetCountModel();
|
||||
bus.app.subscribe( "search.info", this.setCurrentSearch );
|
||||
this.model.bind( "change", this.render );
|
||||
this.inDom = false;
|
||||
bus.stats.publish({ topic: "tweet-count.getLatest", data: {} });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// TODO: Capture scroll position and restore after render...
|
||||
this.$el.html( this.template( this.model.toJSON() ) );
|
||||
if( !this.inDom ) {
|
||||
this.$el.appendTo( "#stats" );
|
||||
this.inDom = true;
|
||||
}
|
||||
},
|
||||
|
||||
show: function( data ) {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
hide: function( data ) {
|
||||
this.$el.hide();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
63
example/node/collectors/hash-tag-count.js
Normal file
63
example/node/collectors/hash-tag-count.js
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
var _ = require('underscore'),
|
||||
_scanner = function(regExp, text, callback) {
|
||||
var match;
|
||||
while(text.search(regExp) !== -1) {
|
||||
match = regExp.exec(text);
|
||||
if(match && match[1]) {
|
||||
callback(match[1].toLowerCase());
|
||||
}
|
||||
text = text.replace(regExp, "");
|
||||
}
|
||||
},
|
||||
HashTagCount = function(namespace) {
|
||||
this.namespace = namespace;
|
||||
|
||||
this.events = {};
|
||||
|
||||
this.hashTags = { list: [], registry: {} };
|
||||
|
||||
this.lastStats = undefined;
|
||||
|
||||
};
|
||||
|
||||
HashTagCount.prototype = {
|
||||
init: function() {
|
||||
this.hashTags = { list: [], registry: {} };
|
||||
this.lastStats = undefined;
|
||||
},
|
||||
on: function( eventName, callback ) {
|
||||
if( !this.events[ eventName ] ) {
|
||||
this.events[ eventName ] = [];
|
||||
}
|
||||
this.events[ eventName ].push( callback );
|
||||
return function() {
|
||||
this.events[ eventName ] = _.without( this.events[ eventName ], callback );
|
||||
}.bind( this );
|
||||
},
|
||||
raiseEvent: function( eventName, data ) {
|
||||
if( this.events[ eventName ] ) {
|
||||
this.events[ eventName ].forEach( function( callback ){
|
||||
callback( data );
|
||||
});
|
||||
}
|
||||
},
|
||||
processNewTweets: function( tweets ) {
|
||||
tweets.forEach( function( tweet ){
|
||||
this.processOtherHashTags( tweet.text );
|
||||
}, this );
|
||||
this.lastStats = { type: "HashTagCount", hashTags: this.hashTags.list };
|
||||
this.raiseEvent( this.namespace, this.lastStats );
|
||||
},
|
||||
processOtherHashTags: function( text ) {
|
||||
_scanner( /#(\w*)/i, text, function( hash ){
|
||||
if( !this.hashTags.registry[ hash ] ) {
|
||||
var obj = { hashTag: hash, count: 0 };
|
||||
this.hashTags.registry[ hash ] = obj;
|
||||
this.hashTags.list.push( obj );
|
||||
}
|
||||
this.hashTags.registry[ hash ].count++;
|
||||
}.bind( this ));
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = HashTagCount;
|
||||
73
example/node/collectors/mention-count.js
Normal file
73
example/node/collectors/mention-count.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
var _ = require('underscore'),
|
||||
_scanner = function(regExp, text, callback) {
|
||||
var match;
|
||||
while(text.search(regExp) !== -1) {
|
||||
match = regExp.exec(text);
|
||||
if(match && match[1]) {
|
||||
callback(match[1].toLowerCase());
|
||||
}
|
||||
text = text.replace(regExp, "");
|
||||
}
|
||||
},
|
||||
MentionCount = function(namespace) {
|
||||
this.namespace = namespace;
|
||||
|
||||
this.events = {};
|
||||
|
||||
this.mentions = { list: [], registry: {} };
|
||||
|
||||
this.userImageMap = {};
|
||||
|
||||
this.lastStats = undefined;
|
||||
};
|
||||
|
||||
MentionCount.prototype = {
|
||||
init: function() {
|
||||
this.mentions = { list: [], registry: {} };
|
||||
this.lastStats = undefined;
|
||||
},
|
||||
on: function( eventName, callback ) {
|
||||
if( !this.events[ eventName ] ) {
|
||||
this.events[ eventName ] = [];
|
||||
}
|
||||
this.events[ eventName ].push( callback );
|
||||
return function() {
|
||||
this.events[ eventName ] = _.without( this.events[ eventName ], callback );
|
||||
}.bind( this );
|
||||
},
|
||||
raiseEvent: function( eventName, data ) {
|
||||
if( this.events[ eventName ] ) {
|
||||
this.events[ eventName ].forEach( function( callback ){
|
||||
callback( data );
|
||||
});
|
||||
}
|
||||
},
|
||||
processNewTweets: function(tweets) {
|
||||
tweets.forEach(function(tweet){
|
||||
this.userImageMap[ tweet.from_user ] = tweet.profile_image_url;
|
||||
this.processMentions(tweet);
|
||||
}, this);
|
||||
this.tryToMatchProfileImages();
|
||||
this.lastStats = { type: "MentionCount", mentions: this.mentions.list };
|
||||
this.raiseEvent( this.namespace, this.lastStats );
|
||||
},
|
||||
tryToMatchProfileImages: function() {
|
||||
_.each( this.mentions.registry, function( v, k ){
|
||||
if( this.userImageMap[ k ] ) {
|
||||
v.image = this.userImageMap[ k ];
|
||||
}
|
||||
}, this );
|
||||
},
|
||||
processMentions: function(tweet) {
|
||||
_scanner(/@(\w*)/i, tweet.text, function(mentioned) {
|
||||
if(!this.mentions.registry[mentioned]) {
|
||||
var obj = { user: mentioned, count: 0, image: "images/default_profile_1_normal.png" };
|
||||
this.mentions.registry[mentioned] = obj;
|
||||
this.mentions.list.push(obj);
|
||||
}
|
||||
this.mentions.registry[mentioned].count++;
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = MentionCount;
|
||||
62
example/node/collectors/mentioner-count.js
Normal file
62
example/node/collectors/mentioner-count.js
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
var _ = require('underscore'),
|
||||
_scanner = function(regExp, text, callback) {
|
||||
var match;
|
||||
while(text.search(regExp) !== -1) {
|
||||
match = regExp.exec(text);
|
||||
if(match && match[1]) {
|
||||
callback(match[1].toLowerCase());
|
||||
}
|
||||
text = text.replace(regExp, "");
|
||||
}
|
||||
},
|
||||
MentionerCount = function(namespace) {
|
||||
this.namespace = namespace;
|
||||
|
||||
this.events = {};
|
||||
|
||||
this.mentioners = { list: [], registry: {} };
|
||||
|
||||
this.lastStats = undefined;
|
||||
};
|
||||
|
||||
MentionerCount.prototype = {
|
||||
init: function() {
|
||||
this.mentioners = { list: [], registry: {} };
|
||||
this.lastStats = undefined;
|
||||
},
|
||||
on: function( eventName, callback ) {
|
||||
if( !this.events[ eventName ] ) {
|
||||
this.events[ eventName ] = [];
|
||||
}
|
||||
this.events[ eventName ].push( callback );
|
||||
return function() {
|
||||
this.events[ eventName ] = _.without( this.events[ eventName ], callback );
|
||||
}.bind( this );
|
||||
},
|
||||
raiseEvent: function( eventName, data ) {
|
||||
if( this.events[ eventName ] ) {
|
||||
this.events[ eventName ].forEach( function( callback ){
|
||||
callback( data );
|
||||
});
|
||||
}
|
||||
},
|
||||
processNewTweets: function(tweets) {
|
||||
tweets.forEach(function(tweet){
|
||||
this.processMentioners(tweet);
|
||||
}, this);
|
||||
this.lastStats = { type: "MentionerCount", mentioners: this.mentioners.list };
|
||||
this.raiseEvent( this.namespace, this.lastStats );
|
||||
},
|
||||
processMentioners: function(tweet) {
|
||||
_scanner(/@(\w*)/i, tweet.text, function(mentioned) {
|
||||
if(!this.mentioners.registry[tweet.from_user]) {
|
||||
var obj = { user: tweet.from_user, count: 0, image: tweet.profile_image_url };
|
||||
this.mentioners.registry[tweet.from_user] = obj;
|
||||
this.mentioners.list.push(obj);
|
||||
}
|
||||
this.mentioners.registry[tweet.from_user].count++;
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = MentionerCount;
|
||||
109
example/node/collectors/profanity-percentage.js
Normal file
109
example/node/collectors/profanity-percentage.js
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// quick hack array - not going to go regex crazy for now
|
||||
var _badWords = [
|
||||
/\bfuck\b/i,
|
||||
/\bfucks\b/i,
|
||||
/\bfucking\b/i,
|
||||
/\bfucked\b/i,
|
||||
/\bfucker\b/i,
|
||||
/\bfuckers\b/i,
|
||||
/\bass\b/i,
|
||||
/\basses\b/i,
|
||||
/\basshole\b/i,
|
||||
/\bassholes\b/i,
|
||||
/\bshit\b/i,
|
||||
/\bshitted\b/i,
|
||||
/\bshitter\b/i,
|
||||
/\bshitters\b/i,
|
||||
/\bshitting\b/i,
|
||||
/\bshithead\b/i,
|
||||
/\bcunt\b/i,
|
||||
/\bcunts\b/i,
|
||||
/\bpussy\b/i,
|
||||
/\bdick\b/i,
|
||||
/\bdicks\b/i,
|
||||
/\bdickhead\b/i,
|
||||
/\bdickheads\b/i,
|
||||
/\bdamn\b/i,
|
||||
/\bdamned\b/i,
|
||||
/\bdamning\b/i,
|
||||
/\bcock\b/i,
|
||||
/\bpenis\b/i,
|
||||
/\bfag\b/i,
|
||||
/\bbitch\b/i,
|
||||
/\bfaggot\b/,
|
||||
/\bpiss\b/,
|
||||
/\bpissing\b/
|
||||
],
|
||||
_ = require('underscore'),
|
||||
ProfanityPercentage = function(namespace) {
|
||||
this.namespace = namespace;
|
||||
|
||||
this.events = {};
|
||||
|
||||
this.profanityStats = { clean: 0, explicit: 0 };
|
||||
|
||||
this.lastStats = undefined;
|
||||
};
|
||||
|
||||
ProfanityPercentage.prototype = {
|
||||
init: function() {
|
||||
this.profanityStats = { clean: 0, explicit: 0 };
|
||||
this.lastStats = undefined;
|
||||
},
|
||||
on: function( eventName, callback ) {
|
||||
if( !this.events[ eventName ] ) {
|
||||
this.events[ eventName ] = [];
|
||||
}
|
||||
this.events[ eventName ].push( callback );
|
||||
return function() {
|
||||
this.events[ eventName ] = _.without( this.events[ eventName ], callback );
|
||||
}.bind( this );
|
||||
},
|
||||
raiseEvent: function( eventName, data ) {
|
||||
if( this.events[ eventName ] ) {
|
||||
this.events[ eventName ].forEach( function( callback ){
|
||||
callback( data );
|
||||
});
|
||||
}
|
||||
},
|
||||
hasProfanity: function(text) {
|
||||
for(var i = 0; i < _badWords.length; i++) {
|
||||
if(text.search(_badWords[i]) !== -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getPercentage: function() {
|
||||
var total = (this.profanityStats.clean + this.profanityStats.explicit);
|
||||
if(total === 0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return ((this.profanityStats.explicit / total) * 100).toFixed(2);
|
||||
}
|
||||
},
|
||||
processNewTweets: function(tweets) {
|
||||
tweets.forEach(function(tweet){
|
||||
this.profanitize(tweet);
|
||||
}, this);
|
||||
this.lastStats = {
|
||||
type: "ProfanityPercentage",
|
||||
percentage: this.getPercentage(),
|
||||
clean: this.profanityStats.clean,
|
||||
explicit: this.profanityStats.explicit
|
||||
};
|
||||
this.raiseEvent( this.namespace, this.lastStats );
|
||||
},
|
||||
profanitize: function(tweet) {
|
||||
if(this.hasProfanity(tweet.text)) {
|
||||
this.profanityStats.explicit++;
|
||||
}
|
||||
else {
|
||||
this.profanityStats.clean++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ProfanityPercentage;
|
||||
52
example/node/collectors/tweet-count.js
Normal file
52
example/node/collectors/tweet-count.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
var _ = require('underscore'),
|
||||
TweetCount = function(namespace) {
|
||||
this.namespace = namespace;
|
||||
|
||||
this.events = {};
|
||||
|
||||
this.tweeters = { list: [], registry: {} };
|
||||
|
||||
this.lastStats = undefined;
|
||||
};
|
||||
|
||||
TweetCount.prototype = {
|
||||
init: function() {
|
||||
this.tweeters = { list: [], registry: {} };
|
||||
this.lastStats = undefined;
|
||||
},
|
||||
on: function( eventName, callback ) {
|
||||
if( !this.events[ eventName ] ) {
|
||||
this.events[ eventName ] = [];
|
||||
}
|
||||
this.events[ eventName ].push( callback );
|
||||
return function() {
|
||||
this.events[ eventName ] = _.without( this.events[ eventName ], callback );
|
||||
}.bind( this );
|
||||
},
|
||||
raiseEvent: function( eventName, data ) {
|
||||
if( this.events[ eventName ] ) {
|
||||
this.events[ eventName ].forEach( function( callback ){
|
||||
callback.call( this, data );
|
||||
});
|
||||
}
|
||||
},
|
||||
processNewTweets: function(tweets) {
|
||||
tweets.forEach(function(tweet){
|
||||
this.processTweetCount(tweet);
|
||||
}, this);
|
||||
this.lastStats = { type: "TweetCount", tweeters: this.tweeters.list };
|
||||
this.raiseEvent( this.namespace, this.lastStats );
|
||||
},
|
||||
processTweetCount : function(tweet) {
|
||||
if(tweet.from_user) {
|
||||
if(!this.tweeters.registry[tweet.from_user]) {
|
||||
var obj = {user: tweet.from_user, count: 0, image: tweet.profile_image_url};
|
||||
this.tweeters.registry[tweet.from_user] = obj;
|
||||
this.tweeters.list.push(obj);
|
||||
}
|
||||
this.tweeters.registry[tweet.from_user].count++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = TweetCount;
|
||||
156
example/node/index.js
Normal file
156
example/node/index.js
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
var _ = require("underscore"),
|
||||
express = require( 'express' ),
|
||||
app = express.createServer(),
|
||||
postal = require( "./messaging/postal.js" ),
|
||||
PostalSocketHost = require( './messaging/postal.socket-host.js' ),
|
||||
sockets = require( './messaging/socket-io-provider.js' ),
|
||||
TwitterSearch = require( './twitter-search.js' ),
|
||||
collectors = require( './stat-collectors.js' ),
|
||||
BusAdapter = require( './messaging/bus-adapter.js' ),
|
||||
machina = require( './machina.js' );
|
||||
|
||||
postal.addWireTap( function( data, envelope ){
|
||||
if( envelope.channel === "stats" /*|| envelope.channel === "twittersearch"*/ ) {
|
||||
var env = _.extend( {}, envelope );
|
||||
delete env.data;
|
||||
console.log( JSON.stringify( env ) );
|
||||
}
|
||||
else if (_.include(["postal.socket", "postal", "app", "app.events"], envelope.channel) ) {
|
||||
console.log( JSON.stringify( envelope ) );
|
||||
}
|
||||
});
|
||||
|
||||
// wire machina FSMs into postal automagically
|
||||
require( './messaging/machina.postal.js' )( postal, machina );
|
||||
|
||||
var TwitterSocketStats = function( port, refreshinterval ) {
|
||||
// Stand up our express app
|
||||
app.use( "/", express.static( __dirname + '/client' ) );
|
||||
app.listen( port );
|
||||
var searchChannel = postal.channel( "twittersearch", "*" ),
|
||||
statsChannel = postal.channel( "stats", "*" ),
|
||||
appChannel = postal.channel( "statsApp", "*" );
|
||||
|
||||
postal.linkChannels( { channel: "postal.socket", topic: "client.migrated"}, { channel: "statsApp", topic: "client.migrated" } );
|
||||
|
||||
return new machina.Fsm({
|
||||
|
||||
namespace: "statsApp",
|
||||
|
||||
currentSearch: {
|
||||
id: null,
|
||||
searchTerm: "{ Search Not Active }"
|
||||
},
|
||||
|
||||
searchRequests: {},
|
||||
|
||||
express: app,
|
||||
|
||||
appChannel: appChannel,
|
||||
|
||||
searchChannel: searchChannel,
|
||||
|
||||
statsChannel: statsChannel,
|
||||
|
||||
searchAgent: new BusAdapter(new TwitterSearch( refreshinterval), searchChannel, searchChannel ),
|
||||
|
||||
stats: collectors.load( searchChannel, statsChannel ),
|
||||
|
||||
postal: postal,
|
||||
|
||||
bridge: new PostalSocketHost( postal, sockets.getSocketProvider( postal, app ) ),
|
||||
|
||||
getAvailableStats: function( clientId ) {
|
||||
this.appChannel.publish({
|
||||
topic: "available.topics",
|
||||
correlationId: clientId,
|
||||
data: {
|
||||
topics:_.toArray(this.stats).map(function(stat) { return { channel: "stats", topic: stat.namespace }; })
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setSearch: function( correlationId, searchTerm ) {
|
||||
this.currentSearch = {
|
||||
id: correlationId,
|
||||
searchTerm: searchTerm
|
||||
};
|
||||
this.searchAgent.search(searchTerm);
|
||||
this.appChannel.publish({
|
||||
topic: "search.info",
|
||||
data: this.currentSearch
|
||||
});
|
||||
},
|
||||
|
||||
getSearchInfo: function( env ) {
|
||||
this.appChannel.publish({
|
||||
topic: "search.info",
|
||||
correlationId: env.correlationId,
|
||||
data: this.currentSearch
|
||||
});
|
||||
},
|
||||
|
||||
states: {
|
||||
uninitialized: {
|
||||
start: function() {
|
||||
this.transition("notSearching");
|
||||
},
|
||||
"*" : function() {
|
||||
this.deferUntilTransition();
|
||||
}
|
||||
},
|
||||
notSearching: {
|
||||
"search.new.request" : function( data, envelope ) {
|
||||
this.setSearch( envelope.correlationId, data.searchTerm );
|
||||
this.transition("searching");
|
||||
},
|
||||
"get.search.info": function( data, env ) {
|
||||
this.getSearchInfo( env );
|
||||
},
|
||||
"get.available" : function( data, envelope ) {
|
||||
this.getAvailableStats( envelope.correlationId );
|
||||
}
|
||||
},
|
||||
searching: {
|
||||
"search.new.request" : function( data, envelope ) {
|
||||
if(envelope.correlationId === this.currentSearch.id) {
|
||||
this.setSearch( envelope.correlationId, data.searchTerm );
|
||||
}
|
||||
else {
|
||||
this.appChannel.publish({
|
||||
topic: "search.new.ask",
|
||||
data: {
|
||||
correlationId: this.currentSearch.id,
|
||||
searchTerm: data.searchTerm
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
"search.new.confirm" : function( data, envelope ) {
|
||||
if( envelope.correlationId === this.currentSearch.id ) {
|
||||
this.setSearch( data.correlationId, data.searchTerm );
|
||||
}
|
||||
},
|
||||
"get.search.info": function( data, env ) {
|
||||
this.getSearchInfo( env );
|
||||
},
|
||||
"get.available" : function( data, envelope ) {
|
||||
this.getAvailableStats( envelope.correlationId );
|
||||
},
|
||||
"client.migrated" : function( data, envelope ) {
|
||||
if( data.lastSessionId === this.currentSearch.id ) {
|
||||
this.currentSearch.id = data.sessionId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var x = module.exports = new TwitterSocketStats( 8002, 7000 );
|
||||
|
||||
x.on("*", function(evnt, data){
|
||||
console.log("FSM Event: " + evnt + " - " + JSON.stringify([].slice.call(arguments,1)));
|
||||
});
|
||||
|
||||
x.handle("start");
|
||||
199
example/node/machina.js
Normal file
199
example/node/machina.js
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
var _ = require('underscore');
|
||||
/*
|
||||
machina.js
|
||||
Author: Jim Cowart
|
||||
License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license)
|
||||
Version 0.1.0
|
||||
*/
|
||||
|
||||
var slice = [].slice,
|
||||
NEXT_TRANSITION = "transition",
|
||||
NEXT_HANDLER = "handler",
|
||||
transformEventListToObject = function(eventList){
|
||||
var obj = {};
|
||||
_.each(eventList, function(evntName) {
|
||||
obj[evntName] = [];
|
||||
});
|
||||
return obj;
|
||||
},
|
||||
parseEventListeners = function(evnts) {
|
||||
var obj = evnts;
|
||||
if(_.isArray(evnts)) {
|
||||
obj = transformEventListToObject(evnts);
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
utils = {
|
||||
makeFsmNamespace: (function(){
|
||||
var machinaCount = 0;
|
||||
return function() {
|
||||
return "fsm." + machinaCount++;
|
||||
};
|
||||
})(),
|
||||
getDefaultOptions: function() {
|
||||
return {
|
||||
initialState: "uninitialized",
|
||||
eventListeners: {
|
||||
"*" : []
|
||||
},
|
||||
states: {},
|
||||
eventQueue: [],
|
||||
namespace: utils.makeFsmNamespace()
|
||||
};
|
||||
}
|
||||
},
|
||||
Fsm = function(options) {
|
||||
var opt, initialState, defaults = utils.getDefaultOptions();
|
||||
if(options) {
|
||||
if(options.eventListeners) {
|
||||
options.eventListeners = parseEventListeners(options.eventListeners);
|
||||
}
|
||||
if(options.messaging) {
|
||||
options.messaging = _.extend({}, defaults.messaging, options.messaging);
|
||||
}
|
||||
}
|
||||
opt = _.extend(defaults , options || {});
|
||||
initialState = opt.initialState;
|
||||
delete opt.initialState;
|
||||
_.extend(this,opt);
|
||||
|
||||
this.state = undefined;
|
||||
this._priorAction = "";
|
||||
this._currentAction = "";
|
||||
if(initialState) {
|
||||
this.transition(initialState);
|
||||
}
|
||||
machina.fireEvent("newFsm", this);
|
||||
};
|
||||
|
||||
Fsm.prototype.fireEvent = function(eventName) {
|
||||
var args = arguments;
|
||||
_.each(this.eventListeners["*"], function(callback) {
|
||||
try {
|
||||
callback.apply(this,slice.call(args, 0));
|
||||
} catch(exception) {
|
||||
if(console && typeof console.log !== "undefined") {
|
||||
console.log(exception.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
if(this.eventListeners[eventName]) {
|
||||
_.each(this.eventListeners[eventName], function(callback) {
|
||||
try {
|
||||
callback.apply(this,slice.call(args, 1));
|
||||
} catch(exception) {
|
||||
if(console && typeof console.log !== "undefined") {
|
||||
console.log(exception.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Fsm.prototype.handle = function(msgType) {
|
||||
// vars to avoid a "this." fest
|
||||
var states = this.states, current = this.state, args = slice.call(arguments,0), handlerName;
|
||||
this.currentActionArgs = args;
|
||||
if(states[current] && (states[current][msgType] || states[current]["*"])) {
|
||||
handlerName = states[current][msgType] ? msgType : "*";
|
||||
this._currentAction = current + "." + handlerName;
|
||||
this.fireEvent.apply(this, ["Handling"].concat(args));
|
||||
states[current][handlerName].apply(this, args.slice(1));
|
||||
this.fireEvent.apply(this, ["Handled"].concat(args));
|
||||
this._priorAction = this._currentAction;
|
||||
this._currentAction = "";
|
||||
this.processQueue(NEXT_HANDLER);
|
||||
}
|
||||
else {
|
||||
this.fireEvent.apply(this, ["NoHandler"].concat(args));
|
||||
}
|
||||
this.currentActionArgs = undefined;
|
||||
};
|
||||
|
||||
Fsm.prototype.transition = function(newState) {
|
||||
if(this.states[newState]){
|
||||
var oldState = this.state;
|
||||
this.state = newState;
|
||||
if(this.states[newState]._onEnter) {
|
||||
this.states[newState]._onEnter.call( this );
|
||||
}
|
||||
this.fireEvent.apply(this, ["Transitioned", oldState, this.state ]);
|
||||
this.processQueue(NEXT_TRANSITION);
|
||||
return;
|
||||
}
|
||||
this.fireEvent.apply(this, ["InvalidState", this.state, newState ]);
|
||||
};
|
||||
|
||||
Fsm.prototype.processQueue = function(type) {
|
||||
var filterFn = type === NEXT_TRANSITION ?
|
||||
function(item){
|
||||
return item.type === NEXT_TRANSITION && ((!item.untilState) || (item.untilState === this.state));
|
||||
} :
|
||||
function(item) {
|
||||
return item.type === NEXT_HANDLER;
|
||||
},
|
||||
toProcess = _.filter(this.eventQueue, filterFn, this);
|
||||
this.eventQueue = _.difference(this.eventQueue, toProcess);
|
||||
_.each(toProcess, function(item, index){
|
||||
this.handle.apply(this, item.args);
|
||||
}, this);
|
||||
};
|
||||
|
||||
Fsm.prototype.deferUntilTransition = function(stateName) {
|
||||
if(this.currentActionArgs) {
|
||||
var queued = { type: NEXT_TRANSITION, untilState: stateName, args: this.currentActionArgs };
|
||||
this.eventQueue.push(queued);
|
||||
this.fireEvent.apply(this, [ "Deferred", this.state, queued ]);
|
||||
}
|
||||
};
|
||||
|
||||
Fsm.prototype.deferUntilNextHandler = function() {
|
||||
if(this.currentActionArgs) {
|
||||
var queued = { type: NEXT_TRANSITION, args: this.currentActionArgs };
|
||||
this.eventQueue.push(queued);
|
||||
this.fireEvent.apply(this, [ "Deferred", this.state, queued ]);
|
||||
}
|
||||
};
|
||||
|
||||
Fsm.prototype.on = function(eventName, callback) {
|
||||
if(!this.eventListeners[eventName]) {
|
||||
this.eventListeners[eventName] = [];
|
||||
}
|
||||
this.eventListeners[eventName].push(callback);
|
||||
};
|
||||
|
||||
Fsm.prototype.off = function(eventName, callback) {
|
||||
if(this.eventListeners[eventName]){
|
||||
this.eventListeners[eventName] = _.without(this.eventListeners[eventName], callback);
|
||||
}
|
||||
};
|
||||
|
||||
var machina = {
|
||||
Fsm: Fsm,
|
||||
bus: undefined,
|
||||
utils: utils,
|
||||
on: function(eventName, callback) {
|
||||
if(!this.eventListeners[eventName]) {
|
||||
this.eventListeners[eventName] = [];
|
||||
}
|
||||
this.eventListeners[eventName].push(callback);
|
||||
},
|
||||
off: function(eventName, callback) {
|
||||
if(this.eventListeners[eventName]){
|
||||
this.eventListeners[eventName] = _.without(this.eventListeners[eventName], callback);
|
||||
}
|
||||
},
|
||||
fireEvent: function(eventName) {
|
||||
var i = 0, len, args = arguments, listeners = this.eventListeners[eventName];
|
||||
if(listeners && listeners.length) {
|
||||
_.each(listeners, function(callback) {
|
||||
callback.apply(null,slice.call(args, 1));
|
||||
});
|
||||
}
|
||||
},
|
||||
eventListeners: {
|
||||
newFsm : []
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = machina;
|
||||
17
example/node/messaging/bus-adapter.js
Normal file
17
example/node/messaging/bus-adapter.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
module.exports = function( target, searchChannel, statsChannel ) {
|
||||
target.bus = {
|
||||
subscriptions: [],
|
||||
publishers: [
|
||||
target.on( "newTweets", function( data ) {
|
||||
statsChannel.publish( { topic: "newTweets", data: data } );
|
||||
} ),
|
||||
target.on( "search.current", function( data ) {
|
||||
searchChannel.publish( { topic: "search.current", data: data } );
|
||||
} ),
|
||||
target.on( "search.nodata", function( data ) {
|
||||
searchChannel.publish( { topic: "search.nodata", data: data } );
|
||||
} )
|
||||
]
|
||||
};
|
||||
return target;
|
||||
};
|
||||
22
example/node/messaging/collector-adapter.js
Normal file
22
example/node/messaging/collector-adapter.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
module.exports = function( target, searchChannel, statChannel ) {
|
||||
target.bus = {
|
||||
subscriptions: [
|
||||
searchChannel.subscribe( "init", target.init ).withContext( target ),
|
||||
searchChannel.subscribe( "newTweets", target.processNewTweets ).withContext( target ),
|
||||
statChannel.subscribe( target.namespace + ".getLatest", function( data, env ){
|
||||
console.log("GET LATEST FOR: " + target.namespace);
|
||||
statChannel.publish( {
|
||||
topic: target.namespace,
|
||||
data: target.lastStats,
|
||||
correlationId: env.correlationId
|
||||
})
|
||||
}).withContext( target )
|
||||
],
|
||||
publishers: [
|
||||
target.on( target.namespace, function( data ) {
|
||||
statChannel.publish( { topic: target.namespace, data: data } );
|
||||
} )
|
||||
]
|
||||
};
|
||||
return target;
|
||||
};
|
||||
45
example/node/messaging/machina.postal.js
Normal file
45
example/node/messaging/machina.postal.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
machina.postal.js
|
||||
Author: Jim Cowart
|
||||
License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license)
|
||||
Version 0.1.0
|
||||
*/
|
||||
|
||||
module.exports = function(postal, machina) {
|
||||
var bus = machina.bus = {
|
||||
channels: {},
|
||||
config: {
|
||||
handlerChannelSuffix: "",
|
||||
eventChannelSuffix: ".events"
|
||||
},
|
||||
wireHandlersToBus: function(fsm, handlerChannel) {
|
||||
bus.channels[handlerChannel]._subscriptions.push(
|
||||
bus.channels[handlerChannel].subscribe("*", function(data, envelope){
|
||||
fsm.handle.call(fsm, envelope.topic, data, envelope);
|
||||
})
|
||||
);
|
||||
},
|
||||
wireEventsToBus: function(fsm, eventChannel) {
|
||||
var publisher = bus.channels[eventChannel].eventPublisher = function(){
|
||||
try {
|
||||
bus.channels[eventChannel].publish({ topic: arguments[0], data: arguments[1] || {} });
|
||||
} catch(exception) {
|
||||
if(console && typeof console.log !== "undefined") {
|
||||
console.log(exception.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
fsm.on("*", publisher);
|
||||
},
|
||||
wireUp: function(fsm) {
|
||||
var handlerChannel = fsm.namespace + bus.config.handlerChannelSuffix,
|
||||
eventChannel = fsm.namespace + bus.config.eventChannelSuffix;
|
||||
bus.channels[handlerChannel] = postal.channel({ channel: handlerChannel });
|
||||
bus.channels[eventChannel] = postal.channel({ channel: eventChannel });
|
||||
bus.channels[handlerChannel]._subscriptions = [];
|
||||
bus.wireHandlersToBus(fsm, handlerChannel);
|
||||
bus.wireEventsToBus(fsm, eventChannel);
|
||||
}
|
||||
};
|
||||
machina.on("newFsm", bus.wireUp);
|
||||
};
|
||||
25
example/node/messaging/postal.diagnostics.js
Normal file
25
example/node/messaging/postal.diagnostics.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
var _ = require('underscore');
|
||||
|
||||
module.exports = function(postal) {
|
||||
|
||||
// this returns a callback that, if invoked, removes the wireTap
|
||||
postal.diagnostics = postal.addWireTap(function(data, envelope) {
|
||||
var all = _.extend(envelope, { data: data });
|
||||
if(!JSON) {
|
||||
throw "This browser or environment does not provide JSON support";
|
||||
}
|
||||
try {
|
||||
console.log(JSON.stringify(all));
|
||||
}
|
||||
catch(exception) {
|
||||
try {
|
||||
all.data = "ERROR: " + exception.message;
|
||||
console.log(JSON.stringify(all));
|
||||
}
|
||||
catch(ex) {
|
||||
console.log("Unable to parse data to JSON: " + exception);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
440
example/node/messaging/postal.js
Normal file
440
example/node/messaging/postal.js
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
postal.js
|
||||
Author: Jim Cowart
|
||||
License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license)
|
||||
Version 0.6.0
|
||||
*/
|
||||
|
||||
// This is the node.js version of postal.js
|
||||
// If you need the standard or amd client lib version, go to http://github.com/ifandelse/postal.js
|
||||
var _ = require('underscore');
|
||||
|
||||
var DEFAULT_CHANNEL = "/",
|
||||
DEFAULT_PRIORITY = 50,
|
||||
DEFAULT_DISPOSEAFTER = 0,
|
||||
SYSTEM_CHANNEL = "postal",
|
||||
NO_OP = function() { };
|
||||
|
||||
var DistinctPredicate = function() {
|
||||
var previous;
|
||||
return function(data) {
|
||||
var eq = false;
|
||||
if(_.isString(data)) {
|
||||
eq = data === previous;
|
||||
previous = data;
|
||||
}
|
||||
else {
|
||||
eq = _.isEqual(data, previous);
|
||||
previous = _.clone(data);
|
||||
}
|
||||
return !eq;
|
||||
};
|
||||
};
|
||||
|
||||
var ChannelDefinition = function(channelName, defaultTopic) {
|
||||
this.channel = channelName || DEFAULT_CHANNEL;
|
||||
this._topic = defaultTopic || "";
|
||||
};
|
||||
|
||||
ChannelDefinition.prototype = {
|
||||
subscribe: function() {
|
||||
var len = arguments.length;
|
||||
if(len === 1) {
|
||||
return new SubscriptionDefinition(this.channel, this._topic, arguments[0]);
|
||||
}
|
||||
else if (len === 2) {
|
||||
return new SubscriptionDefinition(this.channel, arguments[0], arguments[1]);
|
||||
}
|
||||
},
|
||||
|
||||
publish: function(obj) {
|
||||
var envelope = {
|
||||
channel: this.channel,
|
||||
topic: this._topic,
|
||||
data: obj || {}
|
||||
};
|
||||
// If this is an envelope....
|
||||
if( obj.topic && obj.data ) {
|
||||
envelope = obj;
|
||||
envelope.channel = envelope.channel || this.channel;
|
||||
}
|
||||
envelope.timeStamp = new Date();
|
||||
postal.configuration.bus.publish(envelope);
|
||||
return envelope;
|
||||
},
|
||||
|
||||
topic: function(topic) {
|
||||
if(topic === this._topic) {
|
||||
return this;
|
||||
}
|
||||
return new ChannelDefinition(this.channel, topic);
|
||||
}
|
||||
};
|
||||
|
||||
var SubscriptionDefinition = function(channel, topic, callback) {
|
||||
this.channel = channel;
|
||||
this.topic = topic;
|
||||
this.callback = callback;
|
||||
this.priority = DEFAULT_PRIORITY;
|
||||
this.constraints = new Array(0);
|
||||
this.maxCalls = DEFAULT_DISPOSEAFTER;
|
||||
this.onHandled = NO_OP;
|
||||
this.context = null;
|
||||
postal.configuration.bus.publish({
|
||||
channel: SYSTEM_CHANNEL,
|
||||
topic: "subscription.created",
|
||||
timeStamp: new Date(),
|
||||
data: {
|
||||
event: "subscription.created",
|
||||
channel: channel,
|
||||
topic: topic
|
||||
}
|
||||
});
|
||||
|
||||
postal.configuration.bus.subscribe(this);
|
||||
|
||||
};
|
||||
|
||||
SubscriptionDefinition.prototype = {
|
||||
unsubscribe: function() {
|
||||
postal.configuration.bus.unsubscribe(this);
|
||||
postal.configuration.bus.publish({
|
||||
channel: SYSTEM_CHANNEL,
|
||||
topic: "subscription.removed",
|
||||
timeStamp: new Date(),
|
||||
data: {
|
||||
event: "subscription.removed",
|
||||
channel: this.channel,
|
||||
topic: this.topic
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
defer: function() {
|
||||
var fn = this.callback;
|
||||
this.callback = function(data) {
|
||||
setTimeout(fn,0,data);
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
disposeAfter: function(maxCalls) {
|
||||
if(_.isNaN(maxCalls) || maxCalls <= 0) {
|
||||
throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero.";
|
||||
}
|
||||
|
||||
var fn = this.onHandled;
|
||||
var dispose = _.after(maxCalls, _.bind(function() {
|
||||
this.unsubscribe(this);
|
||||
}, this));
|
||||
|
||||
this.onHandled = function() {
|
||||
fn.apply(this.context, arguments);
|
||||
dispose();
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
ignoreDuplicates: function() {
|
||||
this.withConstraint(new DistinctPredicate());
|
||||
return this;
|
||||
},
|
||||
|
||||
withConstraint: function(predicate) {
|
||||
if(! _.isFunction(predicate)) {
|
||||
throw "Predicate constraint must be a function";
|
||||
}
|
||||
this.constraints.push(predicate);
|
||||
return this;
|
||||
},
|
||||
|
||||
withConstraints: function(predicates) {
|
||||
var self = this;
|
||||
if(_.isArray(predicates)) {
|
||||
_.each(predicates, function(predicate) { self.withConstraint(predicate); } );
|
||||
}
|
||||
return self;
|
||||
},
|
||||
|
||||
withContext: function(context) {
|
||||
this.context = context;
|
||||
return this;
|
||||
},
|
||||
|
||||
withDebounce: function(milliseconds) {
|
||||
if(_.isNaN(milliseconds)) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = _.debounce(fn, milliseconds);
|
||||
return this;
|
||||
},
|
||||
|
||||
withDelay: function(milliseconds) {
|
||||
if(_.isNaN(milliseconds)) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = function(data) {
|
||||
setTimeout(function(){
|
||||
fn(data);
|
||||
}, milliseconds);
|
||||
};
|
||||
return this;
|
||||
},
|
||||
|
||||
withPriority: function(priority) {
|
||||
if(_.isNaN(priority)) {
|
||||
throw "Priority must be a number";
|
||||
}
|
||||
this.priority = priority;
|
||||
return this;
|
||||
},
|
||||
|
||||
withThrottle: function(milliseconds) {
|
||||
if(_.isNaN(milliseconds)) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = _.throttle(fn, milliseconds);
|
||||
return this;
|
||||
},
|
||||
|
||||
subscribe: function(callback) {
|
||||
this.callback = callback;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
var bindingsResolver = {
|
||||
cache: { },
|
||||
|
||||
compare: function(binding, topic) {
|
||||
if(this.cache[topic] && this.cache[topic][binding]) {
|
||||
return true;
|
||||
}
|
||||
// binding.replace(/\./g,"\\.") // escape actual periods
|
||||
// .replace(/\*/g, ".*") // asterisks match any value
|
||||
// .replace(/#/g, "[A-Z,a-z,0-9]*"); // hash matches any alpha-numeric 'word'
|
||||
var rgx = new RegExp("^" + binding.replace(/\./g,"\\.").replace(/\*/g, ".*").replace(/#/g, "[A-Z,a-z,0-9]*") + "$"),
|
||||
result = rgx.test(topic);
|
||||
if(result) {
|
||||
if(!this.cache[topic]) {
|
||||
this.cache[topic] = {};
|
||||
}
|
||||
this.cache[topic][binding] = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
var localBus = {
|
||||
|
||||
subscriptions: {},
|
||||
|
||||
wireTaps: new Array(0),
|
||||
|
||||
publish: function(envelope) {
|
||||
_.each(this.wireTaps,function(tap) {
|
||||
tap(envelope.data, envelope);
|
||||
});
|
||||
|
||||
_.each(this.subscriptions[envelope.channel], function(topic) {
|
||||
_.each(topic, function(subDef){
|
||||
if(postal.configuration.resolver.compare(subDef.topic, envelope.topic)) {
|
||||
if(_.all(subDef.constraints, function(constraint) { return constraint(envelope.data,envelope); })) {
|
||||
if(typeof subDef.callback === 'function') {
|
||||
subDef.callback.apply(subDef.context, [envelope.data, envelope]);
|
||||
subDef.onHandled();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
subscribe: function(subDef) {
|
||||
var idx, found, fn, channel = this.subscriptions[subDef.channel], subs;
|
||||
|
||||
if(!channel) {
|
||||
channel = this.subscriptions[subDef.channel] = {};
|
||||
}
|
||||
subs = this.subscriptions[subDef.channel][subDef.topic];
|
||||
if(!subs) {
|
||||
subs = this.subscriptions[subDef.channel][subDef.topic] = new Array(0);
|
||||
}
|
||||
|
||||
idx = subs.length - 1;
|
||||
for(; idx >= 0; idx--) {
|
||||
if(subs[idx].priority <= subDef.priority) {
|
||||
subs.splice(idx + 1, 0, subDef);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
subs.unshift(subDef);
|
||||
}
|
||||
return subDef;
|
||||
},
|
||||
|
||||
unsubscribe: function(config) {
|
||||
if(this.subscriptions[config.channel][config.topic]) {
|
||||
var len = this.subscriptions[config.channel][config.topic].length,
|
||||
idx = 0;
|
||||
for ( ; idx < len; idx++ ) {
|
||||
if (this.subscriptions[config.channel][config.topic][idx] === config) {
|
||||
this.subscriptions[config.channel][config.topic].splice( idx, 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
addWireTap: function(callback) {
|
||||
var self = this;
|
||||
self.wireTaps.push(callback);
|
||||
return function() {
|
||||
var idx = self.wireTaps.indexOf(callback);
|
||||
if(idx !== -1) {
|
||||
self.wireTaps.splice(idx,1);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var publishPicker = {
|
||||
"1" : function(envelope) {
|
||||
if(!envelope) {
|
||||
throw new Error("publishing from the 'global' postal.publish call requires a valid envelope.");
|
||||
}
|
||||
envelope.channel = envelope.channel || DEFAULT_CHANNEL;
|
||||
envelope.timeStamp = new Date();
|
||||
postal.configuration.bus.publish(envelope);
|
||||
return envelope;
|
||||
},
|
||||
"2" : function(topic, data) {
|
||||
var envelope = { channel: DEFAULT_CHANNEL, topic: topic, timeStamp: new Date(), data: data };
|
||||
postal.configuration.bus.publish( envelope );
|
||||
return envelope;
|
||||
},
|
||||
"3" : function(channel, topic, data) {
|
||||
var envelope = { channel: channel, topic: topic, timeStamp: new Date(), data: data };
|
||||
postal.configuration.bus.publish( envelope );
|
||||
return envelope;
|
||||
}
|
||||
},
|
||||
channelPicker = {
|
||||
"1" : function( chn ) {
|
||||
var channel = chn, topic, options = {};
|
||||
if( Object.prototype.toString.call( channel ) === "[object String]" ) {
|
||||
channel = DEFAULT_CHANNEL;
|
||||
topic = chn;
|
||||
}
|
||||
else {
|
||||
channel = chn.channel || DEFAULT_CHANNEL;
|
||||
topic = chn.topic;
|
||||
options = chn.options || options;
|
||||
}
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
},
|
||||
"2" : function( chn, tpc ) {
|
||||
var channel = chn, topic = tpc, options = {};
|
||||
if( Object.prototype.toString.call( tpc ) === "[object Object]" ) {
|
||||
channel = DEFAULT_CHANNEL;
|
||||
topic = chn;
|
||||
options = tpc;
|
||||
}
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
},
|
||||
"3" : function( channel, topic, options ) {
|
||||
return new postal.channelTypes[ options.type || "LocalChannel" ]( channel, topic );
|
||||
}
|
||||
};
|
||||
|
||||
// save some setup time, albeit tiny
|
||||
localBus.subscriptions[SYSTEM_CHANNEL] = {};
|
||||
|
||||
var postal = {
|
||||
configuration: {
|
||||
bus: localBus,
|
||||
resolver: bindingsResolver,
|
||||
DEFAULT_CHANNEL: DEFAULT_CHANNEL,
|
||||
DEFAULT_PRIORITY: DEFAULT_PRIORITY,
|
||||
DEFAULT_DISPOSEAFTER: DEFAULT_DISPOSEAFTER,
|
||||
SYSTEM_CHANNEL: SYSTEM_CHANNEL
|
||||
},
|
||||
|
||||
channelTypes: {
|
||||
LocalChannel: ChannelDefinition
|
||||
},
|
||||
|
||||
channel: function() {
|
||||
var len = arguments.length;
|
||||
if(channelPicker[len]) {
|
||||
return channelPicker[len].apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
subscribe: function(options) {
|
||||
var callback = options.callback,
|
||||
topic = options.topic,
|
||||
channel = options.channel || DEFAULT_CHANNEL;
|
||||
return new SubscriptionDefinition(channel, topic, callback);
|
||||
},
|
||||
|
||||
publish: function() {
|
||||
var len = arguments.length;
|
||||
if(publishPicker[len]) {
|
||||
return publishPicker[len].apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
addWireTap: function(callback) {
|
||||
return this.configuration.bus.addWireTap(callback);
|
||||
},
|
||||
|
||||
linkChannels: function(sources, destinations) {
|
||||
var result = [];
|
||||
if(!_.isArray(sources)) {
|
||||
sources = [sources];
|
||||
}
|
||||
if(!_.isArray(destinations)) {
|
||||
destinations = [destinations];
|
||||
}
|
||||
_.each(sources, function(source){
|
||||
var sourceTopic = source.topic || "*";
|
||||
_.each(destinations, function(destination) {
|
||||
var destChannel = destination.channel || DEFAULT_CHANNEL;
|
||||
result.push(
|
||||
postal.subscribe({
|
||||
channel: source.channel || DEFAULT_CHANNEL,
|
||||
topic: source.topic || "*",
|
||||
callback : function(data, env) {
|
||||
var newEnv = env;
|
||||
newEnv.topic = _.isFunction(destination.topic) ? destination.topic(env.topic) : destination.topic || env.topic;
|
||||
newEnv.channel = destChannel;
|
||||
newEnv.data = data;
|
||||
postal.publish(newEnv);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
// we check first in case a custom bus or resolver
|
||||
// doesn't expose subscriptions or a resolver cache
|
||||
if(postal.configuration.bus.subscriptions) {
|
||||
postal.configuration.bus.subscriptions = {};
|
||||
}
|
||||
if(postal.configuration.resolver.cache) {
|
||||
postal.configuration.resolver.cache = {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = postal;
|
||||
246
example/node/messaging/postal.socket-host.js
Normal file
246
example/node/messaging/postal.socket-host.js
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
var _ = require('underscore'),
|
||||
machina = require('../machina.js');
|
||||
|
||||
/*
|
||||
A RemoteClientProxy instance is a finite state machine that manages
|
||||
how a socket is used, and how it is (or isn't) allowed to interact
|
||||
with the server-side instance of postal, depending on the state
|
||||
related to the connection and the client on the other end of the socket.
|
||||
*/
|
||||
var RemoteClientProxy = function( postal, socketClient, bridge ) {
|
||||
// helper function to handle when a socket client wants
|
||||
// to set up a subscription to server-side messages
|
||||
var subscribe = function( data ) {
|
||||
var self = this;
|
||||
if( !self.subscriptions[ data.channel ] ) {
|
||||
self.subscriptions[ data.channel ] = {};
|
||||
}
|
||||
if( !self.subscriptions[ data.channel ][ data.topic ] ) {
|
||||
self.subscriptions[ data.channel ][ data.topic ] =
|
||||
postal.subscribe({
|
||||
channel : data.channel,
|
||||
topic : data.topic,
|
||||
callback: function( d, e ) {
|
||||
self.handle( "socketTransmit", d, e );
|
||||
}
|
||||
}).withConstraint(function( data, env ) {
|
||||
if( !env.correlationId ) {
|
||||
return true;
|
||||
}
|
||||
return env.correlationId === self.sessionId;
|
||||
});
|
||||
}
|
||||
},
|
||||
// The actual FSM managing the socketClient
|
||||
fsm = new machina.Fsm({
|
||||
// handle to the socket client wrapper
|
||||
socket: socketClient,
|
||||
|
||||
// object used to store (and lookup) subscriptions owned by this connection/client
|
||||
subscriptions: {},
|
||||
|
||||
// method to allow a RemoteClientProxy to hand off state to another RemoteClientProxy
|
||||
// as part of a migration
|
||||
getClientState: function() {
|
||||
return {
|
||||
queuedMsgs: _.filter( this.eventQueue, function( item ) {
|
||||
return item.args[0] === "socketTransmit";
|
||||
})
|
||||
};
|
||||
},
|
||||
|
||||
sessionId: null,
|
||||
|
||||
states: {
|
||||
// we start here after an explicit transition from uninitialized
|
||||
// the only message we are interested in is "clientId" - in which
|
||||
// the client tells us who they are, and we determine if we need
|
||||
// to move through a migration first, or go directly to 'connected'
|
||||
connecting: {
|
||||
"*" : function() {
|
||||
this.deferUntilTransition();
|
||||
},
|
||||
clientId : function( data ) {
|
||||
this.sessionId = data.sessionId;
|
||||
if( bridge.enableMigration && data.lastSessionId && data.lastSessionId !== data.sessionId ) {
|
||||
this.lastSessionId = data.lastSessionId;
|
||||
this.transition( "migrating" );
|
||||
}
|
||||
else {
|
||||
this.transition( "connected" );
|
||||
}
|
||||
}
|
||||
},
|
||||
// we're going to get any relevant state from the old RemoteClientProxy
|
||||
// and apply it to this instance. This includes the publishing of
|
||||
// messages that got queued up at the old RemoteClientProxy.
|
||||
migrating: {
|
||||
// We tell the client to handle it's migration work (if any) first.
|
||||
_onEnter: function() {
|
||||
this.socket.migrateClientSubscriptions();
|
||||
},
|
||||
// Once the client has completed its migration tasks, it will
|
||||
// publish a message that triggers this handler. This is where we
|
||||
// transfer queued messages from the old RemoteClientProxy, etc.
|
||||
migrationComplete: function ( data ) {
|
||||
if( bridge.clientMap[ this.lastSessionId ] ){
|
||||
var priorState = bridge.clientMap[ this.lastSessionId ].getClientState();
|
||||
_.each(priorState.queuedMsgs, function( item ) {
|
||||
this.eventQueue.unshift( item );
|
||||
}, this );
|
||||
}
|
||||
postal.publish( {
|
||||
channel: "postal.socket",
|
||||
topic: "client.migrated",
|
||||
data: {
|
||||
sessionId: this.socket.id,
|
||||
lastSessionId: this.lastSessionId
|
||||
}
|
||||
} );
|
||||
this.transition( "connected" );
|
||||
},
|
||||
subscribe : subscribe,
|
||||
"*": function() {
|
||||
this.deferUntilTransition();
|
||||
}
|
||||
},
|
||||
// We're online and this is how to handle it....
|
||||
connected: {
|
||||
_onEnter: function() {
|
||||
bridge.clientMap[ this.sessionId ] = this;
|
||||
this.socket.confirmClientIdentified( this.sessionId );
|
||||
},
|
||||
disconnect: function() {
|
||||
this.transition( "disconnected" );
|
||||
},
|
||||
subscribe : subscribe,
|
||||
unsubscribe: function( data ) {
|
||||
if( this.subscriptions[ data.channel ] && this.subscriptions[ data.channel ][ data.topic ] ) {
|
||||
this.subscriptions[ data.channel ] && this.subscriptions[ data.channel ][ data.topic ].unsubscribe();
|
||||
}
|
||||
},
|
||||
publish: function( envelope ) {
|
||||
postal.publish( envelope );
|
||||
},
|
||||
socketTransmit: function( data, envelope ) {
|
||||
this.socket.publish.call( this.socket, data, envelope );
|
||||
}
|
||||
},
|
||||
disconnected: {
|
||||
_onEnter: function() {
|
||||
postal.publish( {
|
||||
channel: "postal.socket",
|
||||
topic: "client.disconnect",
|
||||
data: {
|
||||
sessionId: this.sessionId
|
||||
}
|
||||
} );
|
||||
},
|
||||
"*" : function() {
|
||||
this.deferUntilTransition();
|
||||
},
|
||||
socketTransmit: function() {
|
||||
this.deferUntilTransition("connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// These are all the events from our Socket Client wrapper to which we need to listen.
|
||||
_.each([ "disconnect", "subscribe", "unsubscribe", "publish", "clientId", "migrationComplete" ], function ( evnt ) {
|
||||
socketClient.on( evnt, function( data ) {
|
||||
fsm.handle( evnt, data );
|
||||
});
|
||||
});
|
||||
|
||||
// This is currently here for debugging purposes only
|
||||
fsm.on("*", function(evnt, data){
|
||||
var args = [].slice.call(arguments,1);
|
||||
if(evnt === "Deferred" || args[0] === "socketTransmit") {
|
||||
console.log("Socket FSM: " + evnt + " - " + JSON.stringify(args[0]));
|
||||
}
|
||||
else {
|
||||
console.log("Socket FSM: " + evnt + " - " + JSON.stringify(args));
|
||||
}
|
||||
});
|
||||
|
||||
// every RemoteClientProxy gets a private subscription that can talk to the client
|
||||
// apart from any application-level channels. This is a "utility" conduit.
|
||||
fsm.subscriptions._direct = {
|
||||
_private: postal.subscribe({
|
||||
channel : socketClient.id,
|
||||
topic : "*",
|
||||
callback: function(d, e) {
|
||||
fsm.handle("socketTransmit", d, e);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
// we explicitly start the FSM now that we've wired everything up, etc.
|
||||
fsm.transition( "connecting" );
|
||||
return fsm;
|
||||
};
|
||||
|
||||
var PostalSocketHost = function( postal, socketProvider ) {
|
||||
var self = this;
|
||||
|
||||
// if enableMigration === true, then clients are allowed to migrate
|
||||
// from an older session id to a new one. This can happen when the
|
||||
// client's connection is lost, but the old session id is kept around
|
||||
// in memory or local storage, etc. When the client reconnects, it
|
||||
// will transmit the current and previous (if applicable) session ids.
|
||||
// If this is set to true, then the migration will take place - which
|
||||
// includes transferring existing subscriptions, as well as the delivery
|
||||
// of messages sent to the old session id proxy after the client lost
|
||||
// connection.
|
||||
self.enableMigration = true;
|
||||
|
||||
|
||||
self.channel = postal.channel("postal.socket", "client.connect");
|
||||
|
||||
// array of clients - confirmed or not
|
||||
self.clients = [];
|
||||
|
||||
// once a client has been marked as "identified", they are added to
|
||||
// this object, with the session id as the key.
|
||||
self.clientMap = {};
|
||||
|
||||
// how to clean up a client
|
||||
self.removeClient = function( id ) {
|
||||
if( self.clientMap[ id ] ) {
|
||||
_.each( self.clientMap[ id ].subscriptions, function( channel ){
|
||||
_.each( channel, function( sub ){
|
||||
console.log("unsubscribing: " + sub.channel + " - " + sub.topic);
|
||||
sub.unsubscribe();
|
||||
});
|
||||
});
|
||||
delete self.clientMap[ id ];
|
||||
}
|
||||
self.clients = _.filter(self.clients, function( item ) {
|
||||
return item.sessionId !== id;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
self.provider = socketProvider;
|
||||
|
||||
// when our provider indicates a new socket has connected, we pass
|
||||
// the socket wrapper to an fsm (RemoteClientProxy) to be managed by it.
|
||||
self.provider.on( "connect", function( socket ) {
|
||||
self.clients.push( new RemoteClientProxy( postal, socket, self ) );
|
||||
});
|
||||
|
||||
// when a client disconnects, if enableMigration is true, we don't delete
|
||||
// the old session until it has been used in a migration
|
||||
self.channel.subscribe("client.disconnect", function ( data, envelope ){
|
||||
if( !self.enableMigration ) {
|
||||
self.removeClient( data.sessionId );
|
||||
}
|
||||
});
|
||||
|
||||
// if a session has been used in a migration and is no longer needed, remove it
|
||||
self.channel.subscribe("client.migrated", function ( data, envelope ){
|
||||
self.removeClient( data.lastSessionId );
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = PostalSocketHost;
|
||||
113
example/node/messaging/socket-io-provider.js
Normal file
113
example/node/messaging/socket-io-provider.js
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
var _ = require('underscore'),
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
util = require('util');
|
||||
|
||||
module.exports = {
|
||||
getSocketProvider:function( postal, app, options ) {
|
||||
/*
|
||||
Socket client wrappers must provide the following:
|
||||
1.) an "id" property which returns the session identifier for the connection
|
||||
2.) EventEmitter's "on" method call (to subscribe callbacks to events)
|
||||
3.) publish the following events (consumed by the postal socket host:
|
||||
a.) disconnect - triggered when the socket disconnects.
|
||||
b.) publish - triggered when the client at the other end of the socket
|
||||
publishes a message. The callback(s) for this event should receive
|
||||
a valid postal.js message envelope, and should ideally include a
|
||||
correlationId that matches the client wrapper id.
|
||||
{
|
||||
channel: "someChannel",
|
||||
topic: "some.topic",
|
||||
data: {
|
||||
greeting: "Oh, hai!"
|
||||
},
|
||||
timeStamp: "2012-04-17T07:11:14.731Z",
|
||||
correlationId: "195371348624696856"
|
||||
}
|
||||
c.) unsubscribe - triggered when the client at the other end of the socket
|
||||
specified that they want to unsubscribe a server-side subscription tied
|
||||
to the socket. The callback(s) for this event should receive an object
|
||||
that contains the channel name and topic to unsubscribe:
|
||||
{ channel: "someChannel", topic: "some.topic" }
|
||||
d.) subscribe - triggered when the client at the other end of the socket
|
||||
specifies that they want to subscribe on the server-side, and have messages
|
||||
forwarded over the socket down the client. The callback(s) for this event
|
||||
should receive an object that contains the channel name and topic to which
|
||||
the client wants to subscribe:
|
||||
{ channel: "someChannel", topic: "some.topic" }
|
||||
e.) clientId - triggered when the client sends a message containing the current
|
||||
and previous (if one exists) session id. The callback(s) for this event
|
||||
should receive an object similar to the following:
|
||||
{ sessionId: "5072013211555684761", lastSessionId: "15075244651115973710" }
|
||||
f.) migrationComplete - triggered when the client is done migrating any state from
|
||||
an old session id to the current one. The callbacks do not need an arg provided.
|
||||
|
||||
*/
|
||||
var SocketIoClient = function( socket ) {
|
||||
var self = this;
|
||||
EventEmitter.call(self);
|
||||
|
||||
self.socket = socket;
|
||||
Object.defineProperty( self, "id", {
|
||||
get: function() {
|
||||
return self.socket.id;
|
||||
},
|
||||
enumerable : true
|
||||
});
|
||||
|
||||
// wire up what to do when this socket disconnects
|
||||
self.socket.on( 'disconnect', function () {
|
||||
self.emit( "disconnect", self );
|
||||
});
|
||||
|
||||
// set up event hooks for postal specific events
|
||||
_.each( [ "publish", "unsubscribe", "subscribe", "clientId", "migrationComplete" ], function( evnt ) {
|
||||
self.socket.on( "postal." + evnt, function( data ){
|
||||
self.emit( evnt, data );
|
||||
} );
|
||||
});
|
||||
};
|
||||
|
||||
util.inherits(SocketIoClient, EventEmitter);
|
||||
|
||||
SocketIoClient.prototype.publish = function( data, envelope ) {
|
||||
this.socket.emit( "postal.socket.remote", envelope );
|
||||
};
|
||||
SocketIoClient.prototype.confirmClientIdentified = function( uid ) {
|
||||
this.socket.emit( "postal.socket.identified", { uid: uid } );
|
||||
};
|
||||
SocketIoClient.prototype.migrateClientSubscriptions = function() {
|
||||
this.socket.emit( "postal.socket.migration", {} );
|
||||
};
|
||||
|
||||
/*
|
||||
The Socket Provider is a wrapper around the framework being
|
||||
used to provide websocket functionality to postal.socket.
|
||||
The implementation below wraps socket.io.
|
||||
*/
|
||||
var SocketIoProvider = function( webApp, opt ) {
|
||||
var opt = opt || {},
|
||||
io = require( 'socket.io' ).listen( webApp ),
|
||||
self = this;
|
||||
io.set( 'log level', opt.ioLogLevel || 1 );
|
||||
|
||||
EventEmitter.call(self);
|
||||
|
||||
self.events = {
|
||||
"connect" : []
|
||||
};
|
||||
|
||||
// We listen for when socket.io detects a new socket connection.
|
||||
// Then we take that socket instance and wrap it in our SocketIoClient
|
||||
// wrapper. The PostalSocketHost receives an instance of this
|
||||
// SocketIoProvider object and subscribes to the "connect" event.
|
||||
io.sockets.on( "connection", function( socket ) {
|
||||
var _socket = new SocketIoClient( socket );
|
||||
self.emit("connect", _socket);
|
||||
});
|
||||
};
|
||||
|
||||
util.inherits(SocketIoProvider, EventEmitter);
|
||||
|
||||
return new SocketIoProvider( app, options );
|
||||
}
|
||||
};
|
||||
416
example/node/node_modules/.bin/express
generated
vendored
Executable file
416
example/node/node_modules/.bin/express
generated
vendored
Executable file
|
|
@ -0,0 +1,416 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, os = require('os')
|
||||
, exec = require('child_process').exec
|
||||
, mkdirp = require('mkdirp');
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
var version = '2.5.8';
|
||||
|
||||
/**
|
||||
* Add session support.
|
||||
*/
|
||||
|
||||
var sessions = false;
|
||||
|
||||
/**
|
||||
* CSS engine to utilize.
|
||||
*/
|
||||
|
||||
var cssEngine;
|
||||
|
||||
/**
|
||||
* End-of-line code.
|
||||
*/
|
||||
|
||||
var eol = os.platform
|
||||
? ('win32' == os.platform() ? '\r\n' : '\n')
|
||||
: '\n';
|
||||
|
||||
/**
|
||||
* Template engine to utilize.
|
||||
*/
|
||||
|
||||
var templateEngine = 'jade';
|
||||
|
||||
/**
|
||||
* Usage documentation.
|
||||
*/
|
||||
|
||||
var usage = ''
|
||||
+ '\n'
|
||||
+ ' Usage: express [options] [path]\n'
|
||||
+ '\n'
|
||||
+ ' Options:\n'
|
||||
+ ' -s, --sessions add session support\n'
|
||||
+ ' -t, --template <engine> add template <engine> support (jade|ejs). default=jade\n'
|
||||
+ ' -c, --css <engine> add stylesheet <engine> support (stylus). default=plain css\n'
|
||||
+ ' -v, --version output framework version\n'
|
||||
+ ' -h, --help output help information\n'
|
||||
;
|
||||
|
||||
/**
|
||||
* Routes index template.
|
||||
*/
|
||||
|
||||
var index = [
|
||||
''
|
||||
, '/*'
|
||||
, ' * GET home page.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.index = function(req, res){'
|
||||
, ' res.render(\'index\', { title: \'Express\' })'
|
||||
, '};'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
*/
|
||||
|
||||
var jadeLayout = [
|
||||
'!!!'
|
||||
, 'html'
|
||||
, ' head'
|
||||
, ' title= title'
|
||||
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
|
||||
, ' body!= body'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade index template.
|
||||
*/
|
||||
|
||||
var jadeIndex = [
|
||||
'h1= title'
|
||||
, 'p Welcome to #{title}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* EJS layout template.
|
||||
*/
|
||||
|
||||
var ejsLayout = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title><%= title %></title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' <%- body %>'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* EJS index template.
|
||||
*/
|
||||
|
||||
var ejsIndex = [
|
||||
'<h1><%= title %></h1>'
|
||||
, '<p>Welcome to <%= title %></p>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default css template.
|
||||
*/
|
||||
|
||||
var css = [
|
||||
'body {'
|
||||
, ' padding: 50px;'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default stylus template.
|
||||
*/
|
||||
|
||||
var stylus = [
|
||||
'body'
|
||||
, ' padding: 50px'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' color: #00B7FF'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* App template.
|
||||
*/
|
||||
|
||||
var app = [
|
||||
''
|
||||
, '/**'
|
||||
, ' * Module dependencies.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\');'
|
||||
, ''
|
||||
, 'var app = module.exports = express.createServer();'
|
||||
, ''
|
||||
, '// Configuration'
|
||||
, ''
|
||||
, 'app.configure(function(){'
|
||||
, ' app.set(\'views\', __dirname + \'/views\');'
|
||||
, ' app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, ' app.use(express.bodyParser());'
|
||||
, ' app.use(express.methodOverride());{sess}{css}'
|
||||
, ' app.use(app.router);'
|
||||
, ' app.use(express.static(__dirname + \'/public\'));'
|
||||
, '});'
|
||||
, ''
|
||||
, 'app.configure(\'development\', function(){'
|
||||
, ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));'
|
||||
, '});'
|
||||
, ''
|
||||
, 'app.configure(\'production\', function(){'
|
||||
, ' app.use(express.errorHandler());'
|
||||
, '});'
|
||||
, ''
|
||||
, '// Routes'
|
||||
, ''
|
||||
, 'app.get(\'/\', routes.index);'
|
||||
, ''
|
||||
, 'app.listen(3000);'
|
||||
, 'console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);'
|
||||
, ''
|
||||
].join(eol);
|
||||
|
||||
// Parse arguments
|
||||
|
||||
var args = process.argv.slice(2)
|
||||
, path = '.';
|
||||
|
||||
while (args.length) {
|
||||
var arg = args.shift();
|
||||
switch (arg) {
|
||||
case '-h':
|
||||
case '--help':
|
||||
abort(usage);
|
||||
break;
|
||||
case '-v':
|
||||
case '--version':
|
||||
abort(version);
|
||||
break;
|
||||
case '-s':
|
||||
case '--session':
|
||||
case '--sessions':
|
||||
sessions = true;
|
||||
break;
|
||||
case '-c':
|
||||
case '--css':
|
||||
args.length
|
||||
? (cssEngine = args.shift())
|
||||
: abort('--css requires an argument');
|
||||
break;
|
||||
case '-t':
|
||||
case '--template':
|
||||
args.length
|
||||
? (templateEngine = args.shift())
|
||||
: abort('--template requires an argument');
|
||||
break;
|
||||
default:
|
||||
path = arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate application
|
||||
|
||||
(function createApplication(path) {
|
||||
emptyDirectory(path, function(empty){
|
||||
if (empty) {
|
||||
createApplicationAt(path);
|
||||
} else {
|
||||
confirm('destination is not empty, continue? ', function(ok){
|
||||
if (ok) {
|
||||
process.stdin.destroy();
|
||||
createApplicationAt(path);
|
||||
} else {
|
||||
abort('aborting');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})(path);
|
||||
|
||||
/**
|
||||
* Create application at the given directory `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
*/
|
||||
|
||||
function createApplicationAt(path) {
|
||||
console.log();
|
||||
process.on('exit', function(){
|
||||
console.log();
|
||||
console.log(' dont forget to install dependencies:');
|
||||
console.log(' $ cd %s && npm install', path);
|
||||
console.log();
|
||||
});
|
||||
|
||||
mkdir(path, function(){
|
||||
mkdir(path + '/public');
|
||||
mkdir(path + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
switch (cssEngine) {
|
||||
case 'stylus':
|
||||
write(path + '/public/stylesheets/style.styl', stylus);
|
||||
break;
|
||||
default:
|
||||
write(path + '/public/stylesheets/style.css', css);
|
||||
}
|
||||
});
|
||||
|
||||
mkdir(path + '/routes', function(){
|
||||
write(path + '/routes/index.js', index);
|
||||
});
|
||||
|
||||
mkdir(path + '/views', function(){
|
||||
switch (templateEngine) {
|
||||
case 'ejs':
|
||||
write(path + '/views/layout.ejs', ejsLayout);
|
||||
write(path + '/views/index.ejs', ejsIndex);
|
||||
break;
|
||||
case 'jade':
|
||||
write(path + '/views/layout.jade', jadeLayout);
|
||||
write(path + '/views/index.jade', jadeIndex);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// CSS Engine support
|
||||
switch (cssEngine) {
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
|
||||
break;
|
||||
default:
|
||||
app = app.replace('{css}', '');
|
||||
}
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', sessions
|
||||
? eol + ' app.use(express.cookieParser());' + eol + ' app.use(express.session({ secret: \'your secret here\' }));'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
app = app.replace(':TEMPLATE', templateEngine);
|
||||
|
||||
// package.json
|
||||
var json = '{' + eol;
|
||||
json += ' "name": "application-name"' + eol;
|
||||
json += ' , "version": "0.0.1"' + eol;
|
||||
json += ' , "private": true' + eol;
|
||||
json += ' , "dependencies": {' + eol;
|
||||
json += ' "express": "' + version + '"' + eol;
|
||||
if (cssEngine) json += ' , "' + cssEngine + '": ">= 0.0.1"' + eol;
|
||||
if (templateEngine) json += ' , "' + templateEngine + '": ">= 0.0.1"' + eol;
|
||||
json += ' }' + eol;
|
||||
json += '}';
|
||||
|
||||
|
||||
write(path + '/package.json', json);
|
||||
write(path + '/app.js', app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given directory `path` is empty.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function emptyDirectory(path, fn) {
|
||||
fs.readdir(path, function(err, files){
|
||||
if (err && 'ENOENT' != err.code) throw err;
|
||||
fn(!files || !files.length);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* echo str > path.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function write(path, str) {
|
||||
fs.writeFile(path, str);
|
||||
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt confirmation with the given `msg`.
|
||||
*
|
||||
* @param {String} msg
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function confirm(msg, fn) {
|
||||
prompt(msg, function(val){
|
||||
fn(/^ *y(es)?/i.test(val));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt input with the given `msg` and callback `fn`.
|
||||
*
|
||||
* @param {String} msg
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function prompt(msg, fn) {
|
||||
// prompt
|
||||
if (' ' == msg[msg.length - 1]) {
|
||||
process.stdout.write(msg);
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
// stdin
|
||||
process.stdin.setEncoding('ascii');
|
||||
process.stdin.once('data', function(data){
|
||||
fn(data);
|
||||
}).resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mkdir -p.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function mkdir(path, fn) {
|
||||
mkdirp(path, 0755, function(err){
|
||||
if (err) throw err;
|
||||
console.log(' \033[36mcreate\033[0m : ' + path);
|
||||
fn && fn();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit with the given `str`.
|
||||
*
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function abort(str) {
|
||||
console.error(str);
|
||||
process.exit(1);
|
||||
}
|
||||
7
example/node/node_modules/express/.npmignore
generated
vendored
Normal file
7
example/node/node_modules/express/.npmignore
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
.git*
|
||||
docs/
|
||||
examples/
|
||||
support/
|
||||
test/
|
||||
testing.js
|
||||
.DS_Store
|
||||
805
example/node/node_modules/express/History.md
generated
vendored
Normal file
805
example/node/node_modules/express/History.md
generated
vendored
Normal file
|
|
@ -0,0 +1,805 @@
|
|||
|
||||
2.5.8 / 2012-02-08
|
||||
==================
|
||||
|
||||
* Update mkdirp dep. Closes #991
|
||||
|
||||
2.5.7 / 2012-02-06
|
||||
==================
|
||||
|
||||
* Fixed `app.all` duplicate DELETE requests [mscdex]
|
||||
|
||||
2.5.6 / 2012-01-13
|
||||
==================
|
||||
|
||||
* Updated hamljs dev dep. Closes #953
|
||||
|
||||
2.5.5 / 2012-01-08
|
||||
==================
|
||||
|
||||
* Fixed: set `filename` on cached templates [matthewleon]
|
||||
|
||||
2.5.4 / 2012-01-02
|
||||
==================
|
||||
|
||||
* Fixed `express(1)` eol on 0.4.x. Closes #947
|
||||
|
||||
2.5.3 / 2011-12-30
|
||||
==================
|
||||
|
||||
* Fixed `req.is()` when a charset is present
|
||||
|
||||
2.5.2 / 2011-12-10
|
||||
==================
|
||||
|
||||
* Fixed: express(1) LF -> CRLF for windows
|
||||
|
||||
2.5.1 / 2011-11-17
|
||||
==================
|
||||
|
||||
* Changed: updated connect to 1.8.x
|
||||
* Removed sass.js support from express(1)
|
||||
|
||||
2.5.0 / 2011-10-24
|
||||
==================
|
||||
|
||||
* Added ./routes dir for generated app by default
|
||||
* Added npm install reminder to express(1) app gen
|
||||
* Added 0.5.x support
|
||||
* Removed `make test-cov` since it wont work with node 0.5.x
|
||||
* Fixed express(1) public dir for windows. Closes #866
|
||||
|
||||
2.4.7 / 2011-10-05
|
||||
==================
|
||||
|
||||
* Added mkdirp to express(1). Closes #795
|
||||
* Added simple _json-config_ example
|
||||
* Added shorthand for the parsed request's pathname via `req.path`
|
||||
* Changed connect dep to 1.7.x to fix npm issue...
|
||||
* Fixed `res.redirect()` __HEAD__ support. [reported by xerox]
|
||||
* Fixed `req.flash()`, only escape args
|
||||
* Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie]
|
||||
|
||||
2.4.6 / 2011-08-22
|
||||
==================
|
||||
|
||||
* Fixed multiple param callback regression. Closes #824 [reported by TroyGoode]
|
||||
|
||||
2.4.5 / 2011-08-19
|
||||
==================
|
||||
|
||||
* Added support for routes to handle errors. Closes #809
|
||||
* Added `app.routes.all()`. Closes #803
|
||||
* Added "basepath" setting to work in conjunction with reverse proxies etc.
|
||||
* Refactored `Route` to use a single array of callbacks
|
||||
* Added support for multiple callbacks for `app.param()`. Closes #801
|
||||
Closes #805
|
||||
* Changed: removed .call(self) for route callbacks
|
||||
* Dependency: `qs >= 0.3.1`
|
||||
* Fixed `res.redirect()` on windows due to `join()` usage. Closes #808
|
||||
|
||||
2.4.4 / 2011-08-05
|
||||
==================
|
||||
|
||||
* Fixed `res.header()` intention of a set, even when `undefined`
|
||||
* Fixed `*`, value no longer required
|
||||
* Fixed `res.send(204)` support. Closes #771
|
||||
|
||||
2.4.3 / 2011-07-14
|
||||
==================
|
||||
|
||||
* Added docs for `status` option special-case. Closes #739
|
||||
* Fixed `options.filename`, exposing the view path to template engines
|
||||
|
||||
2.4.2. / 2011-07-06
|
||||
==================
|
||||
|
||||
* Revert "removed jsonp stripping" for XSS
|
||||
|
||||
2.4.1 / 2011-07-06
|
||||
==================
|
||||
|
||||
* Added `res.json()` JSONP support. Closes #737
|
||||
* Added _extending-templates_ example. Closes #730
|
||||
* Added "strict routing" setting for trailing slashes
|
||||
* Added support for multiple envs in `app.configure()` calls. Closes #735
|
||||
* Changed: `res.send()` using `res.json()`
|
||||
* Changed: when cookie `path === null` don't default it
|
||||
* Changed; default cookie path to "home" setting. Closes #731
|
||||
* Removed _pids/logs_ creation from express(1)
|
||||
|
||||
2.4.0 / 2011-06-28
|
||||
==================
|
||||
|
||||
* Added chainable `res.status(code)`
|
||||
* Added `res.json()`, an explicit version of `res.send(obj)`
|
||||
* Added simple web-service example
|
||||
|
||||
2.3.12 / 2011-06-22
|
||||
==================
|
||||
|
||||
* \#express is now on freenode! come join!
|
||||
* Added `req.get(field, param)`
|
||||
* Added links to Japanese documentation, thanks @hideyukisaito!
|
||||
* Added; the `express(1)` generated app outputs the env
|
||||
* Added `content-negotiation` example
|
||||
* Dependency: connect >= 1.5.1 < 2.0.0
|
||||
* Fixed view layout bug. Closes #720
|
||||
* Fixed; ignore body on 304. Closes #701
|
||||
|
||||
2.3.11 / 2011-06-04
|
||||
==================
|
||||
|
||||
* Added `npm test`
|
||||
* Removed generation of dummy test file from `express(1)`
|
||||
* Fixed; `express(1)` adds express as a dep
|
||||
* Fixed; prune on `prepublish`
|
||||
|
||||
2.3.10 / 2011-05-27
|
||||
==================
|
||||
|
||||
* Added `req.route`, exposing the current route
|
||||
* Added _package.json_ generation support to `express(1)`
|
||||
* Fixed call to `app.param()` function for optional params. Closes #682
|
||||
|
||||
2.3.9 / 2011-05-25
|
||||
==================
|
||||
|
||||
* Fixed bug-ish with `../' in `res.partial()` calls
|
||||
|
||||
2.3.8 / 2011-05-24
|
||||
==================
|
||||
|
||||
* Fixed `app.options()`
|
||||
|
||||
2.3.7 / 2011-05-23
|
||||
==================
|
||||
|
||||
* Added route `Collection`, ex: `app.get('/user/:id').remove();`
|
||||
* Added support for `app.param(fn)` to define param logic
|
||||
* Removed `app.param()` support for callback with return value
|
||||
* Removed module.parent check from express(1) generated app. Closes #670
|
||||
* Refactored router. Closes #639
|
||||
|
||||
2.3.6 / 2011-05-20
|
||||
==================
|
||||
|
||||
* Changed; using devDependencies instead of git submodules
|
||||
* Fixed redis session example
|
||||
* Fixed markdown example
|
||||
* Fixed view caching, should not be enabled in development
|
||||
|
||||
2.3.5 / 2011-05-20
|
||||
==================
|
||||
|
||||
* Added export `.view` as alias for `.View`
|
||||
|
||||
2.3.4 / 2011-05-08
|
||||
==================
|
||||
|
||||
* Added `./examples/say`
|
||||
* Fixed `res.sendfile()` bug preventing the transfer of files with spaces
|
||||
|
||||
2.3.3 / 2011-05-03
|
||||
==================
|
||||
|
||||
* Added "case sensitive routes" option.
|
||||
* Changed; split methods supported per rfc [slaskis]
|
||||
* Fixed route-specific middleware when using the same callback function several times
|
||||
|
||||
2.3.2 / 2011-04-27
|
||||
==================
|
||||
|
||||
* Fixed view hints
|
||||
|
||||
2.3.1 / 2011-04-26
|
||||
==================
|
||||
|
||||
* Added `app.match()` as `app.match.all()`
|
||||
* Added `app.lookup()` as `app.lookup.all()`
|
||||
* Added `app.remove()` for `app.remove.all()`
|
||||
* Added `app.remove.VERB()`
|
||||
* Fixed template caching collision issue. Closes #644
|
||||
* Moved router over from connect and started refactor
|
||||
|
||||
2.3.0 / 2011-04-25
|
||||
==================
|
||||
|
||||
* Added options support to `res.clearCookie()`
|
||||
* Added `res.helpers()` as alias of `res.locals()`
|
||||
* Added; json defaults to UTF-8 with `res.send()`. Closes #632. [Daniel * Dependency `connect >= 1.4.0`
|
||||
* Changed; auto set Content-Type in res.attachement [Aaron Heckmann]
|
||||
* Renamed "cache views" to "view cache". Closes #628
|
||||
* Fixed caching of views when using several apps. Closes #637
|
||||
* Fixed gotcha invoking `app.param()` callbacks once per route middleware.
|
||||
Closes #638
|
||||
* Fixed partial lookup precedence. Closes #631
|
||||
Shaw]
|
||||
|
||||
2.2.2 / 2011-04-12
|
||||
==================
|
||||
|
||||
* Added second callback support for `res.download()` connection errors
|
||||
* Fixed `filename` option passing to template engine
|
||||
|
||||
2.2.1 / 2011-04-04
|
||||
==================
|
||||
|
||||
* Added `layout(path)` helper to change the layout within a view. Closes #610
|
||||
* Fixed `partial()` collection object support.
|
||||
Previously only anything with `.length` would work.
|
||||
When `.length` is present one must still be aware of holes,
|
||||
however now `{ collection: {foo: 'bar'}}` is valid, exposes
|
||||
`keyInCollection` and `keysInCollection`.
|
||||
|
||||
* Performance improved with better view caching
|
||||
* Removed `request` and `response` locals
|
||||
* Changed; errorHandler page title is now `Express` instead of `Connect`
|
||||
|
||||
2.2.0 / 2011-03-30
|
||||
==================
|
||||
|
||||
* Added `app.lookup.VERB()`, ex `app.lookup.put('/user/:id')`. Closes #606
|
||||
* Added `app.match.VERB()`, ex `app.match.put('/user/12')`. Closes #606
|
||||
* Added `app.VERB(path)` as alias of `app.lookup.VERB()`.
|
||||
* Dependency `connect >= 1.2.0`
|
||||
|
||||
2.1.1 / 2011-03-29
|
||||
==================
|
||||
|
||||
* Added; expose `err.view` object when failing to locate a view
|
||||
* Fixed `res.partial()` call `next(err)` when no callback is given [reported by aheckmann]
|
||||
* Fixed; `res.send(undefined)` responds with 204 [aheckmann]
|
||||
|
||||
2.1.0 / 2011-03-24
|
||||
==================
|
||||
|
||||
* Added `<root>/_?<name>` partial lookup support. Closes #447
|
||||
* Added `request`, `response`, and `app` local variables
|
||||
* Added `settings` local variable, containing the app's settings
|
||||
* Added `req.flash()` exception if `req.session` is not available
|
||||
* Added `res.send(bool)` support (json response)
|
||||
* Fixed stylus example for latest version
|
||||
* Fixed; wrap try/catch around `res.render()`
|
||||
|
||||
2.0.0 / 2011-03-17
|
||||
==================
|
||||
|
||||
* Fixed up index view path alternative.
|
||||
* Changed; `res.locals()` without object returns the locals
|
||||
|
||||
2.0.0rc3 / 2011-03-17
|
||||
==================
|
||||
|
||||
* Added `res.locals(obj)` to compliment `res.local(key, val)`
|
||||
* Added `res.partial()` callback support
|
||||
* Fixed recursive error reporting issue in `res.render()`
|
||||
|
||||
2.0.0rc2 / 2011-03-17
|
||||
==================
|
||||
|
||||
* Changed; `partial()` "locals" are now optional
|
||||
* Fixed `SlowBuffer` support. Closes #584 [reported by tyrda01]
|
||||
* Fixed .filename view engine option [reported by drudge]
|
||||
* Fixed blog example
|
||||
* Fixed `{req,res}.app` reference when mounting [Ben Weaver]
|
||||
|
||||
2.0.0rc / 2011-03-14
|
||||
==================
|
||||
|
||||
* Fixed; expose `HTTPSServer` constructor
|
||||
* Fixed express(1) default test charset. Closes #579 [reported by secoif]
|
||||
* Fixed; default charset to utf-8 instead of utf8 for lame IE [reported by NickP]
|
||||
|
||||
2.0.0beta3 / 2011-03-09
|
||||
==================
|
||||
|
||||
* Added support for `res.contentType()` literal
|
||||
The original `res.contentType('.json')`,
|
||||
`res.contentType('application/json')`, and `res.contentType('json')`
|
||||
will work now.
|
||||
* Added `res.render()` status option support back
|
||||
* Added charset option for `res.render()`
|
||||
* Added `.charset` support (via connect 1.0.4)
|
||||
* Added view resolution hints when in development and a lookup fails
|
||||
* Added layout lookup support relative to the page view.
|
||||
For example while rendering `./views/user/index.jade` if you create
|
||||
`./views/user/layout.jade` it will be used in favour of the root layout.
|
||||
* Fixed `res.redirect()`. RFC states absolute url [reported by unlink]
|
||||
* Fixed; default `res.send()` string charset to utf8
|
||||
* Removed `Partial` constructor (not currently used)
|
||||
|
||||
2.0.0beta2 / 2011-03-07
|
||||
==================
|
||||
|
||||
* Added res.render() `.locals` support back to aid in migration process
|
||||
* Fixed flash example
|
||||
|
||||
2.0.0beta / 2011-03-03
|
||||
==================
|
||||
|
||||
* Added HTTPS support
|
||||
* Added `res.cookie()` maxAge support
|
||||
* Added `req.header()` _Referrer_ / _Referer_ special-case, either works
|
||||
* Added mount support for `res.redirect()`, now respects the mount-point
|
||||
* Added `union()` util, taking place of `merge(clone())` combo
|
||||
* Added stylus support to express(1) generated app
|
||||
* Added secret to session middleware used in examples and generated app
|
||||
* Added `res.local(name, val)` for progressive view locals
|
||||
* Added default param support to `req.param(name, default)`
|
||||
* Added `app.disabled()` and `app.enabled()`
|
||||
* Added `app.register()` support for omitting leading ".", either works
|
||||
* Added `res.partial()`, using the same interface as `partial()` within a view. Closes #539
|
||||
* Added `app.param()` to map route params to async/sync logic
|
||||
* Added; aliased `app.helpers()` as `app.locals()`. Closes #481
|
||||
* Added extname with no leading "." support to `res.contentType()`
|
||||
* Added `cache views` setting, defaulting to enabled in "production" env
|
||||
* Added index file partial resolution, eg: partial('user') may try _views/user/index.jade_.
|
||||
* Added `req.accepts()` support for extensions
|
||||
* Changed; `res.download()` and `res.sendfile()` now utilize Connect's
|
||||
static file server `connect.static.send()`.
|
||||
* Changed; replaced `connect.utils.mime()` with npm _mime_ module
|
||||
* Changed; allow `req.query` to be pre-defined (via middleware or other parent
|
||||
* Changed view partial resolution, now relative to parent view
|
||||
* Changed view engine signature. no longer `engine.render(str, options, callback)`, now `engine.compile(str, options) -> Function`, the returned function accepts `fn(locals)`.
|
||||
* Fixed `req.param()` bug returning Array.prototype methods. Closes #552
|
||||
* Fixed; using `Stream#pipe()` instead of `sys.pump()` in `res.sendfile()`
|
||||
* Fixed; using _qs_ module instead of _querystring_
|
||||
* Fixed; strip unsafe chars from jsonp callbacks
|
||||
* Removed "stream threshold" setting
|
||||
|
||||
1.0.8 / 2011-03-01
|
||||
==================
|
||||
|
||||
* Allow `req.query` to be pre-defined (via middleware or other parent app)
|
||||
* "connect": ">= 0.5.0 < 1.0.0". Closes #547
|
||||
* Removed the long deprecated __EXPRESS_ENV__ support
|
||||
|
||||
1.0.7 / 2011-02-07
|
||||
==================
|
||||
|
||||
* Fixed `render()` setting inheritance.
|
||||
Mounted apps would not inherit "view engine"
|
||||
|
||||
1.0.6 / 2011-02-07
|
||||
==================
|
||||
|
||||
* Fixed `view engine` setting bug when period is in dirname
|
||||
|
||||
1.0.5 / 2011-02-05
|
||||
==================
|
||||
|
||||
* Added secret to generated app `session()` call
|
||||
|
||||
1.0.4 / 2011-02-05
|
||||
==================
|
||||
|
||||
* Added `qs` dependency to _package.json_
|
||||
* Fixed namespaced `require()`s for latest connect support
|
||||
|
||||
1.0.3 / 2011-01-13
|
||||
==================
|
||||
|
||||
* Remove unsafe characters from JSONP callback names [Ryan Grove]
|
||||
|
||||
1.0.2 / 2011-01-10
|
||||
==================
|
||||
|
||||
* Removed nested require, using `connect.router`
|
||||
|
||||
1.0.1 / 2010-12-29
|
||||
==================
|
||||
|
||||
* Fixed for middleware stacked via `createServer()`
|
||||
previously the `foo` middleware passed to `createServer(foo)`
|
||||
would not have access to Express methods such as `res.send()`
|
||||
or props like `req.query` etc.
|
||||
|
||||
1.0.0 / 2010-11-16
|
||||
==================
|
||||
|
||||
* Added; deduce partial object names from the last segment.
|
||||
For example by default `partial('forum/post', postObject)` will
|
||||
give you the _post_ object, providing a meaningful default.
|
||||
* Added http status code string representation to `res.redirect()` body
|
||||
* Added; `res.redirect()` supporting _text/plain_ and _text/html_ via __Accept__.
|
||||
* Added `req.is()` to aid in content negotiation
|
||||
* Added partial local inheritance [suggested by masylum]. Closes #102
|
||||
providing access to parent template locals.
|
||||
* Added _-s, --session[s]_ flag to express(1) to add session related middleware
|
||||
* Added _--template_ flag to express(1) to specify the
|
||||
template engine to use.
|
||||
* Added _--css_ flag to express(1) to specify the
|
||||
stylesheet engine to use (or just plain css by default).
|
||||
* Added `app.all()` support [thanks aheckmann]
|
||||
* Added partial direct object support.
|
||||
You may now `partial('user', user)` providing the "user" local,
|
||||
vs previously `partial('user', { object: user })`.
|
||||
* Added _route-separation_ example since many people question ways
|
||||
to do this with CommonJS modules. Also view the _blog_ example for
|
||||
an alternative.
|
||||
* Performance; caching view path derived partial object names
|
||||
* Fixed partial local inheritance precedence. [reported by Nick Poulden] Closes #454
|
||||
* Fixed jsonp support; _text/javascript_ as per mailinglist discussion
|
||||
|
||||
1.0.0rc4 / 2010-10-14
|
||||
==================
|
||||
|
||||
* Added _NODE_ENV_ support, _EXPRESS_ENV_ is deprecated and will be removed in 1.0.0
|
||||
* Added route-middleware support (very helpful, see the [docs](http://expressjs.com/guide.html#Route-Middleware))
|
||||
* Added _jsonp callback_ setting to enable/disable jsonp autowrapping [Dav Glass]
|
||||
* Added callback query check on response.send to autowrap JSON objects for simple webservice implementations [Dav Glass]
|
||||
* Added `partial()` support for array-like collections. Closes #434
|
||||
* Added support for swappable querystring parsers
|
||||
* Added session usage docs. Closes #443
|
||||
* Added dynamic helper caching. Closes #439 [suggested by maritz]
|
||||
* Added authentication example
|
||||
* Added basic Range support to `res.sendfile()` (and `res.download()` etc)
|
||||
* Changed; `express(1)` generated app using 2 spaces instead of 4
|
||||
* Default env to "development" again [aheckmann]
|
||||
* Removed _context_ option is no more, use "scope"
|
||||
* Fixed; exposing _./support_ libs to examples so they can run without installs
|
||||
* Fixed mvc example
|
||||
|
||||
1.0.0rc3 / 2010-09-20
|
||||
==================
|
||||
|
||||
* Added confirmation for `express(1)` app generation. Closes #391
|
||||
* Added extending of flash formatters via `app.flashFormatters`
|
||||
* Added flash formatter support. Closes #411
|
||||
* Added streaming support to `res.sendfile()` using `sys.pump()` when >= "stream threshold"
|
||||
* Added _stream threshold_ setting for `res.sendfile()`
|
||||
* Added `res.send()` __HEAD__ support
|
||||
* Added `res.clearCookie()`
|
||||
* Added `res.cookie()`
|
||||
* Added `res.render()` headers option
|
||||
* Added `res.redirect()` response bodies
|
||||
* Added `res.render()` status option support. Closes #425 [thanks aheckmann]
|
||||
* Fixed `res.sendfile()` responding with 403 on malicious path
|
||||
* Fixed `res.download()` bug; when an error occurs remove _Content-Disposition_
|
||||
* Fixed; mounted apps settings now inherit from parent app [aheckmann]
|
||||
* Fixed; stripping Content-Length / Content-Type when 204
|
||||
* Fixed `res.send()` 204. Closes #419
|
||||
* Fixed multiple _Set-Cookie_ headers via `res.header()`. Closes #402
|
||||
* Fixed bug messing with error handlers when `listenFD()` is called instead of `listen()`. [thanks guillermo]
|
||||
|
||||
|
||||
1.0.0rc2 / 2010-08-17
|
||||
==================
|
||||
|
||||
* Added `app.register()` for template engine mapping. Closes #390
|
||||
* Added `res.render()` callback support as second argument (no options)
|
||||
* Added callback support to `res.download()`
|
||||
* Added callback support for `res.sendfile()`
|
||||
* Added support for middleware access via `express.middlewareName()` vs `connect.middlewareName()`
|
||||
* Added "partials" setting to docs
|
||||
* Added default expresso tests to `express(1)` generated app. Closes #384
|
||||
* Fixed `res.sendfile()` error handling, defer via `next()`
|
||||
* Fixed `res.render()` callback when a layout is used [thanks guillermo]
|
||||
* Fixed; `make install` creating ~/.node_libraries when not present
|
||||
* Fixed issue preventing error handlers from being defined anywhere. Closes #387
|
||||
|
||||
1.0.0rc / 2010-07-28
|
||||
==================
|
||||
|
||||
* Added mounted hook. Closes #369
|
||||
* Added connect dependency to _package.json_
|
||||
|
||||
* Removed "reload views" setting and support code
|
||||
development env never caches, production always caches.
|
||||
|
||||
* Removed _param_ in route callbacks, signature is now
|
||||
simply (req, res, next), previously (req, res, params, next).
|
||||
Use _req.params_ for path captures, _req.query_ for GET params.
|
||||
|
||||
* Fixed "home" setting
|
||||
* Fixed middleware/router precedence issue. Closes #366
|
||||
* Fixed; _configure()_ callbacks called immediately. Closes #368
|
||||
|
||||
1.0.0beta2 / 2010-07-23
|
||||
==================
|
||||
|
||||
* Added more examples
|
||||
* Added; exporting `Server` constructor
|
||||
* Added `Server#helpers()` for view locals
|
||||
* Added `Server#dynamicHelpers()` for dynamic view locals. Closes #349
|
||||
* Added support for absolute view paths
|
||||
* Added; _home_ setting defaults to `Server#route` for mounted apps. Closes #363
|
||||
* Added Guillermo Rauch to the contributor list
|
||||
* Added support for "as" for non-collection partials. Closes #341
|
||||
* Fixed _install.sh_, ensuring _~/.node_libraries_ exists. Closes #362 [thanks jf]
|
||||
* Fixed `res.render()` exceptions, now passed to `next()` when no callback is given [thanks guillermo]
|
||||
* Fixed instanceof `Array` checks, now `Array.isArray()`
|
||||
* Fixed express(1) expansion of public dirs. Closes #348
|
||||
* Fixed middleware precedence. Closes #345
|
||||
* Fixed view watcher, now async [thanks aheckmann]
|
||||
|
||||
1.0.0beta / 2010-07-15
|
||||
==================
|
||||
|
||||
* Re-write
|
||||
- much faster
|
||||
- much lighter
|
||||
- Check [ExpressJS.com](http://expressjs.com) for migration guide and updated docs
|
||||
|
||||
0.14.0 / 2010-06-15
|
||||
==================
|
||||
|
||||
* Utilize relative requires
|
||||
* Added Static bufferSize option [aheckmann]
|
||||
* Fixed caching of view and partial subdirectories [aheckmann]
|
||||
* Fixed mime.type() comments now that ".ext" is not supported
|
||||
* Updated haml submodule
|
||||
* Updated class submodule
|
||||
* Removed bin/express
|
||||
|
||||
0.13.0 / 2010-06-01
|
||||
==================
|
||||
|
||||
* Added node v0.1.97 compatibility
|
||||
* Added support for deleting cookies via Request#cookie('key', null)
|
||||
* Updated haml submodule
|
||||
* Fixed not-found page, now using using charset utf-8
|
||||
* Fixed show-exceptions page, now using using charset utf-8
|
||||
* Fixed view support due to fs.readFile Buffers
|
||||
* Changed; mime.type() no longer accepts ".type" due to node extname() changes
|
||||
|
||||
0.12.0 / 2010-05-22
|
||||
==================
|
||||
|
||||
* Added node v0.1.96 compatibility
|
||||
* Added view `helpers` export which act as additional local variables
|
||||
* Updated haml submodule
|
||||
* Changed ETag; removed inode, modified time only
|
||||
* Fixed LF to CRLF for setting multiple cookies
|
||||
* Fixed cookie complation; values are now urlencoded
|
||||
* Fixed cookies parsing; accepts quoted values and url escaped cookies
|
||||
|
||||
0.11.0 / 2010-05-06
|
||||
==================
|
||||
|
||||
* Added support for layouts using different engines
|
||||
- this.render('page.html.haml', { layout: 'super-cool-layout.html.ejs' })
|
||||
- this.render('page.html.haml', { layout: 'foo' }) // assumes 'foo.html.haml'
|
||||
- this.render('page.html.haml', { layout: false }) // no layout
|
||||
* Updated ext submodule
|
||||
* Updated haml submodule
|
||||
* Fixed EJS partial support by passing along the context. Issue #307
|
||||
|
||||
0.10.1 / 2010-05-03
|
||||
==================
|
||||
|
||||
* Fixed binary uploads.
|
||||
|
||||
0.10.0 / 2010-04-30
|
||||
==================
|
||||
|
||||
* Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s
|
||||
encoding is set to 'utf8' or 'utf-8'.
|
||||
* Added "encoding" option to Request#render(). Closes #299
|
||||
* Added "dump exceptions" setting, which is enabled by default.
|
||||
* Added simple ejs template engine support
|
||||
* Added error reponse support for text/plain, application/json. Closes #297
|
||||
* Added callback function param to Request#error()
|
||||
* Added Request#sendHead()
|
||||
* Added Request#stream()
|
||||
* Added support for Request#respond(304, null) for empty response bodies
|
||||
* Added ETag support to Request#sendfile()
|
||||
* Added options to Request#sendfile(), passed to fs.createReadStream()
|
||||
* Added filename arg to Request#download()
|
||||
* Performance enhanced due to pre-reversing plugins so that plugins.reverse() is not called on each request
|
||||
* Performance enhanced by preventing several calls to toLowerCase() in Router#match()
|
||||
* Changed; Request#sendfile() now streams
|
||||
* Changed; Renamed Request#halt() to Request#respond(). Closes #289
|
||||
* Changed; Using sys.inspect() instead of JSON.encode() for error output
|
||||
* Changed; run() returns the http.Server instance. Closes #298
|
||||
* Changed; Defaulting Server#host to null (INADDR_ANY)
|
||||
* Changed; Logger "common" format scale of 0.4f
|
||||
* Removed Logger "request" format
|
||||
* Fixed; Catching ENOENT in view caching, preventing error when "views/partials" is not found
|
||||
* Fixed several issues with http client
|
||||
* Fixed Logger Content-Length output
|
||||
* Fixed bug preventing Opera from retaining the generated session id. Closes #292
|
||||
|
||||
0.9.0 / 2010-04-14
|
||||
==================
|
||||
|
||||
* Added DSL level error() route support
|
||||
* Added DSL level notFound() route support
|
||||
* Added Request#error()
|
||||
* Added Request#notFound()
|
||||
* Added Request#render() callback function. Closes #258
|
||||
* Added "max upload size" setting
|
||||
* Added "magic" variables to collection partials (\_\_index\_\_, \_\_length\_\_, \_\_isFirst\_\_, \_\_isLast\_\_). Closes #254
|
||||
* Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js
|
||||
* Added callback function support to Request#halt() as 3rd/4th arg
|
||||
* Added preprocessing of route param wildcards using param(). Closes #251
|
||||
* Added view partial support (with collections etc)
|
||||
* Fixed bug preventing falsey params (such as ?page=0). Closes #286
|
||||
* Fixed setting of multiple cookies. Closes #199
|
||||
* Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml)
|
||||
* Changed; session cookie is now httpOnly
|
||||
* Changed; Request is no longer global
|
||||
* Changed; Event is no longer global
|
||||
* Changed; "sys" module is no longer global
|
||||
* Changed; moved Request#download to Static plugin where it belongs
|
||||
* Changed; Request instance created before body parsing. Closes #262
|
||||
* Changed; Pre-caching views in memory when "cache view contents" is enabled. Closes #253
|
||||
* Changed; Pre-caching view partials in memory when "cache view partials" is enabled
|
||||
* Updated support to node --version 0.1.90
|
||||
* Updated dependencies
|
||||
* Removed set("session cookie") in favour of use(Session, { cookie: { ... }})
|
||||
* Removed utils.mixin(); use Object#mergeDeep()
|
||||
|
||||
0.8.0 / 2010-03-19
|
||||
==================
|
||||
|
||||
* Added coffeescript example app. Closes #242
|
||||
* Changed; cache api now async friendly. Closes #240
|
||||
* Removed deprecated 'express/static' support. Use 'express/plugins/static'
|
||||
|
||||
0.7.6 / 2010-03-19
|
||||
==================
|
||||
|
||||
* Added Request#isXHR. Closes #229
|
||||
* Added `make install` (for the executable)
|
||||
* Added `express` executable for setting up simple app templates
|
||||
* Added "GET /public/*" to Static plugin, defaulting to <root>/public
|
||||
* Added Static plugin
|
||||
* Fixed; Request#render() only calls cache.get() once
|
||||
* Fixed; Namespacing View caches with "view:"
|
||||
* Fixed; Namespacing Static caches with "static:"
|
||||
* Fixed; Both example apps now use the Static plugin
|
||||
* Fixed set("views"). Closes #239
|
||||
* Fixed missing space for combined log format
|
||||
* Deprecated Request#sendfile() and 'express/static'
|
||||
* Removed Server#running
|
||||
|
||||
0.7.5 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Added Request#flash() support without args, now returns all flashes
|
||||
* Updated ext submodule
|
||||
|
||||
0.7.4 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Fixed session reaper
|
||||
* Changed; class.js replacing js-oo Class implementation (quite a bit faster, no browser cruft)
|
||||
|
||||
0.7.3 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Added package.json
|
||||
* Fixed requiring of haml / sass due to kiwi removal
|
||||
|
||||
0.7.2 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Fixed GIT submodules (HAH!)
|
||||
|
||||
0.7.1 / 2010-03-16
|
||||
==================
|
||||
|
||||
* Changed; Express now using submodules again until a PM is adopted
|
||||
* Changed; chat example using millisecond conversions from ext
|
||||
|
||||
0.7.0 / 2010-03-15
|
||||
==================
|
||||
|
||||
* Added Request#pass() support (finds the next matching route, or the given path)
|
||||
* Added Logger plugin (default "common" format replaces CommonLogger)
|
||||
* Removed Profiler plugin
|
||||
* Removed CommonLogger plugin
|
||||
|
||||
0.6.0 / 2010-03-11
|
||||
==================
|
||||
|
||||
* Added seed.yml for kiwi package management support
|
||||
* Added HTTP client query string support when method is GET. Closes #205
|
||||
|
||||
* Added support for arbitrary view engines.
|
||||
For example "foo.engine.html" will now require('engine'),
|
||||
the exports from this module are cached after the first require().
|
||||
|
||||
* Added async plugin support
|
||||
|
||||
* Removed usage of RESTful route funcs as http client
|
||||
get() etc, use http.get() and friends
|
||||
|
||||
* Removed custom exceptions
|
||||
|
||||
0.5.0 / 2010-03-10
|
||||
==================
|
||||
|
||||
* Added ext dependency (library of js extensions)
|
||||
* Removed extname() / basename() utils. Use path module
|
||||
* Removed toArray() util. Use arguments.values
|
||||
* Removed escapeRegexp() util. Use RegExp.escape()
|
||||
* Removed process.mixin() dependency. Use utils.mixin()
|
||||
* Removed Collection
|
||||
* Removed ElementCollection
|
||||
* Shameless self promotion of ebook "Advanced JavaScript" (http://dev-mag.com) ;)
|
||||
|
||||
0.4.0 / 2010-02-11
|
||||
==================
|
||||
|
||||
* Added flash() example to sample upload app
|
||||
* Added high level restful http client module (express/http)
|
||||
* Changed; RESTful route functions double as HTTP clients. Closes #69
|
||||
* Changed; throwing error when routes are added at runtime
|
||||
* Changed; defaulting render() context to the current Request. Closes #197
|
||||
* Updated haml submodule
|
||||
|
||||
0.3.0 / 2010-02-11
|
||||
==================
|
||||
|
||||
* Updated haml / sass submodules. Closes #200
|
||||
* Added flash message support. Closes #64
|
||||
* Added accepts() now allows multiple args. fixes #117
|
||||
* Added support for plugins to halt. Closes #189
|
||||
* Added alternate layout support. Closes #119
|
||||
* Removed Route#run(). Closes #188
|
||||
* Fixed broken specs due to use(Cookie) missing
|
||||
|
||||
0.2.1 / 2010-02-05
|
||||
==================
|
||||
|
||||
* Added "plot" format option for Profiler (for gnuplot processing)
|
||||
* Added request number to Profiler plugin
|
||||
* Fixed binary encoding for multi-part file uploads, was previously defaulting to UTF8
|
||||
* Fixed issue with routes not firing when not files are present. Closes #184
|
||||
* Fixed process.Promise -> events.Promise
|
||||
|
||||
0.2.0 / 2010-02-03
|
||||
==================
|
||||
|
||||
* Added parseParam() support for name[] etc. (allows for file inputs with "multiple" attr) Closes #180
|
||||
* Added Both Cache and Session option "reapInterval" may be "reapEvery". Closes #174
|
||||
* Added expiration support to cache api with reaper. Closes #133
|
||||
* Added cache Store.Memory#reap()
|
||||
* Added Cache; cache api now uses first class Cache instances
|
||||
* Added abstract session Store. Closes #172
|
||||
* Changed; cache Memory.Store#get() utilizing Collection
|
||||
* Renamed MemoryStore -> Store.Memory
|
||||
* Fixed use() of the same plugin several time will always use latest options. Closes #176
|
||||
|
||||
0.1.0 / 2010-02-03
|
||||
==================
|
||||
|
||||
* Changed; Hooks (before / after) pass request as arg as well as evaluated in their context
|
||||
* Updated node support to 0.1.27 Closes #169
|
||||
* Updated dirname(__filename) -> __dirname
|
||||
* Updated libxmljs support to v0.2.0
|
||||
* Added session support with memory store / reaping
|
||||
* Added quick uid() helper
|
||||
* Added multi-part upload support
|
||||
* Added Sass.js support / submodule
|
||||
* Added production env caching view contents and static files
|
||||
* Added static file caching. Closes #136
|
||||
* Added cache plugin with memory stores
|
||||
* Added support to StaticFile so that it works with non-textual files.
|
||||
* Removed dirname() helper
|
||||
* Removed several globals (now their modules must be required)
|
||||
|
||||
0.0.2 / 2010-01-10
|
||||
==================
|
||||
|
||||
* Added view benchmarks; currently haml vs ejs
|
||||
* Added Request#attachment() specs. Closes #116
|
||||
* Added use of node's parseQuery() util. Closes #123
|
||||
* Added `make init` for submodules
|
||||
* Updated Haml
|
||||
* Updated sample chat app to show messages on load
|
||||
* Updated libxmljs parseString -> parseHtmlString
|
||||
* Fixed `make init` to work with older versions of git
|
||||
* Fixed specs can now run independant specs for those who cant build deps. Closes #127
|
||||
* Fixed issues introduced by the node url module changes. Closes 126.
|
||||
* Fixed two assertions failing due to Collection#keys() returning strings
|
||||
* Fixed faulty Collection#toArray() spec due to keys() returning strings
|
||||
* Fixed `make test` now builds libxmljs.node before testing
|
||||
|
||||
0.0.1 / 2010-01-03
|
||||
==================
|
||||
|
||||
* Initial release
|
||||
22
example/node/node_modules/express/LICENSE
generated
vendored
Normal file
22
example/node/node_modules/express/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
29
example/node/node_modules/express/Makefile
generated
vendored
Normal file
29
example/node/node_modules/express/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
DOCS = $(shell find docs/*.md)
|
||||
HTMLDOCS = $(DOCS:.md=.html)
|
||||
TESTS = $(shell find test/*.test.js)
|
||||
|
||||
test:
|
||||
@NODE_ENV=test ./node_modules/.bin/expresso $(TESTS)
|
||||
|
||||
docs: $(HTMLDOCS)
|
||||
@ echo "... generating TOC"
|
||||
@./support/toc.js docs/guide.html
|
||||
|
||||
%.html: %.md
|
||||
@echo "... $< -> $@"
|
||||
@markdown $< \
|
||||
| cat docs/layout/head.html - docs/layout/foot.html \
|
||||
> $@
|
||||
|
||||
site:
|
||||
rm -fr /tmp/docs \
|
||||
&& cp -fr docs /tmp/docs \
|
||||
&& git checkout gh-pages \
|
||||
&& cp -fr /tmp/docs/* . \
|
||||
&& echo "done"
|
||||
|
||||
docclean:
|
||||
rm -f docs/*.{1,html}
|
||||
|
||||
.PHONY: site test docs docclean
|
||||
145
example/node/node_modules/express/Readme.md
generated
vendored
Normal file
145
example/node/node_modules/express/Readme.md
generated
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
|
||||
# Express
|
||||
|
||||
Insanely fast (and small) server-side JavaScript web development framework
|
||||
built on [node](http://nodejs.org) and [Connect](http://github.com/senchalabs/connect).
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
## Installation
|
||||
|
||||
$ npm install express
|
||||
|
||||
or to access the `express(1)` executable install globally:
|
||||
|
||||
$ npm install -g express
|
||||
|
||||
## Quick Start
|
||||
|
||||
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:
|
||||
|
||||
Create the app:
|
||||
|
||||
$ npm install -g express
|
||||
$ express /tmp/foo && cd /tmp/foo
|
||||
|
||||
Install dependencies:
|
||||
|
||||
$ npm install -d
|
||||
|
||||
Start the server:
|
||||
|
||||
$ node app.js
|
||||
|
||||
## Features
|
||||
|
||||
* Robust routing
|
||||
* Redirection helpers
|
||||
* Dynamic view helpers
|
||||
* Content negotiation
|
||||
* Focus on high performance
|
||||
* View rendering and partials support
|
||||
* Environment based configuration
|
||||
* Session based flash notifications
|
||||
* Built on [Connect](http://github.com/senchalabs/connect)
|
||||
* High test coverage
|
||||
* Executable for generating applications quickly
|
||||
* Application level view options
|
||||
|
||||
Via Connect:
|
||||
|
||||
* Session support
|
||||
* Cache API
|
||||
* Mime helpers
|
||||
* ETag support
|
||||
* Persistent flash notifications
|
||||
* Cookie support
|
||||
* JSON-RPC
|
||||
* Logging
|
||||
* and _much_ more!
|
||||
|
||||
## Contributors
|
||||
|
||||
The following are the major contributors of Express (in no specific order).
|
||||
|
||||
* TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
|
||||
* Ciaran Jessup ([ciaranj](http://github.com/ciaranj))
|
||||
* Aaron Heckmann ([aheckmann](http://github.com/aheckmann))
|
||||
* Guillermo Rauch ([guille](http://github.com/guille))
|
||||
|
||||
## More Information
|
||||
|
||||
* #express on freenode
|
||||
* [express-expose](http://github.com/visionmedia/express-expose) expose objects, functions, modules and more to client-side js with ease
|
||||
* [express-configure](http://github.com/visionmedia/express-configuration) async configuration support
|
||||
* [express-messages](http://github.com/visionmedia/express-messages) flash notification rendering helper
|
||||
* [express-namespace](http://github.com/visionmedia/express-namespace) namespaced route support
|
||||
* [express-params](https://github.com/visionmedia/express-params) param pre-condition functions
|
||||
* [express-mongoose](https://github.com/LearnBoost/express-mongoose) plugin for easy rendering of Mongoose async Query results
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* Screencast - [Introduction](http://bit.ly/eRYu0O)
|
||||
* Screencast - [View Partials](http://bit.ly/dU13Fx)
|
||||
* Screencast - [Route Specific Middleware](http://bit.ly/hX4IaH)
|
||||
* Screencast - [Route Path Placeholder Preconditions](http://bit.ly/eNqmVs)
|
||||
|
||||
## Node Compatibility
|
||||
|
||||
Express 1.x is compatible with node 0.2.x and connect < 1.0.
|
||||
|
||||
Express 2.x is compatible with node 0.4.x or 0.6.x, and connect 1.x
|
||||
|
||||
Express 3.x (master) will be compatible with node 0.6.x and connect 2.x
|
||||
|
||||
## Viewing Examples
|
||||
|
||||
First install the dev dependencies to install all the example / test suite deps:
|
||||
|
||||
$ npm install
|
||||
|
||||
then run whichever tests you want:
|
||||
|
||||
$ node examples/jade/app.js
|
||||
|
||||
## Running Tests
|
||||
|
||||
To run the test suite first invoke the following command within the repo, installing the development dependencies:
|
||||
|
||||
$ npm install
|
||||
|
||||
then run the tests:
|
||||
|
||||
$ make test
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
2
example/node/node_modules/express/index.js
generated
vendored
Normal file
2
example/node/node_modules/express/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
module.exports = require('./lib/express');
|
||||
79
example/node/node_modules/express/lib/express.js
generated
vendored
Normal file
79
example/node/node_modules/express/lib/express.js
generated
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
/*!
|
||||
* Express
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var connect = require('connect')
|
||||
, HTTPSServer = require('./https')
|
||||
, HTTPServer = require('./http')
|
||||
, Route = require('./router/route')
|
||||
|
||||
/**
|
||||
* Re-export connect auto-loaders.
|
||||
*
|
||||
* This prevents the need to `require('connect')` in order
|
||||
* to access core middleware, so for example `express.logger()` instead
|
||||
* of `require('connect').logger()`.
|
||||
*/
|
||||
|
||||
var exports = module.exports = connect.middleware;
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '2.5.8';
|
||||
|
||||
/**
|
||||
* Shortcut for `new Server(...)`.
|
||||
*
|
||||
* @param {Function} ...
|
||||
* @return {Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.createServer = function(options){
|
||||
if ('object' == typeof options) {
|
||||
return new HTTPSServer(options, Array.prototype.slice.call(arguments, 1));
|
||||
} else {
|
||||
return new HTTPServer(Array.prototype.slice.call(arguments));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose constructors.
|
||||
*/
|
||||
|
||||
exports.HTTPServer = HTTPServer;
|
||||
exports.HTTPSServer = HTTPSServer;
|
||||
exports.Route = Route;
|
||||
|
||||
/**
|
||||
* View extensions.
|
||||
*/
|
||||
|
||||
exports.View =
|
||||
exports.view = require('./view');
|
||||
|
||||
/**
|
||||
* Response extensions.
|
||||
*/
|
||||
|
||||
require('./response');
|
||||
|
||||
/**
|
||||
* Request extensions.
|
||||
*/
|
||||
|
||||
require('./request');
|
||||
|
||||
// Error handler title
|
||||
|
||||
exports.errorHandler.title = 'Express';
|
||||
|
||||
582
example/node/node_modules/express/lib/http.js
generated
vendored
Normal file
582
example/node/node_modules/express/lib/http.js
generated
vendored
Normal file
|
|
@ -0,0 +1,582 @@
|
|||
/*!
|
||||
* Express - HTTPServer
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var qs = require('qs')
|
||||
, connect = require('connect')
|
||||
, router = require('./router')
|
||||
, Router = require('./router')
|
||||
, view = require('./view')
|
||||
, toArray = require('./utils').toArray
|
||||
, methods = router.methods.concat('del', 'all')
|
||||
, url = require('url')
|
||||
, utils = connect.utils;
|
||||
|
||||
/**
|
||||
* Expose `HTTPServer`.
|
||||
*/
|
||||
|
||||
exports = module.exports = HTTPServer;
|
||||
|
||||
/**
|
||||
* Server proto.
|
||||
*/
|
||||
|
||||
var app = HTTPServer.prototype;
|
||||
|
||||
/**
|
||||
* Initialize a new `HTTPServer` with optional `middleware`.
|
||||
*
|
||||
* @param {Array} middleware
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function HTTPServer(middleware){
|
||||
connect.HTTPServer.call(this, []);
|
||||
this.init(middleware);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherit from `connect.HTTPServer`.
|
||||
*/
|
||||
|
||||
app.__proto__ = connect.HTTPServer.prototype;
|
||||
|
||||
/**
|
||||
* Initialize the server.
|
||||
*
|
||||
* @param {Array} middleware
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.init = function(middleware){
|
||||
var self = this;
|
||||
this.cache = {};
|
||||
this.settings = {};
|
||||
this.redirects = {};
|
||||
this.isCallbacks = {};
|
||||
this._locals = {};
|
||||
this.dynamicViewHelpers = {};
|
||||
this.errorHandlers = [];
|
||||
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
|
||||
// expose objects to each other
|
||||
this.use(function(req, res, next){
|
||||
req.query = req.query || {};
|
||||
res.setHeader('X-Powered-By', 'Express');
|
||||
req.app = res.app = self;
|
||||
req.res = res;
|
||||
res.req = req;
|
||||
req.next = next;
|
||||
// assign req.query
|
||||
if (req.url.indexOf('?') > 0) {
|
||||
var query = url.parse(req.url).query;
|
||||
req.query = qs.parse(query);
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// apply middleware
|
||||
if (middleware) middleware.forEach(self.use.bind(self));
|
||||
|
||||
// router
|
||||
this.routes = new Router(this);
|
||||
this.__defineGetter__('router', function(){
|
||||
this.__usedRouter = true;
|
||||
return self.routes.middleware;
|
||||
});
|
||||
|
||||
// default locals
|
||||
this.locals({
|
||||
settings: this.settings
|
||||
, app: this
|
||||
});
|
||||
|
||||
// default development configuration
|
||||
this.configure('development', function(){
|
||||
this.enable('hints');
|
||||
});
|
||||
|
||||
// default production configuration
|
||||
this.configure('production', function(){
|
||||
this.enable('view cache');
|
||||
});
|
||||
|
||||
// register error handlers on "listening"
|
||||
// so that they disregard definition position.
|
||||
this.on('listening', this.registerErrorHandlers.bind(this));
|
||||
|
||||
// route manipulation methods
|
||||
methods.forEach(function(method){
|
||||
self.lookup[method] = function(path){
|
||||
return self.routes.lookup(method, path);
|
||||
};
|
||||
|
||||
self.match[method] = function(path){
|
||||
return self.routes.match(method, path);
|
||||
};
|
||||
|
||||
self.remove[method] = function(path){
|
||||
return self.routes.lookup(method, path).remove();
|
||||
};
|
||||
});
|
||||
|
||||
// del -> delete
|
||||
self.lookup.del = self.lookup.delete;
|
||||
self.match.del = self.match.delete;
|
||||
self.remove.del = self.remove.delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove routes matching the given `path`.
|
||||
*
|
||||
* @param {Route} path
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.remove = function(path){
|
||||
return this.routes.lookup('all', path).remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup routes defined with a path
|
||||
* equivalent to `path`.
|
||||
*
|
||||
* @param {Stirng} path
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.lookup = function(path){
|
||||
return this.routes.lookup('all', path);
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup routes matching the given `url`.
|
||||
*
|
||||
* @param {Stirng} url
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.match = function(url){
|
||||
return this.routes.match('all', url);
|
||||
};
|
||||
|
||||
/**
|
||||
* When using the vhost() middleware register error handlers.
|
||||
*/
|
||||
|
||||
app.onvhost = function(){
|
||||
this.registerErrorHandlers();
|
||||
};
|
||||
|
||||
/**
|
||||
* Register error handlers.
|
||||
*
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.registerErrorHandlers = function(){
|
||||
this.errorHandlers.forEach(function(fn){
|
||||
this.use(function(err, req, res, next){
|
||||
fn.apply(this, arguments);
|
||||
});
|
||||
}, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy `connect.HTTPServer#use()` to apply settings to
|
||||
* mounted applications.
|
||||
*
|
||||
* @param {String|Function|Server} route
|
||||
* @param {Function|Server} middleware
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.use = function(route, middleware){
|
||||
var app, base, handle;
|
||||
|
||||
if ('string' != typeof route) {
|
||||
middleware = route, route = '/';
|
||||
}
|
||||
|
||||
// express app
|
||||
if (middleware.handle && middleware.set) app = middleware;
|
||||
|
||||
// restore .app property on req and res
|
||||
if (app) {
|
||||
app.route = route;
|
||||
middleware = function(req, res, next) {
|
||||
var orig = req.app;
|
||||
app.handle(req, res, function(err){
|
||||
req.app = res.app = orig;
|
||||
next(err);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
connect.HTTPServer.prototype.use.call(this, route, middleware);
|
||||
|
||||
// mounted an app, invoke the hook
|
||||
// and adjust some settings
|
||||
if (app) {
|
||||
base = this.set('basepath') || this.route;
|
||||
if ('/' == base) base = '';
|
||||
base = base + (app.set('basepath') || app.route);
|
||||
app.set('basepath', base);
|
||||
app.parent = this;
|
||||
if (app.__mounted) app.__mounted.call(app, this);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign a callback `fn` which is called
|
||||
* when this `Server` is passed to `Server#use()`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var app = express.createServer()
|
||||
* , blog = express.createServer();
|
||||
*
|
||||
* blog.mounted(function(parent){
|
||||
* // parent is app
|
||||
* // "this" is blog
|
||||
* });
|
||||
*
|
||||
* app.use(blog);
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.mounted = function(fn){
|
||||
this.__mounted = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* See: view.register.
|
||||
*
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.register = function(){
|
||||
view.register.apply(this, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given view helpers `obj`. This method
|
||||
* can be called several times to apply additional helpers.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.helpers =
|
||||
app.locals = function(obj){
|
||||
utils.merge(this._locals, obj);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given dynamic view helpers `obj`. This method
|
||||
* can be called several times to apply additional helpers.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.dynamicHelpers = function(obj){
|
||||
utils.merge(this.dynamicViewHelpers, obj);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map the given param placeholder `name`(s) to the given callback(s).
|
||||
*
|
||||
* Param mapping is used to provide pre-conditions to routes
|
||||
* which us normalized placeholders. This callback has the same
|
||||
* signature as regular middleware, for example below when ":userId"
|
||||
* is used this function will be invoked in an attempt to load the user.
|
||||
*
|
||||
* app.param('userId', function(req, res, next, id){
|
||||
* User.find(id, function(err, user){
|
||||
* if (err) {
|
||||
* next(err);
|
||||
* } else if (user) {
|
||||
* req.user = user;
|
||||
* next();
|
||||
* } else {
|
||||
* next(new Error('failed to load user'));
|
||||
* }
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* Passing a single function allows you to map logic
|
||||
* to the values passed to `app.param()`, for example
|
||||
* this is useful to provide coercion support in a concise manner.
|
||||
*
|
||||
* The following example maps regular expressions to param values
|
||||
* ensuring that they match, otherwise passing control to the next
|
||||
* route:
|
||||
*
|
||||
* app.param(function(name, regexp){
|
||||
* if (regexp instanceof RegExp) {
|
||||
* return function(req, res, next, val){
|
||||
* var captures;
|
||||
* if (captures = regexp.exec(String(val))) {
|
||||
* req.params[name] = captures;
|
||||
* next();
|
||||
* } else {
|
||||
* next('route');
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* We can now use it as shown below, where "/commit/:commit" expects
|
||||
* that the value for ":commit" is at 5 or more digits. The capture
|
||||
* groups are then available as `req.params.commit` as we defined
|
||||
* in the function above.
|
||||
*
|
||||
* app.param('commit', /^\d{5,}$/);
|
||||
*
|
||||
* For more of this useful functionality take a look
|
||||
* at [express-params](http://github.com/visionmedia/express-params).
|
||||
*
|
||||
* @param {String|Array|Function} name
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.param = function(name, fn){
|
||||
var self = this
|
||||
, fns = [].slice.call(arguments, 1);
|
||||
|
||||
// array
|
||||
if (Array.isArray(name)) {
|
||||
name.forEach(function(name){
|
||||
fns.forEach(function(fn){
|
||||
self.param(name, fn);
|
||||
});
|
||||
});
|
||||
// param logic
|
||||
} else if ('function' == typeof name) {
|
||||
this.routes.param(name);
|
||||
// single
|
||||
} else {
|
||||
if (':' == name[0]) name = name.substr(1);
|
||||
fns.forEach(function(fn){
|
||||
self.routes.param(name, fn);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign a custom exception handler callback `fn`.
|
||||
* These handlers are always _last_ in the middleware stack.
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.error = function(fn){
|
||||
this.errorHandlers.push(fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given callback `fn` for the given `type`.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.is = function(type, fn){
|
||||
if (!fn) return this.isCallbacks[type];
|
||||
this.isCallbacks[type] = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign `setting` to `val`, or return `setting`'s value.
|
||||
* Mounted servers inherit their parent server's settings.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @param {String} val
|
||||
* @return {Server|Mixed} for chaining, or the setting value
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.set = function(setting, val){
|
||||
if (val === undefined) {
|
||||
if (this.settings.hasOwnProperty(setting)) {
|
||||
return this.settings[setting];
|
||||
} else if (this.parent) {
|
||||
return this.parent.set(setting);
|
||||
}
|
||||
} else {
|
||||
this.settings[setting] = val;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `setting` is enabled.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.enabled = function(setting){
|
||||
return !!this.set(setting);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `setting` is disabled.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.disabled = function(setting){
|
||||
return !this.set(setting);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable `setting`.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.enable = function(setting){
|
||||
return this.set(setting, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable `setting`.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.disable = function(setting){
|
||||
return this.set(setting, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Redirect `key` to `url`.
|
||||
*
|
||||
* @param {String} key
|
||||
* @param {String} url
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.redirect = function(key, url){
|
||||
this.redirects[key] = url;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure callback for zero or more envs,
|
||||
* when no env is specified that callback will
|
||||
* be invoked for all environments. Any combination
|
||||
* can be used multiple times, in any order desired.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* app.configure(function(){
|
||||
* // executed for all envs
|
||||
* });
|
||||
*
|
||||
* app.configure('stage', function(){
|
||||
* // executed staging env
|
||||
* });
|
||||
*
|
||||
* app.configure('stage', 'production', function(){
|
||||
* // executed for stage and production
|
||||
* });
|
||||
*
|
||||
* @param {String} env...
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.configure = function(env, fn){
|
||||
var envs = 'all'
|
||||
, args = toArray(arguments);
|
||||
fn = args.pop();
|
||||
if (args.length) envs = args;
|
||||
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delegate `.VERB(...)` calls to `.route(VERB, ...)`.
|
||||
*/
|
||||
|
||||
methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
if (1 == arguments.length) return this.routes.lookup(method, path);
|
||||
var args = [method].concat(toArray(arguments));
|
||||
if (!this.__usedRouter) this.use(this.router);
|
||||
return this.routes._route.apply(this.routes, args);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Special-cased "all" method, applying the given route `path`,
|
||||
* middleware, and callback to _every_ HTTP method.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} ...
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.all = function(path){
|
||||
var args = arguments;
|
||||
if (1 == args.length) return this.routes.lookup('all', path);
|
||||
methods.forEach(function(method){
|
||||
if ('all' == method || 'del' == method) return;
|
||||
app[method].apply(this, args);
|
||||
}, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
// del -> delete alias
|
||||
|
||||
app.del = app.delete;
|
||||
|
||||
52
example/node/node_modules/express/lib/https.js
generated
vendored
Normal file
52
example/node/node_modules/express/lib/https.js
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
/*!
|
||||
* Express - HTTPSServer
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var connect = require('connect')
|
||||
, HTTPServer = require('./http')
|
||||
, https = require('https');
|
||||
|
||||
/**
|
||||
* Expose `HTTPSServer`.
|
||||
*/
|
||||
|
||||
exports = module.exports = HTTPSServer;
|
||||
|
||||
/**
|
||||
* Server proto.
|
||||
*/
|
||||
|
||||
var app = HTTPSServer.prototype;
|
||||
|
||||
/**
|
||||
* Initialize a new `HTTPSServer` with the
|
||||
* given `options`, and optional `middleware`.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {Array} middleware
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function HTTPSServer(options, middleware){
|
||||
connect.HTTPSServer.call(this, options, []);
|
||||
this.init(middleware);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherit from `connect.HTTPSServer`.
|
||||
*/
|
||||
|
||||
app.__proto__ = connect.HTTPSServer.prototype;
|
||||
|
||||
// mixin HTTPServer methods
|
||||
|
||||
Object.keys(HTTPServer.prototype).forEach(function(method){
|
||||
app[method] = HTTPServer.prototype[method];
|
||||
});
|
||||
323
example/node/node_modules/express/lib/request.js
generated
vendored
Normal file
323
example/node/node_modules/express/lib/request.js
generated
vendored
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
|
||||
/*!
|
||||
* Express - request
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http')
|
||||
, req = http.IncomingMessage.prototype
|
||||
, utils = require('./utils')
|
||||
, parse = require('url').parse
|
||||
, mime = require('mime');
|
||||
|
||||
/**
|
||||
* Default flash formatters.
|
||||
*
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
var flashFormatters = exports.flashFormatters = {
|
||||
s: function(val){
|
||||
return String(val);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return request header or optional default.
|
||||
*
|
||||
* The `Referrer` header field is special-cased,
|
||||
* both `Referrer` and `Referer` will yield are
|
||||
* interchangeable.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* req.header('Content-Type');
|
||||
* // => "text/plain"
|
||||
*
|
||||
* req.header('content-type');
|
||||
* // => "text/plain"
|
||||
*
|
||||
* req.header('Accept');
|
||||
* // => undefined
|
||||
*
|
||||
* req.header('Accept', 'text/html');
|
||||
* // => "text/html"
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} defaultValue
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.header = function(name, defaultValue){
|
||||
switch (name = name.toLowerCase()) {
|
||||
case 'referer':
|
||||
case 'referrer':
|
||||
return this.headers.referrer
|
||||
|| this.headers.referer
|
||||
|| defaultValue;
|
||||
default:
|
||||
return this.headers[name] || defaultValue;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get `field`'s `param` value, defaulting to ''.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* req.get('content-disposition', 'filename');
|
||||
* // => "something.png"
|
||||
*
|
||||
* @param {String} field
|
||||
* @param {String} param
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.get = function(field, param){
|
||||
var val = this.header(field);
|
||||
if (!val) return '';
|
||||
var regexp = new RegExp(param + ' *= *(?:"([^"]+)"|([^;]+))', 'i');
|
||||
if (!regexp.exec(val)) return '';
|
||||
return RegExp.$1 || RegExp.$2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Short-hand for `require('url').parse(req.url).pathname`.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('path', function(){
|
||||
return parse(this.url).pathname;
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the _Accept_ header is present, and includes the given `type`.
|
||||
*
|
||||
* When the _Accept_ header is not present `true` is returned. Otherwise
|
||||
* the given `type` is matched by an exact match, and then subtypes. You
|
||||
* may pass the subtype such as "html" which is then converted internally
|
||||
* to "text/html" using the mime lookup table.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* // Accept: text/html
|
||||
* req.accepts('html');
|
||||
* // => true
|
||||
*
|
||||
* // Accept: text/*; application/json
|
||||
* req.accepts('html');
|
||||
* req.accepts('text/html');
|
||||
* req.accepts('text/plain');
|
||||
* req.accepts('application/json');
|
||||
* // => true
|
||||
*
|
||||
* req.accepts('image/png');
|
||||
* req.accepts('png');
|
||||
* // => false
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.accepts = function(type){
|
||||
var accept = this.header('Accept');
|
||||
|
||||
// normalize extensions ".json" -> "json"
|
||||
if (type && '.' == type[0]) type = type.substr(1);
|
||||
|
||||
// when Accept does not exist, or is '*/*' return true
|
||||
if (!accept || '*/*' == accept) {
|
||||
return true;
|
||||
} else if (type) {
|
||||
// allow "html" vs "text/html" etc
|
||||
if (!~type.indexOf('/')) type = mime.lookup(type);
|
||||
|
||||
// check if we have a direct match
|
||||
if (~accept.indexOf(type)) return true;
|
||||
|
||||
// check if we have type/*
|
||||
type = type.split('/')[0] + '/*';
|
||||
return !!~accept.indexOf(type);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the value of param `name` when present or `defaultValue`.
|
||||
*
|
||||
* - Checks route placeholders, ex: _/user/:id_
|
||||
* - Checks query string params, ex: ?id=12
|
||||
* - Checks urlencoded body params, ex: id=12
|
||||
*
|
||||
* To utilize urlencoded request bodies, `req.body`
|
||||
* should be an object. This can be done by using
|
||||
* the `connect.bodyParser` middleware.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Mixed} defaultValue
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.param = function(name, defaultValue){
|
||||
// route params like /user/:id
|
||||
if (this.params && this.params.hasOwnProperty(name) && undefined !== this.params[name]) {
|
||||
return this.params[name];
|
||||
}
|
||||
// query string params
|
||||
if (undefined !== this.query[name]) {
|
||||
return this.query[name];
|
||||
}
|
||||
// request body params via connect.bodyParser
|
||||
if (this.body && undefined !== this.body[name]) {
|
||||
return this.body[name];
|
||||
}
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Queue flash `msg` of the given `type`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* req.flash('info', 'email sent');
|
||||
* req.flash('error', 'email delivery failed');
|
||||
* req.flash('info', 'email re-sent');
|
||||
* // => 2
|
||||
*
|
||||
* req.flash('info');
|
||||
* // => ['email sent', 'email re-sent']
|
||||
*
|
||||
* req.flash('info');
|
||||
* // => []
|
||||
*
|
||||
* req.flash();
|
||||
* // => { error: ['email delivery failed'], info: [] }
|
||||
*
|
||||
* Formatting:
|
||||
*
|
||||
* Flash notifications also support arbitrary formatting support.
|
||||
* For example you may pass variable arguments to `req.flash()`
|
||||
* and use the %s specifier to be replaced by the associated argument:
|
||||
*
|
||||
* req.flash('info', 'email has been sent to %s.', userName);
|
||||
*
|
||||
* To add custom formatters use the `exports.flashFormatters` object.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} msg
|
||||
* @return {Array|Object|Number}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.flash = function(type, msg){
|
||||
if (this.session === undefined) throw Error('req.flash() requires sessions');
|
||||
var msgs = this.session.flash = this.session.flash || {};
|
||||
if (type && msg) {
|
||||
var i = 2
|
||||
, args = arguments
|
||||
, formatters = this.app.flashFormatters || {};
|
||||
formatters.__proto__ = flashFormatters;
|
||||
msg = utils.miniMarkdown(msg);
|
||||
msg = msg.replace(/%([a-zA-Z])/g, function(_, format){
|
||||
var formatter = formatters[format];
|
||||
if (formatter) return formatter(utils.escape(args[i++]));
|
||||
});
|
||||
return (msgs[type] = msgs[type] || []).push(msg);
|
||||
} else if (type) {
|
||||
var arr = msgs[type];
|
||||
delete msgs[type];
|
||||
return arr || [];
|
||||
} else {
|
||||
this.session.flash = {};
|
||||
return msgs;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the incoming request contains the "Content-Type"
|
||||
* header field, and it contains the give mime `type`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* // With Content-Type: text/html; charset=utf-8
|
||||
* req.is('html');
|
||||
* req.is('text/html');
|
||||
* // => true
|
||||
*
|
||||
* // When Content-Type is application/json
|
||||
* req.is('json');
|
||||
* req.is('application/json');
|
||||
* // => true
|
||||
*
|
||||
* req.is('html');
|
||||
* // => false
|
||||
*
|
||||
* Ad-hoc callbacks can also be registered with Express, to perform
|
||||
* assertions again the request, for example if we need an expressive
|
||||
* way to check if our incoming request is an image, we can register "an image"
|
||||
* callback:
|
||||
*
|
||||
* app.is('an image', function(req){
|
||||
* return 0 == req.headers['content-type'].indexOf('image');
|
||||
* });
|
||||
*
|
||||
* Now within our route callbacks, we can use to to assert content types
|
||||
* such as "image/jpeg", "image/png", etc.
|
||||
*
|
||||
* app.post('/image/upload', function(req, res, next){
|
||||
* if (req.is('an image')) {
|
||||
* // do something
|
||||
* } else {
|
||||
* next();
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.is = function(type){
|
||||
var fn = this.app.is(type);
|
||||
if (fn) return fn(this);
|
||||
var ct = this.headers['content-type'];
|
||||
if (!ct) return false;
|
||||
ct = ct.split(';')[0];
|
||||
if (!~type.indexOf('/')) type = mime.lookup(type);
|
||||
if (~type.indexOf('*')) {
|
||||
type = type.split('/');
|
||||
ct = ct.split('/');
|
||||
if ('*' == type[0] && type[1] == ct[1]) return true;
|
||||
if ('*' == type[1] && type[0] == ct[0]) return true;
|
||||
return false;
|
||||
}
|
||||
return !! ~ct.indexOf(type);
|
||||
};
|
||||
|
||||
// Callback for isXMLHttpRequest / xhr
|
||||
|
||||
function isxhr() {
|
||||
return this.header('X-Requested-With', '').toLowerCase() === 'xmlhttprequest';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the request was an _XMLHttpRequest_.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('isXMLHttpRequest', isxhr);
|
||||
req.__defineGetter__('xhr', isxhr);
|
||||
460
example/node/node_modules/express/lib/response.js
generated
vendored
Normal file
460
example/node/node_modules/express/lib/response.js
generated
vendored
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
|
||||
/*!
|
||||
* Express - response
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, http = require('http')
|
||||
, path = require('path')
|
||||
, connect = require('connect')
|
||||
, utils = connect.utils
|
||||
, parseRange = require('./utils').parseRange
|
||||
, res = http.ServerResponse.prototype
|
||||
, send = connect.static.send
|
||||
, mime = require('mime')
|
||||
, basename = path.basename
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
* Send a response with the given `body` and optional `headers` and `status` code.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.send();
|
||||
* res.send(new Buffer('wahoo'));
|
||||
* res.send({ some: 'json' });
|
||||
* res.send('<p>some html</p>');
|
||||
* res.send('Sorry, cant find that', 404);
|
||||
* res.send('text', { 'Content-Type': 'text/plain' }, 201);
|
||||
* res.send(404);
|
||||
*
|
||||
* @param {String|Object|Number|Buffer} body or status
|
||||
* @param {Object|Number} headers or status
|
||||
* @param {Number} status
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.send = function(body, headers, status){
|
||||
// allow status as second arg
|
||||
if ('number' == typeof headers) {
|
||||
status = headers,
|
||||
headers = null;
|
||||
}
|
||||
|
||||
// default status
|
||||
status = status || this.statusCode;
|
||||
|
||||
// allow 0 args as 204
|
||||
if (!arguments.length || undefined === body) status = 204;
|
||||
|
||||
// determine content type
|
||||
switch (typeof body) {
|
||||
case 'number':
|
||||
if (!this.header('Content-Type')) {
|
||||
this.contentType('.txt');
|
||||
}
|
||||
body = http.STATUS_CODES[status = body];
|
||||
break;
|
||||
case 'string':
|
||||
if (!this.header('Content-Type')) {
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.contentType('.html');
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'object':
|
||||
if (Buffer.isBuffer(body)) {
|
||||
if (!this.header('Content-Type')) {
|
||||
this.contentType('.bin');
|
||||
}
|
||||
} else {
|
||||
return this.json(body, headers, status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// populate Content-Length
|
||||
if (undefined !== body && !this.header('Content-Length')) {
|
||||
this.header('Content-Length', Buffer.isBuffer(body)
|
||||
? body.length
|
||||
: Buffer.byteLength(body));
|
||||
}
|
||||
|
||||
// merge headers passed
|
||||
if (headers) {
|
||||
var fields = Object.keys(headers);
|
||||
for (var i = 0, len = fields.length; i < len; ++i) {
|
||||
var field = fields[i];
|
||||
this.header(field, headers[field]);
|
||||
}
|
||||
}
|
||||
|
||||
// strip irrelevant headers
|
||||
if (204 == status || 304 == status) {
|
||||
this.removeHeader('Content-Type');
|
||||
this.removeHeader('Content-Length');
|
||||
body = '';
|
||||
}
|
||||
|
||||
// respond
|
||||
this.statusCode = status;
|
||||
this.end('HEAD' == this.req.method ? null : body);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send JSON response with `obj`, optional `headers`, and optional `status`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.json(null);
|
||||
* res.json({ user: 'tj' });
|
||||
* res.json('oh noes!', 500);
|
||||
* res.json('I dont have that', 404);
|
||||
*
|
||||
* @param {Mixed} obj
|
||||
* @param {Object|Number} headers or status
|
||||
* @param {Number} status
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.json = function(obj, headers, status){
|
||||
var body = JSON.stringify(obj)
|
||||
, callback = this.req.query.callback
|
||||
, jsonp = this.app.enabled('jsonp callback');
|
||||
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.header('Content-Type', 'application/json');
|
||||
|
||||
if (callback && jsonp) {
|
||||
this.header('Content-Type', 'text/javascript');
|
||||
body = callback.replace(/[^\w$.]/g, '') + '(' + body + ');';
|
||||
}
|
||||
|
||||
return this.send(body, headers, status);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set status `code`.
|
||||
*
|
||||
* @param {Number} code
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.status = function(code){
|
||||
this.statusCode = code;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfer the file at the given `path`. Automatically sets
|
||||
* the _Content-Type_ response header field. `next()` is called
|
||||
* when `path` is a directory, or when an error occurs.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` defaulting to 0
|
||||
* - `root` root directory for relative filenames
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Object|Function} options or fn
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.sendfile = function(path, options, fn){
|
||||
var next = this.req.next;
|
||||
options = options || {};
|
||||
|
||||
// support function as second arg
|
||||
if ('function' == typeof options) {
|
||||
fn = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
options.path = encodeURIComponent(path);
|
||||
options.callback = fn;
|
||||
send(this.req, this, next, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set _Content-Type_ response header passed through `mime.lookup()`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var filename = 'path/to/image.png';
|
||||
* res.contentType(filename);
|
||||
* // res.headers['Content-Type'] is now "image/png"
|
||||
*
|
||||
* res.contentType('.html');
|
||||
* res.contentType('html');
|
||||
* res.contentType('json');
|
||||
* res.contentType('png');
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {String} the resolved mime type
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.contentType = function(type){
|
||||
return this.header('Content-Type', mime.lookup(type));
|
||||
};
|
||||
|
||||
/**
|
||||
* Set _Content-Disposition_ header to _attachment_ with optional `filename`.
|
||||
*
|
||||
* @param {String} filename
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.attachment = function(filename){
|
||||
if (filename) this.contentType(filename);
|
||||
this.header('Content-Disposition', filename
|
||||
? 'attachment; filename="' + basename(filename) + '"'
|
||||
: 'attachment');
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfer the file at the given `path`, with optional
|
||||
* `filename` as an attachment and optional callback `fn(err)`,
|
||||
* and optional `fn2(err)` which is invoked when an error has
|
||||
* occurred after header has been sent.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String|Function} filename or fn
|
||||
* @param {Function} fn
|
||||
* @param {Function} fn2
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.download = function(path, filename, fn, fn2){
|
||||
var self = this;
|
||||
|
||||
// support callback as second arg
|
||||
if ('function' == typeof filename) {
|
||||
fn2 = fn;
|
||||
fn = filename;
|
||||
filename = null;
|
||||
}
|
||||
|
||||
// transfer the file
|
||||
this.attachment(filename || path).sendfile(path, function(err){
|
||||
var sentHeader = self._header;
|
||||
if (err) {
|
||||
if (!sentHeader) self.removeHeader('Content-Disposition');
|
||||
if (sentHeader) {
|
||||
fn2 && fn2(err);
|
||||
} else if (fn) {
|
||||
fn(err);
|
||||
} else {
|
||||
self.req.next(err);
|
||||
}
|
||||
} else if (fn) {
|
||||
fn();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Set or get response header `name` with optional `val`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} val
|
||||
* @return {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.header = function(name, val){
|
||||
if (1 == arguments.length) return this.getHeader(name);
|
||||
this.setHeader(name, val);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear cookie `name`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.clearCookie = function(name, options){
|
||||
var opts = { expires: new Date(1) };
|
||||
this.cookie(name, '', options
|
||||
? utils.merge(options, opts)
|
||||
: opts);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set cookie `name` to `val`, with the given `options`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` max-age in milliseconds, converted to `expires`
|
||||
* - `path` defaults to the "basepath" setting which is typically "/"
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* // "Remember Me" for 15 minutes
|
||||
* res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||
*
|
||||
* // save as above
|
||||
* res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} val
|
||||
* @param {Options} options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.cookie = function(name, val, options){
|
||||
options = options || {};
|
||||
if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge);
|
||||
if (undefined === options.path) options.path = this.app.set('basepath');
|
||||
var cookie = utils.serializeCookie(name, val, options);
|
||||
this.header('Set-Cookie', cookie);
|
||||
};
|
||||
|
||||
/**
|
||||
* Redirect to the given `url` with optional response `status`
|
||||
* defauling to 302.
|
||||
*
|
||||
* The given `url` can also be the name of a mapped url, for
|
||||
* example by default express supports "back" which redirects
|
||||
* to the _Referrer_ or _Referer_ headers or the application's
|
||||
* "basepath" setting. Express also supports "basepath" out of the box,
|
||||
* which can be set via `app.set('basepath', '/blog');`, and defaults
|
||||
* to '/'.
|
||||
*
|
||||
* Redirect Mapping:
|
||||
*
|
||||
* To extend the redirect mapping capabilities that Express provides,
|
||||
* we may use the `app.redirect()` method:
|
||||
*
|
||||
* app.redirect('google', 'http://google.com');
|
||||
*
|
||||
* Now in a route we may call:
|
||||
*
|
||||
* res.redirect('google');
|
||||
*
|
||||
* We may also map dynamic redirects:
|
||||
*
|
||||
* app.redirect('comments', function(req, res){
|
||||
* return '/post/' + req.params.id + '/comments';
|
||||
* });
|
||||
*
|
||||
* So now we may do the following, and the redirect will dynamically adjust to
|
||||
* the context of the request. If we called this route with _GET /post/12_ our
|
||||
* redirect _Location_ would be _/post/12/comments_.
|
||||
*
|
||||
* app.get('/post/:id', function(req, res){
|
||||
* res.redirect('comments');
|
||||
* });
|
||||
*
|
||||
* Unless an absolute `url` is given, the app's mount-point
|
||||
* will be respected. For example if we redirect to `/posts`,
|
||||
* and our app is mounted at `/blog` we will redirect to `/blog/posts`.
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {Number} code
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.redirect = function(url, status){
|
||||
var app = this.app
|
||||
, req = this.req
|
||||
, base = app.set('basepath') || app.route
|
||||
, status = status || 302
|
||||
, head = 'HEAD' == req.method
|
||||
, body;
|
||||
|
||||
// Setup redirect map
|
||||
var map = {
|
||||
back: req.header('Referrer', base)
|
||||
, home: base
|
||||
};
|
||||
|
||||
// Support custom redirect map
|
||||
map.__proto__ = app.redirects;
|
||||
|
||||
// Attempt mapped redirect
|
||||
var mapped = 'function' == typeof map[url]
|
||||
? map[url](req, this)
|
||||
: map[url];
|
||||
|
||||
// Perform redirect
|
||||
url = mapped || url;
|
||||
|
||||
// Relative
|
||||
if (!~url.indexOf('://')) {
|
||||
// Respect mount-point
|
||||
if ('/' != base && 0 != url.indexOf(base)) url = base + url;
|
||||
|
||||
// Absolute
|
||||
var host = req.headers.host
|
||||
, tls = req.connection.encrypted;
|
||||
url = 'http' + (tls ? 's' : '') + '://' + host + url;
|
||||
}
|
||||
|
||||
// Support text/{plain,html} by default
|
||||
if (req.accepts('html')) {
|
||||
body = '<p>' + http.STATUS_CODES[status] + '. Redirecting to <a href="' + url + '">' + url + '</a></p>';
|
||||
this.header('Content-Type', 'text/html');
|
||||
} else {
|
||||
body = http.STATUS_CODES[status] + '. Redirecting to ' + url;
|
||||
this.header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
// Respond
|
||||
this.statusCode = status;
|
||||
this.header('Location', url);
|
||||
this.end(head ? null : body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign the view local variable `name` to `val` or return the
|
||||
* local previously assigned to `name`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Mixed} val
|
||||
* @return {Mixed} val
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.local = function(name, val){
|
||||
this._locals = this._locals || {};
|
||||
return undefined === val
|
||||
? this._locals[name]
|
||||
: this._locals[name] = val;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign several locals with the given `obj`,
|
||||
* or return the locals.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Object|Undefined}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.locals =
|
||||
res.helpers = function(obj){
|
||||
if (obj) {
|
||||
for (var key in obj) {
|
||||
this.local(key, obj[key]);
|
||||
}
|
||||
} else {
|
||||
return this._locals;
|
||||
}
|
||||
};
|
||||
53
example/node/node_modules/express/lib/router/collection.js
generated
vendored
Normal file
53
example/node/node_modules/express/lib/router/collection.js
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
/*!
|
||||
* Express - router - Collection
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Expose `Collection`.
|
||||
*/
|
||||
|
||||
module.exports = Collection;
|
||||
|
||||
/**
|
||||
* Initialize a new route `Collection`
|
||||
* with the given `router`.
|
||||
*
|
||||
* @param {Router} router
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Collection(router) {
|
||||
Array.apply(this, arguments);
|
||||
this.router = router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherit from `Array.prototype`.
|
||||
*/
|
||||
|
||||
Collection.prototype.__proto__ = Array.prototype;
|
||||
|
||||
/**
|
||||
* Remove the routes in this collection.
|
||||
*
|
||||
* @return {Collection} of routes removed
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Collection.prototype.remove = function(){
|
||||
var router = this.router
|
||||
, len = this.length
|
||||
, ret = new Collection(this.router);
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (router.remove(this[i])) {
|
||||
ret.push(this[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
398
example/node/node_modules/express/lib/router/index.js
generated
vendored
Normal file
398
example/node/node_modules/express/lib/router/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
|
||||
/*!
|
||||
* Express - Router
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Route = require('./route')
|
||||
, Collection = require('./collection')
|
||||
, utils = require('../utils')
|
||||
, parse = require('url').parse
|
||||
, toArray = utils.toArray;
|
||||
|
||||
/**
|
||||
* Expose `Router` constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = Router;
|
||||
|
||||
/**
|
||||
* Expose HTTP methods.
|
||||
*/
|
||||
|
||||
var methods = exports.methods = require('./methods');
|
||||
|
||||
/**
|
||||
* Initialize a new `Router` with the given `app`.
|
||||
*
|
||||
* @param {express.HTTPServer} app
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Router(app) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.routes = {};
|
||||
this.params = {};
|
||||
this._params = [];
|
||||
|
||||
this.middleware = function(req, res, next){
|
||||
self._dispatch(req, res, next);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a param callback `fn` for the given `name`.
|
||||
*
|
||||
* @param {String|Function} name
|
||||
* @param {Function} fn
|
||||
* @return {Router} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.param = function(name, fn){
|
||||
// param logic
|
||||
if ('function' == typeof name) {
|
||||
this._params.push(name);
|
||||
return;
|
||||
}
|
||||
|
||||
// apply param functions
|
||||
var params = this._params
|
||||
, len = params.length
|
||||
, ret;
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (ret = params[i](name, fn)) {
|
||||
fn = ret;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure we end up with a
|
||||
// middleware function
|
||||
if ('function' != typeof fn) {
|
||||
throw new Error('invalid param() call for ' + name + ', got ' + fn);
|
||||
}
|
||||
|
||||
(this.params[name] = this.params[name] || []).push(fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a `Collection` of all routes defined.
|
||||
*
|
||||
* @return {Collection}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.all = function(){
|
||||
return this.find(function(){
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the given `route`, returns
|
||||
* a bool indicating if the route was present
|
||||
* or not.
|
||||
*
|
||||
* @param {Route} route
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.remove = function(route){
|
||||
var routes = this.routes[route.method]
|
||||
, len = routes.length;
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (route == routes[i]) {
|
||||
routes.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return routes with route paths matching `path`.
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @return {Collection}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.lookup = function(method, path){
|
||||
return this.find(function(route){
|
||||
return path == route.path
|
||||
&& (route.method == method
|
||||
|| method == 'all');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return routes with regexps that match the given `url`.
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} url
|
||||
* @return {Collection}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.match = function(method, url){
|
||||
return this.find(function(route){
|
||||
return route.match(url)
|
||||
&& (route.method == method
|
||||
|| method == 'all');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Find routes based on the return value of `fn`
|
||||
* which is invoked once per route.
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @return {Collection}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.find = function(fn){
|
||||
var len = methods.length
|
||||
, ret = new Collection(this)
|
||||
, method
|
||||
, routes
|
||||
, route;
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
method = methods[i];
|
||||
routes = this.routes[method];
|
||||
if (!routes) continue;
|
||||
for (var j = 0, jlen = routes.length; j < jlen; ++j) {
|
||||
route = routes[j];
|
||||
if (fn(route)) ret.push(route);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Route dispatcher aka the route "middleware".
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @param {Function} next
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._dispatch = function(req, res, next){
|
||||
var params = this.params
|
||||
, self = this;
|
||||
|
||||
// route dispatch
|
||||
(function pass(i, err){
|
||||
var paramCallbacks
|
||||
, paramIndex = 0
|
||||
, paramVal
|
||||
, route
|
||||
, keys
|
||||
, key
|
||||
, ret;
|
||||
|
||||
// match next route
|
||||
function nextRoute(err) {
|
||||
pass(req._route_index + 1, err);
|
||||
}
|
||||
|
||||
// match route
|
||||
req.route = route = self._match(req, i);
|
||||
|
||||
// implied OPTIONS
|
||||
if (!route && 'OPTIONS' == req.method) return self._options(req, res);
|
||||
|
||||
// no route
|
||||
if (!route) return next(err);
|
||||
|
||||
// we have a route
|
||||
// start at param 0
|
||||
req.params = route.params;
|
||||
keys = route.keys;
|
||||
i = 0;
|
||||
|
||||
// param callbacks
|
||||
function param(err) {
|
||||
paramIndex = 0;
|
||||
key = keys[i++];
|
||||
paramVal = key && req.params[key.name];
|
||||
paramCallbacks = key && params[key.name];
|
||||
|
||||
try {
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err) {
|
||||
i = 0;
|
||||
callbacks(err);
|
||||
} else if (paramCallbacks && undefined !== paramVal) {
|
||||
paramCallback();
|
||||
} else if (key) {
|
||||
param();
|
||||
} else {
|
||||
i = 0;
|
||||
callbacks();
|
||||
}
|
||||
} catch (err) {
|
||||
param(err);
|
||||
}
|
||||
};
|
||||
|
||||
param(err);
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
if (err || !fn) return param(err);
|
||||
fn(req, res, paramCallback, paramVal, key.name);
|
||||
}
|
||||
|
||||
// invoke route callbacks
|
||||
function callbacks(err) {
|
||||
var fn = route.callbacks[i++];
|
||||
try {
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err && fn) {
|
||||
if (fn.length < 4) return callbacks(err);
|
||||
fn(err, req, res, callbacks);
|
||||
} else if (fn) {
|
||||
fn(req, res, callbacks);
|
||||
} else {
|
||||
nextRoute(err);
|
||||
}
|
||||
} catch (err) {
|
||||
callbacks(err);
|
||||
}
|
||||
}
|
||||
})(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to __OPTIONS__ method.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._options = function(req, res){
|
||||
var path = parse(req.url).pathname
|
||||
, body = this._optionsFor(path).join(',');
|
||||
res.send(body, { Allow: body });
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of HTTP verbs or "options" for `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._optionsFor = function(path){
|
||||
var self = this;
|
||||
return methods.filter(function(method){
|
||||
var routes = self.routes[method];
|
||||
if (!routes || 'options' == method) return;
|
||||
for (var i = 0, len = routes.length; i < len; ++i) {
|
||||
if (routes[i].match(path)) return true;
|
||||
}
|
||||
}).map(function(method){
|
||||
return method.toUpperCase();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to match a route for `req`
|
||||
* starting from offset `i`.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {Number} i
|
||||
* @return {Route}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._match = function(req, i){
|
||||
var method = req.method.toLowerCase()
|
||||
, url = parse(req.url)
|
||||
, path = url.pathname
|
||||
, routes = this.routes
|
||||
, captures
|
||||
, route
|
||||
, keys;
|
||||
|
||||
// pass HEAD to GET routes
|
||||
if ('head' == method) method = 'get';
|
||||
|
||||
// routes for this method
|
||||
if (routes = routes[method]) {
|
||||
|
||||
// matching routes
|
||||
for (var len = routes.length; i < len; ++i) {
|
||||
route = routes[i];
|
||||
if (captures = route.match(path)) {
|
||||
keys = route.keys;
|
||||
route.params = [];
|
||||
|
||||
// params from capture groups
|
||||
for (var j = 1, jlen = captures.length; j < jlen; ++j) {
|
||||
var key = keys[j-1]
|
||||
, val = 'string' == typeof captures[j]
|
||||
? decodeURIComponent(captures[j])
|
||||
: captures[j];
|
||||
if (key) {
|
||||
route.params[key.name] = val;
|
||||
} else {
|
||||
route.params.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
// all done
|
||||
req._route_index = i;
|
||||
return route;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Route `method`, `path`, and one or more callbacks.
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Function} callback...
|
||||
* @return {Router} for chaining
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._route = function(method, path, callbacks){
|
||||
var app = this.app
|
||||
, callbacks = utils.flatten(toArray(arguments, 2));
|
||||
|
||||
// ensure path was given
|
||||
if (!path) throw new Error('app.' + method + '() requires a path');
|
||||
|
||||
// create the route
|
||||
var route = new Route(method, path, callbacks, {
|
||||
sensitive: app.enabled('case sensitive routes')
|
||||
, strict: app.enabled('strict routing')
|
||||
});
|
||||
|
||||
// add it
|
||||
(this.routes[method] = this.routes[method] || [])
|
||||
.push(route);
|
||||
return this;
|
||||
};
|
||||
70
example/node/node_modules/express/lib/router/methods.js
generated
vendored
Normal file
70
example/node/node_modules/express/lib/router/methods.js
generated
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
/*!
|
||||
* Express - router - methods
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Hypertext Transfer Protocol -- HTTP/1.1
|
||||
* http://www.ietf.org/rfc/rfc2616.txt
|
||||
*/
|
||||
|
||||
var RFC2616 = ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT'];
|
||||
|
||||
/**
|
||||
* HTTP Extensions for Distributed Authoring -- WEBDAV
|
||||
* http://www.ietf.org/rfc/rfc2518.txt
|
||||
*/
|
||||
|
||||
var RFC2518 = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK'];
|
||||
|
||||
/**
|
||||
* Versioning Extensions to WebDAV
|
||||
* http://www.ietf.org/rfc/rfc3253.txt
|
||||
*/
|
||||
|
||||
var RFC3253 = ['VERSION-CONTROL', 'REPORT', 'CHECKOUT', 'CHECKIN', 'UNCHECKOUT', 'MKWORKSPACE', 'UPDATE', 'LABEL', 'MERGE', 'BASELINE-CONTROL', 'MKACTIVITY'];
|
||||
|
||||
/**
|
||||
* Ordered Collections Protocol (WebDAV)
|
||||
* http://www.ietf.org/rfc/rfc3648.txt
|
||||
*/
|
||||
|
||||
var RFC3648 = ['ORDERPATCH'];
|
||||
|
||||
/**
|
||||
* Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol
|
||||
* http://www.ietf.org/rfc/rfc3744.txt
|
||||
*/
|
||||
|
||||
var RFC3744 = ['ACL'];
|
||||
|
||||
/**
|
||||
* Web Distributed Authoring and Versioning (WebDAV) SEARCH
|
||||
* http://www.ietf.org/rfc/rfc5323.txt
|
||||
*/
|
||||
|
||||
var RFC5323 = ['SEARCH'];
|
||||
|
||||
/**
|
||||
* PATCH Method for HTTP
|
||||
* http://www.ietf.org/rfc/rfc5789.txt
|
||||
*/
|
||||
|
||||
var RFC5789 = ['PATCH'];
|
||||
|
||||
/**
|
||||
* Expose the methods.
|
||||
*/
|
||||
|
||||
module.exports = [].concat(
|
||||
RFC2616
|
||||
, RFC2518
|
||||
, RFC3253
|
||||
, RFC3648
|
||||
, RFC3744
|
||||
, RFC5323
|
||||
, RFC5789).map(function(method){
|
||||
return method.toLowerCase();
|
||||
});
|
||||
88
example/node/node_modules/express/lib/router/route.js
generated
vendored
Normal file
88
example/node/node_modules/express/lib/router/route.js
generated
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
|
||||
/*!
|
||||
* Express - router - Route
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Expose `Route`.
|
||||
*/
|
||||
|
||||
module.exports = Route;
|
||||
|
||||
/**
|
||||
* Initialize `Route` with the given HTTP `method`, `path`,
|
||||
* and an array of `callbacks` and `options`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `sensitive` enable case-sensitive routes
|
||||
* - `strict` enable strict matching for trailing slashes
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Array} callbacks
|
||||
* @param {Object} options.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Route(method, path, callbacks, options) {
|
||||
options = options || {};
|
||||
this.path = path;
|
||||
this.method = method;
|
||||
this.callbacks = callbacks;
|
||||
this.regexp = normalize(path
|
||||
, this.keys = []
|
||||
, options.sensitive
|
||||
, options.strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this route matches `path` and return captures made.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Route.prototype.match = function(path){
|
||||
return this.regexp.exec(path);
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize the given path string,
|
||||
* returning a regular expression.
|
||||
*
|
||||
* An empty array should be passed,
|
||||
* which will contain the placeholder
|
||||
* key names. For example "/user/:id" will
|
||||
* then contain ["id"].
|
||||
*
|
||||
* @param {String|RegExp} path
|
||||
* @param {Array} keys
|
||||
* @param {Boolean} sensitive
|
||||
* @param {Boolean} strict
|
||||
* @return {RegExp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function normalize(path, keys, sensitive, strict) {
|
||||
if (path instanceof RegExp) return path;
|
||||
path = path
|
||||
.concat(strict ? '' : '/?')
|
||||
.replace(/\/\(/g, '(?:/')
|
||||
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
|
||||
keys.push({ name: key, optional: !! optional });
|
||||
slash = slash || '';
|
||||
return ''
|
||||
+ (optional ? '' : slash)
|
||||
+ '(?:'
|
||||
+ (optional ? slash : '')
|
||||
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
|
||||
+ (optional || '');
|
||||
})
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.*)');
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
}
|
||||
152
example/node/node_modules/express/lib/utils.js
generated
vendored
Normal file
152
example/node/node_modules/express/lib/utils.js
generated
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
|
||||
/*!
|
||||
* Express - Utils
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check if `path` looks absolute.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.isAbsolute = function(path){
|
||||
if ('/' == path[0]) return true;
|
||||
if (':' == path[1] && '\\' == path[2]) return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge object `b` with `a` giving precedence to
|
||||
* values in object `a`.
|
||||
*
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @return {Object} a
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.union = function(a, b){
|
||||
if (a && b) {
|
||||
var keys = Object.keys(b)
|
||||
, len = keys.length
|
||||
, key;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
key = keys[i];
|
||||
if (!a.hasOwnProperty(key)) {
|
||||
a[key] = b[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
/**
|
||||
* Flatten the given `arr`.
|
||||
*
|
||||
* @param {Array} arr
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.flatten = function(arr, ret){
|
||||
var ret = ret || []
|
||||
, len = arr.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (Array.isArray(arr[i])) {
|
||||
exports.flatten(arr[i], ret);
|
||||
} else {
|
||||
ret.push(arr[i]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse mini markdown implementation.
|
||||
* The following conversions are supported,
|
||||
* primarily for the "flash" middleware:
|
||||
*
|
||||
* _foo_ or *foo* become <em>foo</em>
|
||||
* __foo__ or **foo** become <strong>foo</strong>
|
||||
* [A](B) becomes <a href="B">A</a>
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.miniMarkdown = function(str){
|
||||
return String(str)
|
||||
.replace(/(__|\*\*)(.*?)\1/g, '<strong>$2</strong>')
|
||||
.replace(/(_|\*)(.*?)\1/g, '<em>$2</em>')
|
||||
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
||||
};
|
||||
|
||||
/**
|
||||
* Escape special characters in the given string of html.
|
||||
*
|
||||
* @param {String} html
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.escape = function(html) {
|
||||
return String(html)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse "Range" header `str` relative to the given file `size`.
|
||||
*
|
||||
* @param {Number} size
|
||||
* @param {String} str
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.parseRange = function(size, str){
|
||||
var valid = true;
|
||||
var arr = str.substr(6).split(',').map(function(range){
|
||||
var range = range.split('-')
|
||||
, start = parseInt(range[0], 10)
|
||||
, end = parseInt(range[1], 10);
|
||||
|
||||
// -500
|
||||
if (isNaN(start)) {
|
||||
start = size - end;
|
||||
end = size - 1;
|
||||
// 500-
|
||||
} else if (isNaN(end)) {
|
||||
end = size - 1;
|
||||
}
|
||||
|
||||
// Invalid
|
||||
if (isNaN(start) || isNaN(end) || start > end) valid = false;
|
||||
|
||||
return { start: start, end: end };
|
||||
});
|
||||
return valid ? arr : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fast alternative to `Array.prototype.slice.call()`.
|
||||
*
|
||||
* @param {Arguments} args
|
||||
* @param {Number} n
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.toArray = function(args, i){
|
||||
var arr = []
|
||||
, len = args.length
|
||||
, i = i || 0;
|
||||
for (; i < len; ++i) arr.push(args[i]);
|
||||
return arr;
|
||||
};
|
||||
460
example/node/node_modules/express/lib/view.js
generated
vendored
Normal file
460
example/node/node_modules/express/lib/view.js
generated
vendored
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
|
||||
/*!
|
||||
* Express - view
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var path = require('path')
|
||||
, extname = path.extname
|
||||
, dirname = path.dirname
|
||||
, basename = path.basename
|
||||
, utils = require('connect').utils
|
||||
, View = require('./view/view')
|
||||
, partial = require('./view/partial')
|
||||
, union = require('./utils').union
|
||||
, merge = utils.merge
|
||||
, http = require('http')
|
||||
, res = http.ServerResponse.prototype;
|
||||
|
||||
/**
|
||||
* Expose constructors.
|
||||
*/
|
||||
|
||||
exports = module.exports = View;
|
||||
|
||||
/**
|
||||
* Export template engine registrar.
|
||||
*/
|
||||
|
||||
exports.register = View.register;
|
||||
|
||||
/**
|
||||
* Lookup and compile `view` with cache support by supplying
|
||||
* both the `cache` object and `cid` string,
|
||||
* followed by `options` passed to `exports.lookup()`.
|
||||
*
|
||||
* @param {String} view
|
||||
* @param {Object} cache
|
||||
* @param {Object} cid
|
||||
* @param {Object} options
|
||||
* @return {View}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.compile = function(view, cache, cid, options){
|
||||
if (cache && cid && cache[cid]){
|
||||
options.filename = cache[cid].path;
|
||||
return cache[cid];
|
||||
}
|
||||
|
||||
// lookup
|
||||
view = exports.lookup(view, options);
|
||||
|
||||
// hints
|
||||
if (!view.exists) {
|
||||
if (options.hint) hintAtViewPaths(view.original, options);
|
||||
var err = new Error('failed to locate view "' + view.original.view + '"');
|
||||
err.view = view.original;
|
||||
throw err;
|
||||
}
|
||||
|
||||
// compile
|
||||
options.filename = view.path;
|
||||
view.fn = view.templateEngine.compile(view.contents, options);
|
||||
cache[cid] = view;
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup `view`, returning an instanceof `View`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `root` root directory path
|
||||
* - `defaultEngine` default template engine
|
||||
* - `parentView` parent `View` object
|
||||
* - `cache` cache object
|
||||
* - `cacheid` optional cache id
|
||||
*
|
||||
* Lookup:
|
||||
*
|
||||
* - partial `_<name>`
|
||||
* - any `<name>/index`
|
||||
* - non-layout `../<name>/index`
|
||||
* - any `<root>/<name>`
|
||||
* - partial `<root>/_<name>`
|
||||
*
|
||||
* @param {String} view
|
||||
* @param {Object} options
|
||||
* @return {View}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.lookup = function(view, options){
|
||||
var orig = view = new View(view, options)
|
||||
, partial = options.isPartial
|
||||
, layout = options.isLayout;
|
||||
|
||||
// Try _ prefix ex: ./views/_<name>.jade
|
||||
// taking precedence over the direct path
|
||||
if (partial) {
|
||||
view = new View(orig.prefixPath, options);
|
||||
if (!view.exists) view = orig;
|
||||
}
|
||||
|
||||
// Try index ex: ./views/user/index.jade
|
||||
if (!layout && !view.exists) view = new View(orig.indexPath, options);
|
||||
|
||||
// Try ../<name>/index ex: ../user/index.jade
|
||||
// when calling partial('user') within the same dir
|
||||
if (!layout && !view.exists) view = new View(orig.upIndexPath, options);
|
||||
|
||||
// Try root ex: <root>/user.jade
|
||||
if (!view.exists) view = new View(orig.rootPath, options);
|
||||
|
||||
// Try root _ prefix ex: <root>/_user.jade
|
||||
if (!view.exists && partial) view = new View(view.prefixPath, options);
|
||||
|
||||
view.original = orig;
|
||||
return view;
|
||||
};
|
||||
|
||||
/**
|
||||
* Partial render helper.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function renderPartial(res, view, options, parentLocals, parent){
|
||||
var collection, object, locals;
|
||||
|
||||
if (options) {
|
||||
// collection
|
||||
if (options.collection) {
|
||||
collection = options.collection;
|
||||
delete options.collection;
|
||||
} else if ('length' in options) {
|
||||
collection = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
// locals
|
||||
if (options.locals) {
|
||||
locals = options.locals;
|
||||
delete options.locals;
|
||||
}
|
||||
|
||||
// object
|
||||
if ('Object' != options.constructor.name) {
|
||||
object = options;
|
||||
options = {};
|
||||
} else if (undefined != options.object) {
|
||||
object = options.object;
|
||||
delete options.object;
|
||||
}
|
||||
} else {
|
||||
options = {};
|
||||
}
|
||||
|
||||
// Inherit locals from parent
|
||||
union(options, parentLocals);
|
||||
|
||||
// Merge locals
|
||||
if (locals) merge(options, locals);
|
||||
|
||||
// Partials dont need layouts
|
||||
options.isPartial = true;
|
||||
options.layout = false;
|
||||
|
||||
// Deduce name from view path
|
||||
var name = options.as || partial.resolveObjectName(view);
|
||||
|
||||
// Render partial
|
||||
function render(){
|
||||
if (object) {
|
||||
if ('string' == typeof name) {
|
||||
options[name] = object;
|
||||
} else if (name === global) {
|
||||
merge(options, object);
|
||||
}
|
||||
}
|
||||
return res.render(view, options, null, parent, true);
|
||||
}
|
||||
|
||||
// Collection support
|
||||
if (collection) {
|
||||
var len = collection.length
|
||||
, buf = ''
|
||||
, keys
|
||||
, key
|
||||
, val;
|
||||
|
||||
options.collectionLength = len;
|
||||
|
||||
if ('number' == typeof len || Array.isArray(collection)) {
|
||||
for (var i = 0; i < len; ++i) {
|
||||
val = collection[i];
|
||||
options.firstInCollection = i == 0;
|
||||
options.indexInCollection = i;
|
||||
options.lastInCollection = i == len - 1;
|
||||
object = val;
|
||||
buf += render();
|
||||
}
|
||||
} else {
|
||||
keys = Object.keys(collection);
|
||||
len = keys.length;
|
||||
options.collectionLength = len;
|
||||
options.collectionKeys = keys;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
key = keys[i];
|
||||
val = collection[key];
|
||||
options.keyInCollection = key;
|
||||
options.firstInCollection = i == 0;
|
||||
options.indexInCollection = i;
|
||||
options.lastInCollection = i == len - 1;
|
||||
object = val;
|
||||
buf += render();
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
} else {
|
||||
return render();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Render `view` partial with the given `options`. Optionally a
|
||||
* callback `fn(err, str)` may be passed instead of writing to
|
||||
* the socket.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `object` Single object with name derived from the view (unless `as` is present)
|
||||
*
|
||||
* - `as` Variable name for each `collection` value, defaults to the view name.
|
||||
* * as: 'something' will add the `something` local variable
|
||||
* * as: this will use the collection value as the template context
|
||||
* * as: global will merge the collection value's properties with `locals`
|
||||
*
|
||||
* - `collection` Array of objects, the name is derived from the view name itself.
|
||||
* For example _video.html_ will have a object _video_ available to it.
|
||||
*
|
||||
* @param {String} view
|
||||
* @param {Object|Array|Function} options, collection, callback, or object
|
||||
* @param {Function} fn
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.partial = function(view, options, fn){
|
||||
var app = this.app
|
||||
, options = options || {}
|
||||
, viewEngine = app.set('view engine')
|
||||
, parent = {};
|
||||
|
||||
// accept callback as second argument
|
||||
if ('function' == typeof options) {
|
||||
fn = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
// root "views" option
|
||||
parent.dirname = app.set('views') || process.cwd() + '/views';
|
||||
|
||||
// utilize "view engine" option
|
||||
if (viewEngine) parent.engine = viewEngine;
|
||||
|
||||
// render the partial
|
||||
try {
|
||||
var str = renderPartial(this, view, options, null, parent);
|
||||
} catch (err) {
|
||||
if (fn) {
|
||||
fn(err);
|
||||
} else {
|
||||
this.req.next(err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// callback or transfer
|
||||
if (fn) {
|
||||
fn(null, str);
|
||||
} else {
|
||||
this.send(str);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Render `view` with the given `options` and optional callback `fn`.
|
||||
* When a callback function is given a response will _not_ be made
|
||||
* automatically, however otherwise a response of _200_ and _text/html_ is given.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `scope` Template evaluation context (the value of `this`)
|
||||
* - `debug` Output debugging information
|
||||
* - `status` Response status code
|
||||
*
|
||||
* @param {String} view
|
||||
* @param {Object|Function} options or callback function
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.render = function(view, opts, fn, parent, sub){
|
||||
// support callback function as second arg
|
||||
if ('function' == typeof opts) {
|
||||
fn = opts, opts = null;
|
||||
}
|
||||
|
||||
try {
|
||||
return this._render(view, opts, fn, parent, sub);
|
||||
} catch (err) {
|
||||
// callback given
|
||||
if (fn) {
|
||||
fn(err);
|
||||
// unwind to root call to prevent multiple callbacks
|
||||
} else if (sub) {
|
||||
throw err;
|
||||
// root template, next(err)
|
||||
} else {
|
||||
this.req.next(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// private render()
|
||||
|
||||
res._render = function(view, opts, fn, parent, sub){
|
||||
var options = {}
|
||||
, self = this
|
||||
, app = this.app
|
||||
, helpers = app._locals
|
||||
, dynamicHelpers = app.dynamicViewHelpers
|
||||
, viewOptions = app.set('view options')
|
||||
, root = app.set('views') || process.cwd() + '/views';
|
||||
|
||||
// cache id
|
||||
var cid = app.enabled('view cache')
|
||||
? view + (parent ? ':' + parent.path : '')
|
||||
: false;
|
||||
|
||||
// merge "view options"
|
||||
if (viewOptions) merge(options, viewOptions);
|
||||
|
||||
// merge res._locals
|
||||
if (this._locals) merge(options, this._locals);
|
||||
|
||||
// merge render() options
|
||||
if (opts) merge(options, opts);
|
||||
|
||||
// merge render() .locals
|
||||
if (opts && opts.locals) merge(options, opts.locals);
|
||||
|
||||
// status support
|
||||
if (options.status) this.statusCode = options.status;
|
||||
|
||||
// capture attempts
|
||||
options.attempts = [];
|
||||
|
||||
var partial = options.isPartial
|
||||
, layout = options.layout;
|
||||
|
||||
// Layout support
|
||||
if (true === layout || undefined === layout) {
|
||||
layout = 'layout';
|
||||
}
|
||||
|
||||
// Default execution scope to a plain object
|
||||
options.scope = options.scope || {};
|
||||
|
||||
// Populate view
|
||||
options.parentView = parent;
|
||||
|
||||
// "views" setting
|
||||
options.root = root;
|
||||
|
||||
// "view engine" setting
|
||||
options.defaultEngine = app.set('view engine');
|
||||
|
||||
// charset option
|
||||
if (options.charset) this.charset = options.charset;
|
||||
|
||||
// Dynamic helper support
|
||||
if (false !== options.dynamicHelpers) {
|
||||
// cache
|
||||
if (!this.__dynamicHelpers) {
|
||||
this.__dynamicHelpers = {};
|
||||
for (var key in dynamicHelpers) {
|
||||
this.__dynamicHelpers[key] = dynamicHelpers[key].call(
|
||||
this.app
|
||||
, this.req
|
||||
, this);
|
||||
}
|
||||
}
|
||||
|
||||
// apply
|
||||
merge(options, this.__dynamicHelpers);
|
||||
}
|
||||
|
||||
// Merge view helpers
|
||||
union(options, helpers);
|
||||
|
||||
// Always expose partial() as a local
|
||||
options.partial = function(path, opts){
|
||||
return renderPartial(self, path, opts, options, view);
|
||||
};
|
||||
|
||||
// View lookup
|
||||
options.hint = app.enabled('hints');
|
||||
view = exports.compile(view, app.cache, cid, options);
|
||||
|
||||
// layout helper
|
||||
options.layout = function(path){
|
||||
layout = path;
|
||||
};
|
||||
|
||||
// render
|
||||
var str = view.fn.call(options.scope, options);
|
||||
|
||||
// layout expected
|
||||
if (layout) {
|
||||
options.isLayout = true;
|
||||
options.layout = false;
|
||||
options.body = str;
|
||||
this.render(layout, options, fn, view, true);
|
||||
// partial return
|
||||
} else if (partial) {
|
||||
return str;
|
||||
// render complete, and
|
||||
// callback given
|
||||
} else if (fn) {
|
||||
fn(null, str);
|
||||
// respond
|
||||
} else {
|
||||
this.send(str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hint at view path resolution, outputting the
|
||||
* paths that Express has tried.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function hintAtViewPaths(view, options) {
|
||||
console.error();
|
||||
console.error('failed to locate view "' + view.view + '", tried:');
|
||||
options.attempts.forEach(function(path){
|
||||
console.error(' - %s', path);
|
||||
});
|
||||
console.error();
|
||||
}
|
||||
40
example/node/node_modules/express/lib/view/partial.js
generated
vendored
Normal file
40
example/node/node_modules/express/lib/view/partial.js
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
/*!
|
||||
* Express - view - Partial
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Memory cache.
|
||||
*/
|
||||
|
||||
var cache = {};
|
||||
|
||||
/**
|
||||
* Resolve partial object name from the view path.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* "user.ejs" becomes "user"
|
||||
* "forum thread.ejs" becomes "forumThread"
|
||||
* "forum/thread/post.ejs" becomes "post"
|
||||
* "blog-post.ejs" becomes "blogPost"
|
||||
*
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.resolveObjectName = function(view){
|
||||
return cache[view] || (cache[view] = view
|
||||
.split('/')
|
||||
.slice(-1)[0]
|
||||
.split('.')[0]
|
||||
.replace(/^_/, '')
|
||||
.replace(/[^a-zA-Z0-9 ]+/g, ' ')
|
||||
.split(/ +/).map(function(word, i){
|
||||
return i
|
||||
? word[0].toUpperCase() + word.substr(1)
|
||||
: word;
|
||||
}).join(''));
|
||||
};
|
||||
210
example/node/node_modules/express/lib/view/view.js
generated
vendored
Normal file
210
example/node/node_modules/express/lib/view/view.js
generated
vendored
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
|
||||
/*!
|
||||
* Express - View
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var path = require('path')
|
||||
, utils = require('../utils')
|
||||
, extname = path.extname
|
||||
, dirname = path.dirname
|
||||
, basename = path.basename
|
||||
, fs = require('fs')
|
||||
, stat = fs.statSync;
|
||||
|
||||
/**
|
||||
* Expose `View`.
|
||||
*/
|
||||
|
||||
exports = module.exports = View;
|
||||
|
||||
/**
|
||||
* Require cache.
|
||||
*/
|
||||
|
||||
var cache = {};
|
||||
|
||||
/**
|
||||
* Initialize a new `View` with the given `view` path and `options`.
|
||||
*
|
||||
* @param {String} view
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function View(view, options) {
|
||||
options = options || {};
|
||||
this.view = view;
|
||||
this.root = options.root;
|
||||
this.relative = false !== options.relative;
|
||||
this.defaultEngine = options.defaultEngine;
|
||||
this.parent = options.parentView;
|
||||
this.basename = basename(view);
|
||||
this.engine = this.resolveEngine();
|
||||
this.extension = '.' + this.engine;
|
||||
this.name = this.basename.replace(this.extension, '');
|
||||
this.path = this.resolvePath();
|
||||
this.dirname = dirname(this.path);
|
||||
if (options.attempts) {
|
||||
if (!~options.attempts.indexOf(this.path))
|
||||
options.attempts.push(this.path);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the view path exists.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
View.prototype.__defineGetter__('exists', function(){
|
||||
try {
|
||||
stat(this.path);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Resolve view engine.
|
||||
*
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
View.prototype.resolveEngine = function(){
|
||||
// Explicit
|
||||
if (~this.basename.indexOf('.')) return extname(this.basename).substr(1);
|
||||
// Inherit from parent
|
||||
if (this.parent) return this.parent.engine;
|
||||
// Default
|
||||
return this.defaultEngine;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve view path.
|
||||
*
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
View.prototype.resolvePath = function(){
|
||||
var path = this.view;
|
||||
// Implicit engine
|
||||
if (!~this.basename.indexOf('.')) path += this.extension;
|
||||
// Absolute
|
||||
if (utils.isAbsolute(path)) return path;
|
||||
// Relative to parent
|
||||
if (this.relative && this.parent) return this.parent.dirname + '/' + path;
|
||||
// Relative to root
|
||||
return this.root
|
||||
? this.root + '/' + path
|
||||
: path;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get view contents. This is a one-time hit, so we
|
||||
* can afford to be sync.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
View.prototype.__defineGetter__('contents', function(){
|
||||
return fs.readFileSync(this.path, 'utf8');
|
||||
});
|
||||
|
||||
/**
|
||||
* Get template engine api, cache exports to reduce
|
||||
* require() calls.
|
||||
*
|
||||
* @return {Object}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
View.prototype.__defineGetter__('templateEngine', function(){
|
||||
var ext = this.extension;
|
||||
return cache[ext] || (cache[ext] = require(this.engine));
|
||||
});
|
||||
|
||||
/**
|
||||
* Return root path alternative.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
View.prototype.__defineGetter__('rootPath', function(){
|
||||
this.relative = false;
|
||||
return this.resolvePath();
|
||||
});
|
||||
|
||||
/**
|
||||
* Return index path alternative.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
View.prototype.__defineGetter__('indexPath', function(){
|
||||
return this.dirname
|
||||
+ '/' + this.basename.replace(this.extension, '')
|
||||
+ '/index' + this.extension;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return ../<name>/index path alternative.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
View.prototype.__defineGetter__('upIndexPath', function(){
|
||||
return this.dirname + '/../' + this.name + '/index' + this.extension;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return _ prefix path alternative
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
View.prototype.__defineGetter__('prefixPath', function(){
|
||||
return this.dirname + '/_' + this.basename;
|
||||
});
|
||||
|
||||
/**
|
||||
* Register the given template engine `exports`
|
||||
* as `ext`. For example we may wish to map ".html"
|
||||
* files to jade:
|
||||
*
|
||||
* app.register('.html', require('jade'));
|
||||
*
|
||||
* or
|
||||
*
|
||||
* app.register('html', require('jade'));
|
||||
*
|
||||
* This is also useful for libraries that may not
|
||||
* match extensions correctly. For example my haml.js
|
||||
* library is installed from npm as "hamljs" so instead
|
||||
* of layout.hamljs, we can register the engine as ".haml":
|
||||
*
|
||||
* app.register('.haml', require('haml-js'));
|
||||
*
|
||||
* @param {String} ext
|
||||
* @param {Object} obj
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.register = function(ext, exports) {
|
||||
if ('.' != ext[0]) ext = '.' + ext;
|
||||
cache[ext] = exports;
|
||||
};
|
||||
11
example/node/node_modules/express/node_modules/connect/.npmignore
generated
vendored
Normal file
11
example/node/node_modules/express/node_modules/connect/.npmignore
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
*.markdown
|
||||
*.md
|
||||
.git*
|
||||
Makefile
|
||||
benchmarks/
|
||||
docs/
|
||||
examples/
|
||||
install.sh
|
||||
support/
|
||||
test/
|
||||
.DS_Store
|
||||
24
example/node/node_modules/express/node_modules/connect/LICENSE
generated
vendored
Normal file
24
example/node/node_modules/express/node_modules/connect/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (c) 2010 Sencha Inc.
|
||||
Copyright (c) 2011 LearnBoost
|
||||
Copyright (c) 2011 TJ Holowaychuk
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
2
example/node/node_modules/express/node_modules/connect/index.js
generated
vendored
Normal file
2
example/node/node_modules/express/node_modules/connect/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
module.exports = require('./lib/connect');
|
||||
81
example/node/node_modules/express/node_modules/connect/lib/cache.js
generated
vendored
Normal file
81
example/node/node_modules/express/node_modules/connect/lib/cache.js
generated
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
|
||||
/*!
|
||||
* Connect - Cache
|
||||
* Copyright(c) 2011 Sencha Inc.
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Expose `Cache`.
|
||||
*/
|
||||
|
||||
module.exports = Cache;
|
||||
|
||||
/**
|
||||
* LRU cache store.
|
||||
*
|
||||
* @param {Number} limit
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Cache(limit) {
|
||||
this.store = {};
|
||||
this.keys = [];
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Touch `key`, promoting the object.
|
||||
*
|
||||
* @param {String} key
|
||||
* @param {Number} i
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Cache.prototype.touch = function(key, i){
|
||||
this.keys.splice(i,1);
|
||||
this.keys.push(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove `key`.
|
||||
*
|
||||
* @param {String} key
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Cache.prototype.remove = function(key){
|
||||
delete this.store[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the object stored for `key`.
|
||||
*
|
||||
* @param {String} key
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Cache.prototype.get = function(key){
|
||||
return this.store[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a cache `key`.
|
||||
*
|
||||
* @param {String} key
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Cache.prototype.add = function(key){
|
||||
// initialize store
|
||||
var len = this.keys.push(key);
|
||||
|
||||
// limit reached, invalid LRU
|
||||
if (len > this.limit) this.remove(this.keys.shift());
|
||||
|
||||
var arr = this.store[key] = [];
|
||||
arr.createdAt = new Date;
|
||||
return arr;
|
||||
};
|
||||
106
example/node/node_modules/express/node_modules/connect/lib/connect.js
generated
vendored
Normal file
106
example/node/node_modules/express/node_modules/connect/lib/connect.js
generated
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
/*!
|
||||
* Connect
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var HTTPServer = require('./http').Server
|
||||
, HTTPSServer = require('./https').Server
|
||||
, fs = require('fs');
|
||||
|
||||
// node patches
|
||||
|
||||
require('./patch');
|
||||
|
||||
// expose createServer() as the module
|
||||
|
||||
exports = module.exports = createServer;
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '1.8.6';
|
||||
|
||||
/**
|
||||
* Initialize a new `connect.HTTPServer` with the middleware
|
||||
* passed to this function. When an object is passed _first_,
|
||||
* we assume these are the tls options, and return a `connect.HTTPSServer`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* An example HTTP server, accepting several middleware.
|
||||
*
|
||||
* var server = connect.createServer(
|
||||
* connect.logger()
|
||||
* , connect.static(__dirname + '/public')
|
||||
* );
|
||||
*
|
||||
* An HTTPS server, utilizing the same middleware as above.
|
||||
*
|
||||
* var server = connect.createServer(
|
||||
* { key: key, cert: cert }
|
||||
* , connect.logger()
|
||||
* , connect.static(__dirname + '/public')
|
||||
* );
|
||||
*
|
||||
* Alternatively with connect 1.0 we may omit `createServer()`.
|
||||
*
|
||||
* connect(
|
||||
* connect.logger()
|
||||
* , connect.static(__dirname + '/public')
|
||||
* ).listen(3000);
|
||||
*
|
||||
* @param {Object|Function} ...
|
||||
* @return {Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function createServer() {
|
||||
if ('object' == typeof arguments[0]) {
|
||||
return new HTTPSServer(arguments[0], Array.prototype.slice.call(arguments, 1));
|
||||
} else {
|
||||
return new HTTPServer(Array.prototype.slice.call(arguments));
|
||||
}
|
||||
};
|
||||
|
||||
// support connect.createServer()
|
||||
|
||||
exports.createServer = createServer;
|
||||
|
||||
// auto-load getters
|
||||
|
||||
exports.middleware = {};
|
||||
|
||||
/**
|
||||
* Auto-load bundled middleware with getters.
|
||||
*/
|
||||
|
||||
fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
|
||||
if (/\.js$/.test(filename)) {
|
||||
var name = filename.substr(0, filename.lastIndexOf('.'));
|
||||
exports.middleware.__defineGetter__(name, function(){
|
||||
return require('./middleware/' + name);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// expose utils
|
||||
|
||||
exports.utils = require('./utils');
|
||||
|
||||
// expose getters as first-class exports
|
||||
|
||||
exports.utils.merge(exports, exports.middleware);
|
||||
|
||||
// expose constructors
|
||||
|
||||
exports.HTTPServer = HTTPServer;
|
||||
exports.HTTPSServer = HTTPSServer;
|
||||
|
||||
217
example/node/node_modules/express/node_modules/connect/lib/http.js
generated
vendored
Normal file
217
example/node/node_modules/express/node_modules/connect/lib/http.js
generated
vendored
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
|
||||
/*!
|
||||
* Connect - HTTPServer
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http')
|
||||
, parse = require('url').parse
|
||||
, assert = require('assert');
|
||||
|
||||
// environment
|
||||
|
||||
var env = process.env.NODE_ENV || 'development';
|
||||
|
||||
/**
|
||||
* Initialize a new `Server` with the given `middleware`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var server = connect.createServer(
|
||||
* connect.favicon()
|
||||
* , connect.logger()
|
||||
* , connect.static(__dirname + '/public')
|
||||
* );
|
||||
*
|
||||
* @params {Array} middleware
|
||||
* @return {Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
var Server = exports.Server = function HTTPServer(middleware) {
|
||||
this.stack = [];
|
||||
middleware.forEach(function(fn){
|
||||
this.use(fn);
|
||||
}, this);
|
||||
http.Server.call(this, this.handle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherit from `http.Server.prototype`.
|
||||
*/
|
||||
|
||||
Server.prototype.__proto__ = http.Server.prototype;
|
||||
|
||||
/**
|
||||
* Utilize the given middleware `handle` to the given `route`,
|
||||
* defaulting to _/_. This "route" is the mount-point for the
|
||||
* middleware, when given a value other than _/_ the middleware
|
||||
* is only effective when that segment is present in the request's
|
||||
* pathname.
|
||||
*
|
||||
* For example if we were to mount a function at _/admin_, it would
|
||||
* be invoked on _/admin_, and _/admin/settings_, however it would
|
||||
* not be invoked for _/_, or _/posts_.
|
||||
*
|
||||
* This is effectively the same as passing middleware to `connect.createServer()`,
|
||||
* however provides a progressive api.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var server = connect.createServer();
|
||||
* server.use(connect.favicon());
|
||||
* server.use(connect.logger());
|
||||
* server.use(connect.static(__dirname + '/public'));
|
||||
*
|
||||
* If we wanted to prefix static files with _/public_, we could
|
||||
* "mount" the `static()` middleware:
|
||||
*
|
||||
* server.use('/public', connect.static(__dirname + '/public'));
|
||||
*
|
||||
* This api is chainable, meaning the following is valid:
|
||||
*
|
||||
* connect.createServer()
|
||||
* .use(connect.favicon())
|
||||
* .use(connect.logger())
|
||||
* .use(connect.static(__dirname + '/public'))
|
||||
* .listen(3000);
|
||||
*
|
||||
* @param {String|Function} route or handle
|
||||
* @param {Function} handle
|
||||
* @return {Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Server.prototype.use = function(route, handle){
|
||||
this.route = '/';
|
||||
|
||||
// default route to '/'
|
||||
if ('string' != typeof route) {
|
||||
handle = route;
|
||||
route = '/';
|
||||
}
|
||||
|
||||
// wrap sub-apps
|
||||
if ('function' == typeof handle.handle) {
|
||||
var server = handle;
|
||||
server.route = route;
|
||||
handle = function(req, res, next) {
|
||||
server.handle(req, res, next);
|
||||
};
|
||||
}
|
||||
|
||||
// wrap vanilla http.Servers
|
||||
if (handle instanceof http.Server) {
|
||||
handle = handle.listeners('request')[0];
|
||||
}
|
||||
|
||||
// normalize route to not trail with slash
|
||||
if ('/' == route[route.length - 1]) {
|
||||
route = route.substr(0, route.length - 1);
|
||||
}
|
||||
|
||||
// add the middleware
|
||||
this.stack.push({ route: route, handle: handle });
|
||||
|
||||
// allow chaining
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle server requests, punting them down
|
||||
* the middleware stack.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Server.prototype.handle = function(req, res, out) {
|
||||
var writeHead = res.writeHead
|
||||
, stack = this.stack
|
||||
, removed = ''
|
||||
, index = 0;
|
||||
|
||||
function next(err) {
|
||||
var layer, path, c;
|
||||
req.url = removed + req.url;
|
||||
req.originalUrl = req.originalUrl || req.url;
|
||||
removed = '';
|
||||
|
||||
layer = stack[index++];
|
||||
|
||||
// all done
|
||||
if (!layer || res.headerSent) {
|
||||
// but wait! we have a parent
|
||||
if (out) return out(err);
|
||||
|
||||
// error
|
||||
if (err) {
|
||||
var msg = 'production' == env
|
||||
? 'Internal Server Error'
|
||||
: err.stack || err.toString();
|
||||
|
||||
// output to stderr in a non-test env
|
||||
if ('test' != env) console.error(err.stack || err.toString());
|
||||
|
||||
// unable to respond
|
||||
if (res.headerSent) return req.socket.destroy();
|
||||
|
||||
res.statusCode = 500;
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
if ('HEAD' == req.method) return res.end();
|
||||
res.end(msg);
|
||||
} else {
|
||||
res.statusCode = 404;
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
if ('HEAD' == req.method) return res.end();
|
||||
res.end('Cannot ' + req.method + ' ' + req.url);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
path = parse(req.url).pathname;
|
||||
if (undefined == path) path = '/';
|
||||
|
||||
// skip this layer if the route doesn't match.
|
||||
if (0 != path.indexOf(layer.route)) return next(err);
|
||||
|
||||
c = path[layer.route.length];
|
||||
if (c && '/' != c && '.' != c) return next(err);
|
||||
|
||||
// Call the layer handler
|
||||
// Trim off the part of the url that matches the route
|
||||
removed = layer.route;
|
||||
req.url = req.url.substr(removed.length);
|
||||
|
||||
// Ensure leading slash
|
||||
if ('/' != req.url[0]) req.url = '/' + req.url;
|
||||
|
||||
var arity = layer.handle.length;
|
||||
if (err) {
|
||||
if (arity === 4) {
|
||||
layer.handle(err, req, res, next);
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
} else if (arity < 4) {
|
||||
layer.handle(req, res, next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof assert.AssertionError) {
|
||||
console.error(e.stack + '\n');
|
||||
next(e);
|
||||
} else {
|
||||
next(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
next();
|
||||
};
|
||||
47
example/node/node_modules/express/node_modules/connect/lib/https.js
generated
vendored
Normal file
47
example/node/node_modules/express/node_modules/connect/lib/https.js
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
/*!
|
||||
* Connect - HTTPServer
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var HTTPServer = require('./http').Server
|
||||
, https = require('https');
|
||||
|
||||
/**
|
||||
* Initialize a new `Server` with the given
|
||||
*`options` and `middleware`. The HTTPS api
|
||||
* is identical to the [HTTP](http.html) server,
|
||||
* however TLS `options` must be provided before
|
||||
* passing in the optional middleware.
|
||||
*
|
||||
* @params {Object} options
|
||||
* @params {Array} middleawre
|
||||
* @return {Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
var Server = exports.Server = function HTTPSServer(options, middleware) {
|
||||
this.stack = [];
|
||||
middleware.forEach(function(fn){
|
||||
this.use(fn);
|
||||
}, this);
|
||||
https.Server.call(this, options, this.handle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherit from `http.Server.prototype`.
|
||||
*/
|
||||
|
||||
Server.prototype.__proto__ = https.Server.prototype;
|
||||
|
||||
// mixin HTTPServer methods
|
||||
|
||||
Object.keys(HTTPServer.prototype).forEach(function(method){
|
||||
Server.prototype[method] = HTTPServer.prototype[method];
|
||||
});
|
||||
46
example/node/node_modules/express/node_modules/connect/lib/index.js
generated
vendored
Normal file
46
example/node/node_modules/express/node_modules/connect/lib/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
/**
|
||||
* # Connect
|
||||
*
|
||||
* Connect is a middleware framework for node,
|
||||
* shipping with over 11 bundled middleware and a rich choice of
|
||||
* [3rd-party middleware](https://github.com/senchalabs/connect/wiki).
|
||||
*
|
||||
* Installation:
|
||||
*
|
||||
* $ npm install connect
|
||||
*
|
||||
* API:
|
||||
*
|
||||
* - [connect](connect.html) general
|
||||
* - [http](http.html) http server
|
||||
* - [https](https.html) https server
|
||||
*
|
||||
* Middleware:
|
||||
*
|
||||
* - [logger](middleware-logger.html) request logger with custom format support
|
||||
* - [csrf](middleware-csrf.html) Cross-site request forgery protection
|
||||
* - [basicAuth](middleware-basicAuth.html) basic http authentication
|
||||
* - [bodyParser](middleware-bodyParser.html) extensible request body parser
|
||||
* - [cookieParser](middleware-cookieParser.html) cookie parser
|
||||
* - [session](middleware-session.html) session management support with bundled [MemoryStore](middleware-session-memory.html)
|
||||
* - [compiler](middleware-compiler.html) static asset compiler (sass, less, coffee-script, etc)
|
||||
* - [methodOverride](middleware-methodOverride.html) faux HTTP method support
|
||||
* - [responseTime](middleware-responseTime.html) calculates response-time and exposes via X-Response-Time
|
||||
* - [router](middleware-router.html) provides rich Sinatra / Express-like routing
|
||||
* - [staticCache](middleware-staticCache.html) memory cache layer for the static() middleware
|
||||
* - [static](middleware-static.html) streaming static file server supporting `Range` and more
|
||||
* - [directory](middleware-directory.html) directory listing middleware
|
||||
* - [vhost](middleware-vhost.html) virtual host sub-domain mapping middleware
|
||||
* - [favicon](middleware-favicon.html) efficient favicon server (with default icon)
|
||||
* - [limit](middleware-limit.html) limit the bytesize of request bodies
|
||||
* - [profiler](middleware-profiler.html) request profiler reporting response-time, memory usage, etc
|
||||
* - [query](middleware-query.html) automatic querystring parser, populating `req.query`
|
||||
* - [errorHandler](middleware-errorHandler.html) flexible error handler
|
||||
*
|
||||
* Internals:
|
||||
*
|
||||
* - connect [utilities](utils.html)
|
||||
* - node monkey [patches](patch.html)
|
||||
*
|
||||
*/
|
||||
93
example/node/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js
generated
vendored
Normal file
93
example/node/node_modules/express/node_modules/connect/lib/middleware/basicAuth.js
generated
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
/*!
|
||||
* Connect - basicAuth
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('../utils')
|
||||
, unauthorized = utils.unauthorized
|
||||
, badRequest = utils.badRequest;
|
||||
|
||||
/**
|
||||
* Enfore basic authentication by providing a `callback(user, pass)`,
|
||||
* which must return `true` in order to gain access. Alternatively an async
|
||||
* method is provided as well, invoking `callback(user, pass, callback)`. Populates
|
||||
* `req.remoteUser`. The final alternative is simply passing username / password
|
||||
* strings.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* connect(connect.basicAuth('username', 'password'));
|
||||
*
|
||||
* connect(
|
||||
* connect.basicAuth(function(user, pass){
|
||||
* return 'tj' == user & 'wahoo' == pass;
|
||||
* })
|
||||
* );
|
||||
*
|
||||
* connect(
|
||||
* connect.basicAuth(function(user, pass, fn){
|
||||
* User.authenticate({ user: user, pass: pass }, fn);
|
||||
* })
|
||||
* );
|
||||
*
|
||||
* @param {Function|String} callback or username
|
||||
* @param {String} realm
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function basicAuth(callback, realm) {
|
||||
var username, password;
|
||||
|
||||
// user / pass strings
|
||||
if ('string' == typeof callback) {
|
||||
username = callback;
|
||||
password = realm;
|
||||
if ('string' != typeof password) throw new Error('password argument required');
|
||||
realm = arguments[2];
|
||||
callback = function(user, pass){
|
||||
return user == username && pass == password;
|
||||
}
|
||||
}
|
||||
|
||||
realm = realm || 'Authorization Required';
|
||||
|
||||
return function(req, res, next) {
|
||||
var authorization = req.headers.authorization;
|
||||
|
||||
if (req.remoteUser) return next();
|
||||
if (!authorization) return unauthorized(res, realm);
|
||||
|
||||
var parts = authorization.split(' ')
|
||||
, scheme = parts[0]
|
||||
, credentials = new Buffer(parts[1], 'base64').toString().split(':');
|
||||
|
||||
if ('Basic' != scheme) return badRequest(res);
|
||||
|
||||
// async
|
||||
if (callback.length >= 3) {
|
||||
var pause = utils.pause(req);
|
||||
callback(credentials[0], credentials[1], function(err, user){
|
||||
if (err || !user) return unauthorized(res, realm);
|
||||
req.remoteUser = user;
|
||||
next();
|
||||
pause.resume();
|
||||
});
|
||||
// sync
|
||||
} else {
|
||||
if (callback(credentials[0], credentials[1])) {
|
||||
req.remoteUser = credentials[0];
|
||||
next();
|
||||
} else {
|
||||
unauthorized(res, realm);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
196
example/node/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js
generated
vendored
Normal file
196
example/node/node_modules/express/node_modules/connect/lib/middleware/bodyParser.js
generated
vendored
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
|
||||
/*!
|
||||
* Connect - bodyParser
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var qs = require('qs')
|
||||
, formidable = require('formidable');
|
||||
|
||||
/**
|
||||
* Extract the mime type from the given request's
|
||||
* _Content-Type_ header.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function mime(req) {
|
||||
var str = req.headers['content-type'] || '';
|
||||
return str.split(';')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse request bodies.
|
||||
*
|
||||
* By default _application/json_, _application/x-www-form-urlencoded_,
|
||||
* and _multipart/form-data_ are supported, however you may map `connect.bodyParser.parse[contentType]`
|
||||
* to a function receiving `(req, options, callback)`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* connect.createServer(
|
||||
* connect.bodyParser()
|
||||
* , function(req, res) {
|
||||
* res.end('viewing user ' + req.body.user.name);
|
||||
* }
|
||||
* );
|
||||
*
|
||||
* $ curl -d 'user[name]=tj' http://localhost/
|
||||
* $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://localhost/
|
||||
*
|
||||
* Multipart req.files:
|
||||
*
|
||||
* As a security measure files are stored in a separate object, stored
|
||||
* as `req.files`. This prevents attacks that may potentially alter
|
||||
* filenames, and depending on the application gain access to restricted files.
|
||||
*
|
||||
* Multipart configuration:
|
||||
*
|
||||
* The `options` passed are provided to each parser function.
|
||||
* The _multipart/form-data_ parser merges these with formidable's
|
||||
* IncomingForm object, allowing you to tweak the upload directory,
|
||||
* size limits, etc. For example you may wish to retain the file extension
|
||||
* and change the upload directory:
|
||||
*
|
||||
* server.use(bodyParser({ uploadDir: '/www/mysite.com/uploads' }));
|
||||
*
|
||||
* View [node-formidable](https://github.com/felixge/node-formidable) for more information.
|
||||
*
|
||||
* If you wish to use formidable directly within your app, and do not
|
||||
* desire this behaviour for multipart requests simply remove the
|
||||
* parser:
|
||||
*
|
||||
* delete connect.bodyParser.parse['multipart/form-data'];
|
||||
*
|
||||
* Or
|
||||
*
|
||||
* delete express.bodyParser.parse['multipart/form-data'];
|
||||
*
|
||||
* @param {Object} options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports = module.exports = function bodyParser(options){
|
||||
options = options || {};
|
||||
return function bodyParser(req, res, next) {
|
||||
if (req.body) return next();
|
||||
req.body = {};
|
||||
|
||||
if ('GET' == req.method || 'HEAD' == req.method) return next();
|
||||
var parser = exports.parse[mime(req)];
|
||||
if (parser) {
|
||||
parser(req, options, next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Parsers.
|
||||
*/
|
||||
|
||||
exports.parse = {};
|
||||
|
||||
/**
|
||||
* Parse application/x-www-form-urlencoded.
|
||||
*/
|
||||
|
||||
exports.parse['application/x-www-form-urlencoded'] = function(req, options, fn){
|
||||
var buf = '';
|
||||
req.setEncoding('utf8');
|
||||
req.on('data', function(chunk){ buf += chunk });
|
||||
req.on('end', function(){
|
||||
try {
|
||||
req.body = buf.length
|
||||
? qs.parse(buf)
|
||||
: {};
|
||||
fn();
|
||||
} catch (err){
|
||||
fn(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse application/json.
|
||||
*/
|
||||
|
||||
exports.parse['application/json'] = function(req, options, fn){
|
||||
var buf = '';
|
||||
req.setEncoding('utf8');
|
||||
req.on('data', function(chunk){ buf += chunk });
|
||||
req.on('end', function(){
|
||||
try {
|
||||
req.body = buf.length
|
||||
? JSON.parse(buf)
|
||||
: {};
|
||||
fn();
|
||||
} catch (err){
|
||||
fn(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse multipart/form-data.
|
||||
*
|
||||
* TODO: make multiple support optional
|
||||
* TODO: revisit "error" flag if it's a formidable bug
|
||||
*/
|
||||
|
||||
exports.parse['multipart/form-data'] = function(req, options, fn){
|
||||
var form = new formidable.IncomingForm
|
||||
, data = {}
|
||||
, files = {}
|
||||
, done;
|
||||
|
||||
Object.keys(options).forEach(function(key){
|
||||
form[key] = options[key];
|
||||
});
|
||||
|
||||
function ondata(name, val, data){
|
||||
if (Array.isArray(data[name])) {
|
||||
data[name].push(val);
|
||||
} else if (data[name]) {
|
||||
data[name] = [data[name], val];
|
||||
} else {
|
||||
data[name] = val;
|
||||
}
|
||||
}
|
||||
|
||||
form.on('field', function(name, val){
|
||||
ondata(name, val, data);
|
||||
});
|
||||
|
||||
form.on('file', function(name, val){
|
||||
ondata(name, val, files);
|
||||
});
|
||||
|
||||
form.on('error', function(err){
|
||||
fn(err);
|
||||
done = true;
|
||||
});
|
||||
|
||||
form.on('end', function(){
|
||||
if (done) return;
|
||||
try {
|
||||
req.body = qs.parse(data);
|
||||
req.files = qs.parse(files);
|
||||
fn();
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
});
|
||||
|
||||
form.parse(req);
|
||||
};
|
||||
163
example/node/node_modules/express/node_modules/connect/lib/middleware/compiler.js
generated
vendored
Normal file
163
example/node/node_modules/express/node_modules/connect/lib/middleware/compiler.js
generated
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
|
||||
/*!
|
||||
* Connect - compiler
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, path = require('path')
|
||||
, parse = require('url').parse;
|
||||
|
||||
/**
|
||||
* Require cache.
|
||||
*/
|
||||
|
||||
var cache = {};
|
||||
|
||||
/**
|
||||
* Setup compiler.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `src` Source directory, defaults to **CWD**.
|
||||
* - `dest` Destination directory, defaults `src`.
|
||||
* - `enable` Array of enabled compilers.
|
||||
*
|
||||
* Compilers:
|
||||
*
|
||||
* - `sass` Compiles sass to css
|
||||
* - `less` Compiles less to css
|
||||
* - `coffeescript` Compiles coffee to js
|
||||
*
|
||||
* @param {Object} options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports = module.exports = function compiler(options){
|
||||
options = options || {};
|
||||
|
||||
var srcDir = options.src || process.cwd()
|
||||
, destDir = options.dest || srcDir
|
||||
, enable = options.enable;
|
||||
|
||||
if (!enable || enable.length === 0) {
|
||||
throw new Error('compiler\'s "enable" option is not set, nothing will be compiled.');
|
||||
}
|
||||
|
||||
return function compiler(req, res, next){
|
||||
if ('GET' != req.method) return next();
|
||||
var pathname = parse(req.url).pathname;
|
||||
for (var i = 0, len = enable.length; i < len; ++i) {
|
||||
var name = enable[i]
|
||||
, compiler = compilers[name];
|
||||
if (compiler.match.test(pathname)) {
|
||||
var src = (srcDir + pathname).replace(compiler.match, compiler.ext)
|
||||
, dest = destDir + pathname;
|
||||
|
||||
// Compare mtimes
|
||||
fs.stat(src, function(err, srcStats){
|
||||
if (err) {
|
||||
if ('ENOENT' == err.code) {
|
||||
next();
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
} else {
|
||||
fs.stat(dest, function(err, destStats){
|
||||
if (err) {
|
||||
// Oh snap! it does not exist, compile it
|
||||
if ('ENOENT' == err.code) {
|
||||
compile();
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
} else {
|
||||
// Source has changed, compile it
|
||||
if (srcStats.mtime > destStats.mtime) {
|
||||
compile();
|
||||
} else {
|
||||
// Defer file serving
|
||||
next();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Compile to the destination
|
||||
function compile() {
|
||||
fs.readFile(src, 'utf8', function(err, str){
|
||||
if (err) {
|
||||
next(err);
|
||||
} else {
|
||||
compiler.compile(str, function(err, str){
|
||||
if (err) {
|
||||
next(err);
|
||||
} else {
|
||||
fs.writeFile(dest, str, 'utf8', function(err){
|
||||
next(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Bundled compilers:
|
||||
*
|
||||
* - [sass](http://github.com/visionmedia/sass.js) to _css_
|
||||
* - [less](http://github.com/cloudhead/less.js) to _css_
|
||||
* - [coffee](http://github.com/jashkenas/coffee-script) to _js_
|
||||
*/
|
||||
|
||||
var compilers = exports.compilers = {
|
||||
sass: {
|
||||
match: /\.css$/,
|
||||
ext: '.sass',
|
||||
compile: function(str, fn){
|
||||
var sass = cache.sass || (cache.sass = require('sass'));
|
||||
try {
|
||||
fn(null, sass.render(str));
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
}
|
||||
},
|
||||
less: {
|
||||
match: /\.css$/,
|
||||
ext: '.less',
|
||||
compile: function(str, fn){
|
||||
var less = cache.less || (cache.less = require('less'));
|
||||
try {
|
||||
less.render(str, fn);
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
}
|
||||
},
|
||||
coffeescript: {
|
||||
match: /\.js$/,
|
||||
ext: '.coffee',
|
||||
compile: function(str, fn){
|
||||
var coffee = cache.coffee || (cache.coffee = require('coffee-script'));
|
||||
try {
|
||||
fn(null, coffee.compile(str));
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
46
example/node/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js
generated
vendored
Normal file
46
example/node/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
/*!
|
||||
* Connect - cookieParser
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('./../utils');
|
||||
|
||||
/**
|
||||
* Parse _Cookie_ header and populate `req.cookies`
|
||||
* with an object keyed by the cookie names.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* connect.createServer(
|
||||
* connect.cookieParser()
|
||||
* , function(req, res, next){
|
||||
* res.end(JSON.stringify(req.cookies));
|
||||
* }
|
||||
* );
|
||||
*
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function cookieParser(){
|
||||
return function cookieParser(req, res, next) {
|
||||
var cookie = req.headers.cookie;
|
||||
if (req.cookies) return next();
|
||||
req.cookies = {};
|
||||
if (cookie) {
|
||||
try {
|
||||
req.cookies = utils.parseCookie(cookie);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
105
example/node/node_modules/express/node_modules/connect/lib/middleware/csrf.js
generated
vendored
Normal file
105
example/node/node_modules/express/node_modules/connect/lib/middleware/csrf.js
generated
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
/*!
|
||||
* Connect - csrf
|
||||
* Copyright(c) 2011 Sencha Inc.
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('../utils')
|
||||
, crypto = require('crypto');
|
||||
|
||||
/**
|
||||
* CRSF protection middleware.
|
||||
*
|
||||
* By default this middleware generates a token named "_csrf"
|
||||
* which should be added to requests which mutate
|
||||
* state, within a hidden form field, query-string etc. This
|
||||
* token is validated against the visitor's `req.session._csrf`
|
||||
* property which is re-generated per request.
|
||||
*
|
||||
* The default `value` function checks `req.body` generated
|
||||
* by the `bodyParser()` middleware, `req.query` generated
|
||||
* by `query()`, and the "X-CSRF-Token" header field.
|
||||
*
|
||||
* This middleware requires session support, thus should be added
|
||||
* somewhere _below_ `session()` and `cookieParser()`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var form = '\n\
|
||||
* <form action="/" method="post">\n\
|
||||
* <input type="hidden" name="_csrf" value="{token}" />\n\
|
||||
* <input type="text" name="user[name]" value="{user}" />\n\
|
||||
* <input type="password" name="user[pass]" />\n\
|
||||
* <input type="submit" value="Login" />\n\
|
||||
* </form>\n\
|
||||
* ';
|
||||
*
|
||||
* connect(
|
||||
* connect.cookieParser()
|
||||
* , connect.session({ secret: 'keyboard cat' })
|
||||
* , connect.bodyParser()
|
||||
* , connect.csrf()
|
||||
*
|
||||
* , function(req, res, next){
|
||||
* if ('POST' != req.method) return next();
|
||||
* req.session.user = req.body.user;
|
||||
* next();
|
||||
* }
|
||||
*
|
||||
* , function(req, res){
|
||||
* res.setHeader('Content-Type', 'text/html');
|
||||
* var body = form
|
||||
* .replace('{token}', req.session._csrf)
|
||||
* .replace('{user}', req.session.user && req.session.user.name || '');
|
||||
* res.end(body);
|
||||
* }
|
||||
* ).listen(3000);
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `value` a function accepting the request, returning the token
|
||||
*
|
||||
* @param {Object} options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function csrf(options) {
|
||||
var options = options || {}
|
||||
, value = options.value || defaultValue;
|
||||
|
||||
return function(req, res, next){
|
||||
// generate CSRF token
|
||||
var token = req.session._csrf || (req.session._csrf = utils.uid(24));
|
||||
|
||||
// ignore GET (for now)
|
||||
if ('GET' == req.method) return next();
|
||||
|
||||
// determine value
|
||||
var val = value(req);
|
||||
|
||||
// check
|
||||
if (val != token) return utils.forbidden(res);
|
||||
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Default value function, checking the `req.body`
|
||||
* and `req.query` for the CSRF token.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function defaultValue(req) {
|
||||
return (req.body && req.body._csrf)
|
||||
|| (req.query && req.query._csrf)
|
||||
|| (req.headers['x-csrf-token']);
|
||||
}
|
||||
222
example/node/node_modules/express/node_modules/connect/lib/middleware/directory.js
generated
vendored
Normal file
222
example/node/node_modules/express/node_modules/connect/lib/middleware/directory.js
generated
vendored
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
|
||||
/*!
|
||||
* Connect - directory
|
||||
* Copyright(c) 2011 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
// TODO: icon / style for directories
|
||||
// TODO: arrow key navigation
|
||||
// TODO: make icons extensible
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, parse = require('url').parse
|
||||
, utils = require('../utils')
|
||||
, path = require('path')
|
||||
, normalize = path.normalize
|
||||
, extname = path.extname
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
* Icon cache.
|
||||
*/
|
||||
|
||||
var cache = {};
|
||||
|
||||
/**
|
||||
* Serve directory listings with the given `root` path.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `hidden` display hidden (dot) files. Defaults to false.
|
||||
* - `icons` display icons. Defaults to false.
|
||||
* - `filter` Apply this filter function to files. Defaults to false.
|
||||
*
|
||||
* @param {String} root
|
||||
* @param {Object} options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports = module.exports = function directory(root, options){
|
||||
options = options || {};
|
||||
|
||||
// root required
|
||||
if (!root) throw new Error('directory() root path required');
|
||||
var hidden = options.hidden
|
||||
, icons = options.icons
|
||||
, filter = options.filter
|
||||
, root = normalize(root);
|
||||
|
||||
return function directory(req, res, next) {
|
||||
var accept = req.headers.accept || 'text/plain'
|
||||
, url = parse(req.url)
|
||||
, dir = decodeURIComponent(url.pathname)
|
||||
, path = normalize(join(root, dir))
|
||||
, originalUrl = parse(req.originalUrl)
|
||||
, originalDir = decodeURIComponent(originalUrl.pathname)
|
||||
, showUp = path != root && path != root + '/';
|
||||
|
||||
// null byte(s)
|
||||
if (~path.indexOf('\0')) return utils.badRequest(res);
|
||||
|
||||
// malicious path
|
||||
if (0 != path.indexOf(root)) return utils.forbidden(res);
|
||||
|
||||
// check if we have a directory
|
||||
fs.stat(path, function(err, stat){
|
||||
if (err) return 'ENOENT' == err.code
|
||||
? next()
|
||||
: next(err);
|
||||
|
||||
if (!stat.isDirectory()) return next();
|
||||
|
||||
// fetch files
|
||||
fs.readdir(path, function(err, files){
|
||||
if (err) return next(err);
|
||||
if (!hidden) files = removeHidden(files);
|
||||
if (filter) files = files.filter(filter);
|
||||
files.sort();
|
||||
// content-negotiation
|
||||
for (var key in exports) {
|
||||
if (~accept.indexOf(key) || ~accept.indexOf('*/*')) {
|
||||
exports[key](req, res, files, next, originalDir, showUp, icons);
|
||||
return;
|
||||
}
|
||||
}
|
||||
utils.notAcceptable(res);
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond with text/html.
|
||||
*/
|
||||
|
||||
exports.html = function(req, res, files, next, dir, showUp, icons){
|
||||
fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){
|
||||
if (err) return next(err);
|
||||
fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){
|
||||
if (err) return next(err);
|
||||
if (showUp) files.unshift('..');
|
||||
str = str
|
||||
.replace('{style}', style)
|
||||
.replace('{files}', html(files, dir, icons))
|
||||
.replace('{directory}', dir)
|
||||
.replace('{linked-path}', htmlPath(dir));
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.setHeader('Content-Length', str.length);
|
||||
res.end(str);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond with application/json.
|
||||
*/
|
||||
|
||||
exports.json = function(req, res, files){
|
||||
files = JSON.stringify(files);
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.setHeader('Content-Length', files.length);
|
||||
res.end(files);
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond with text/plain.
|
||||
*/
|
||||
|
||||
exports.plain = function(req, res, files){
|
||||
files = files.join('\n') + '\n';
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.setHeader('Content-Length', files.length);
|
||||
res.end(files);
|
||||
};
|
||||
|
||||
/**
|
||||
* Map html `dir`, returning a linked path.
|
||||
*/
|
||||
|
||||
function htmlPath(dir) {
|
||||
var curr = [];
|
||||
return dir.split('/').map(function(part){
|
||||
curr.push(part);
|
||||
return '<a href="' + curr.join('/') + '">' + part + '</a>';
|
||||
}).join(' / ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Map html `files`, returning an html unordered list.
|
||||
*/
|
||||
|
||||
function html(files, dir, useIcons) {
|
||||
return '<ul id="files">' + files.map(function(file){
|
||||
var icon = ''
|
||||
, classes = [];
|
||||
|
||||
if (useIcons && '..' != file) {
|
||||
icon = icons[extname(file)] || icons.default;
|
||||
icon = '<img src="data:image/png;base64,' + load(icon) + '" />';
|
||||
classes.push('icon');
|
||||
}
|
||||
|
||||
return '<li><a href="'
|
||||
+ join(dir, file)
|
||||
+ '" class="'
|
||||
+ classes.join(' ') + '"'
|
||||
+ ' title="' + file + '">'
|
||||
+ icon + file + '</a></li>';
|
||||
|
||||
}).join('\n') + '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and cache the given `icon`.
|
||||
*
|
||||
* @param {String} icon
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function load(icon) {
|
||||
if (cache[icon]) return cache[icon];
|
||||
return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64');
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter "hidden" `files`, aka files
|
||||
* beginning with a `.`.
|
||||
*
|
||||
* @param {Array} files
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function removeHidden(files) {
|
||||
return files.filter(function(file){
|
||||
return '.' != file[0];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon map.
|
||||
*/
|
||||
|
||||
var icons = {
|
||||
'.js': 'page_white_code_red.png'
|
||||
, '.c': 'page_white_c.png'
|
||||
, '.h': 'page_white_h.png'
|
||||
, '.cc': 'page_white_cplusplus.png'
|
||||
, '.php': 'page_white_php.png'
|
||||
, '.rb': 'page_white_ruby.png'
|
||||
, '.cpp': 'page_white_cplusplus.png'
|
||||
, '.swf': 'page_white_flash.png'
|
||||
, '.pdf': 'page_white_acrobat.png'
|
||||
, 'default': 'page_white.png'
|
||||
};
|
||||
100
example/node/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js
generated
vendored
Normal file
100
example/node/node_modules/express/node_modules/connect/lib/middleware/errorHandler.js
generated
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*!
|
||||
* Connect - errorHandler
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('../utils')
|
||||
, url = require('url')
|
||||
, fs = require('fs');
|
||||
|
||||
/**
|
||||
* Flexible error handler, providing (_optional_) stack traces
|
||||
* and error message responses for requests accepting text, html,
|
||||
* or json.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `showStack`, `stack` respond with both the error message and stack trace. Defaults to `false`
|
||||
* - `showMessage`, `message`, respond with the exception message only. Defaults to `false`
|
||||
* - `dumpExceptions`, `dump`, dump exceptions to stderr (without terminating the process). Defaults to `false`
|
||||
*
|
||||
* Text:
|
||||
*
|
||||
* By default, and when _text/plain_ is accepted a simple stack trace
|
||||
* or error message will be returned.
|
||||
*
|
||||
* JSON:
|
||||
*
|
||||
* When _application/json_ is accepted, connect will respond with
|
||||
* an object in the form of `{ "error": error }`.
|
||||
*
|
||||
* HTML:
|
||||
*
|
||||
* When accepted connect will output a nice html stack trace.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports = module.exports = function errorHandler(options){
|
||||
options = options || {};
|
||||
|
||||
// defaults
|
||||
var showStack = options.showStack || options.stack
|
||||
, showMessage = options.showMessage || options.message
|
||||
, dumpExceptions = options.dumpExceptions || options.dump
|
||||
, formatUrl = options.formatUrl;
|
||||
|
||||
return function errorHandler(err, req, res, next){
|
||||
res.statusCode = 500;
|
||||
if (dumpExceptions) console.error(err.stack);
|
||||
if (showStack) {
|
||||
var accept = req.headers.accept || '';
|
||||
// html
|
||||
if (~accept.indexOf('html')) {
|
||||
fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){
|
||||
fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){
|
||||
var stack = (err.stack || '')
|
||||
.split('\n').slice(1)
|
||||
.map(function(v){ return '<li>' + v + '</li>'; }).join('');
|
||||
html = html
|
||||
.replace('{style}', style)
|
||||
.replace('{stack}', stack)
|
||||
.replace('{title}', exports.title)
|
||||
.replace(/\{error\}/g, utils.escape(err.toString()));
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end(html);
|
||||
});
|
||||
});
|
||||
// json
|
||||
} else if (~accept.indexOf('json')) {
|
||||
var json = JSON.stringify({ error: err });
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(json);
|
||||
// plain text
|
||||
} else {
|
||||
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
||||
res.end(err.stack);
|
||||
}
|
||||
} else {
|
||||
var body = showMessage
|
||||
? err.toString()
|
||||
: 'Internal Server Error';
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.end(body);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Template title.
|
||||
*/
|
||||
|
||||
exports.title = 'Connect';
|
||||
76
example/node/node_modules/express/node_modules/connect/lib/middleware/favicon.js
generated
vendored
Normal file
76
example/node/node_modules/express/node_modules/connect/lib/middleware/favicon.js
generated
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
/*!
|
||||
* Connect - favicon
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Favicon cache.
|
||||
*/
|
||||
|
||||
var icon;
|
||||
|
||||
/**
|
||||
* By default serves the connect favicon, or the favicon
|
||||
* located by the given `path`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` cache-control max-age directive, defaulting to 1 day
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* connect.createServer(
|
||||
* connect.favicon()
|
||||
* );
|
||||
*
|
||||
* connect.createServer(
|
||||
* connect.favicon(__dirname + '/public/favicon.ico')
|
||||
* );
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Object} options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function favicon(path, options){
|
||||
var options = options || {}
|
||||
, path = path || __dirname + '/../public/favicon.ico'
|
||||
, maxAge = options.maxAge || 86400000;
|
||||
|
||||
return function favicon(req, res, next){
|
||||
if ('/favicon.ico' == req.url) {
|
||||
if (icon) {
|
||||
res.writeHead(200, icon.headers);
|
||||
res.end(icon.body);
|
||||
} else {
|
||||
fs.readFile(path, function(err, buf){
|
||||
if (err) return next(err);
|
||||
icon = {
|
||||
headers: {
|
||||
'Content-Type': 'image/x-icon'
|
||||
, 'Content-Length': buf.length
|
||||
, 'ETag': '"' + utils.md5(buf) + '"'
|
||||
, 'Cache-Control': 'public, max-age=' + (maxAge / 1000)
|
||||
},
|
||||
body: buf
|
||||
};
|
||||
res.writeHead(200, icon.headers);
|
||||
res.end(icon.body);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
};
|
||||
80
example/node/node_modules/express/node_modules/connect/lib/middleware/limit.js
generated
vendored
Normal file
80
example/node/node_modules/express/node_modules/connect/lib/middleware/limit.js
generated
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
/*!
|
||||
* Connect - limit
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Limit request bodies to the given size in `bytes`.
|
||||
*
|
||||
* A string representation of the bytesize may also be passed,
|
||||
* for example "5mb", "200kb", "1gb", etc.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var server = connect(
|
||||
* connect.limit('5.5mb')
|
||||
* ).listen(3000);
|
||||
*
|
||||
* @param {Number|String} bytes
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function limit(bytes){
|
||||
if ('string' == typeof bytes) bytes = parse(bytes);
|
||||
if ('number' != typeof bytes) throw new Error('limit() bytes required');
|
||||
return function limit(req, res, next){
|
||||
var received = 0
|
||||
, len = req.headers['content-length']
|
||||
? parseInt(req.headers['content-length'], 10)
|
||||
: null;
|
||||
|
||||
// deny the request
|
||||
function deny() {
|
||||
req.destroy();
|
||||
}
|
||||
|
||||
// self-awareness
|
||||
if (req._limit) return next();
|
||||
req._limit = true;
|
||||
|
||||
// limit by content-length
|
||||
if (len && len > bytes) {
|
||||
res.statusCode = 413;
|
||||
res.end('Request Entity Too Large');
|
||||
return;
|
||||
}
|
||||
|
||||
// limit
|
||||
req.on('data', function(chunk){
|
||||
received += chunk.length;
|
||||
if (received > bytes) deny();
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse byte `size` string.
|
||||
*
|
||||
* @param {String} size
|
||||
* @return {Number}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function parse(size) {
|
||||
var parts = size.match(/^(\d+(?:\.\d+)?) *(kb|mb|gb)$/)
|
||||
, n = parseFloat(parts[1])
|
||||
, type = parts[2];
|
||||
|
||||
var map = {
|
||||
kb: 1024
|
||||
, mb: 1024 * 1024
|
||||
, gb: 1024 * 1024 * 1024
|
||||
};
|
||||
|
||||
return map[type] * n;
|
||||
}
|
||||
299
example/node/node_modules/express/node_modules/connect/lib/middleware/logger.js
generated
vendored
Normal file
299
example/node/node_modules/express/node_modules/connect/lib/middleware/logger.js
generated
vendored
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
|
||||
/*!
|
||||
* Connect - logger
|
||||
* Copyright(c) 2010 Sencha Inc.
|
||||
* Copyright(c) 2011 TJ Holowaychuk
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Log buffer.
|
||||
*/
|
||||
|
||||
var buf = [];
|
||||
|
||||
/**
|
||||
* Default log buffer duration.
|
||||
*/
|
||||
|
||||
var defaultBufferDuration = 1000;
|
||||
|
||||
/**
|
||||
* Log requests with the given `options` or a `format` string.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `format` Format string, see below for tokens
|
||||
* - `stream` Output stream, defaults to _stdout_
|
||||
* - `buffer` Buffer duration, defaults to 1000ms when _true_
|
||||
* - `immediate` Write log line on request instead of response (for response times)
|
||||
*
|
||||
* Tokens:
|
||||
*
|
||||
* - `:req[header]` ex: `:req[Accept]`
|
||||
* - `:res[header]` ex: `:res[Content-Length]`
|
||||
* - `:http-version`
|
||||
* - `:response-time`
|
||||
* - `:remote-addr`
|
||||
* - `:date`
|
||||
* - `:method`
|
||||
* - `:url`
|
||||
* - `:referrer`
|
||||
* - `:user-agent`
|
||||
* - `:status`
|
||||
*
|
||||
* Formats:
|
||||
*
|
||||
* Pre-defined formats that ship with connect:
|
||||
*
|
||||
* - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
|
||||
* - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
|
||||
* - `tiny` ':method :url :status :res[content-length] - :response-time ms'
|
||||
* - `dev` concise output colored by response status for development use
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* connect.logger() // default
|
||||
* connect.logger('short')
|
||||
* connect.logger('tiny')
|
||||
* connect.logger('dev')
|
||||
* connect.logger(':method :url - :referrer')
|
||||
* connect.logger(':req[content-type] -> :res[content-type]')
|
||||
* connect.logger(function(req, res){ return 'some format string' })
|
||||
*
|
||||
* Defining Tokens:
|
||||
*
|
||||
* To define a token, simply invoke `connect.logger.token()` with the
|
||||
* name and a callback function. The value returned is then available
|
||||
* as ":type" in this case.
|
||||
*
|
||||
* connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
|
||||
*
|
||||
* Defining Formats:
|
||||
*
|
||||
* All default formats are defined this way, however it's public API as well:
|
||||
*
|
||||
* connect.logger.format('name', 'string or function')
|
||||
*
|
||||
* @param {String|Function|Object} format or options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports = module.exports = function logger(options) {
|
||||
if ('object' == typeof options) {
|
||||
options = options || {};
|
||||
} else if (options) {
|
||||
options = { format: options };
|
||||
} else {
|
||||
options = {};
|
||||
}
|
||||
|
||||
// output on request instead of response
|
||||
var immediate = options.immediate;
|
||||
|
||||
// format name
|
||||
var fmt = exports[options.format] || options.format || exports.default;
|
||||
|
||||
// compile format
|
||||
if ('function' != typeof fmt) fmt = compile(fmt);
|
||||
|
||||
// options
|
||||
var stream = options.stream || process.stdout
|
||||
, buffer = options.buffer;
|
||||
|
||||
// buffering support
|
||||
if (buffer) {
|
||||
var realStream = stream
|
||||
, interval = 'number' == typeof buffer
|
||||
? buffer
|
||||
: defaultBufferDuration;
|
||||
|
||||
// flush interval
|
||||
setInterval(function(){
|
||||
if (buf.length) {
|
||||
realStream.write(buf.join(''), 'ascii');
|
||||
buf.length = 0;
|
||||
}
|
||||
}, interval);
|
||||
|
||||
// swap the stream
|
||||
stream = {
|
||||
write: function(str){
|
||||
buf.push(str);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return function logger(req, res, next) {
|
||||
req._startTime = new Date;
|
||||
|
||||
// mount safety
|
||||
if (req._logging) return next();
|
||||
|
||||
// flag as logging
|
||||
req._logging = true;
|
||||
|
||||
// immediate
|
||||
if (immediate) {
|
||||
var line = fmt(exports, req, res);
|
||||
if (null == line) return;
|
||||
stream.write(line + '\n', 'ascii');
|
||||
} else {
|
||||
// proxy end to output loggging
|
||||
var end = res.end;
|
||||
res.end = function(chunk, encoding){
|
||||
res.end = end;
|
||||
res.end(chunk, encoding);
|
||||
var line = fmt(exports, req, res);
|
||||
if (null == line) return;
|
||||
stream.write(line + '\n', 'ascii');
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Compile `fmt` into a function.
|
||||
*
|
||||
* @param {String} fmt
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function compile(fmt) {
|
||||
fmt = fmt.replace(/"/g, '\\"');
|
||||
var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
|
||||
return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
|
||||
}) + '";'
|
||||
return new Function('tokens, req, res', js);
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a token function with the given `name`,
|
||||
* and callback `fn(req, res)`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Function} fn
|
||||
* @return {Object} exports for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.token = function(name, fn) {
|
||||
exports[name] = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a `fmt` with the given `name`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String|Function} fmt
|
||||
* @return {Object} exports for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.format = function(name, str){
|
||||
exports[name] = str;
|
||||
return this;
|
||||
};
|
||||
|
||||
// default format
|
||||
|
||||
exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');
|
||||
|
||||
// short format
|
||||
|
||||
exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');
|
||||
|
||||
// tiny format
|
||||
|
||||
exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');
|
||||
|
||||
// dev (colored)
|
||||
|
||||
exports.format('dev', function(tokens, req, res){
|
||||
var status = res.statusCode
|
||||
, color = 32;
|
||||
|
||||
if (status >= 500) color = 31
|
||||
else if (status >= 400) color = 33
|
||||
else if (status >= 300) color = 36;
|
||||
|
||||
return '\033[90m' + req.method
|
||||
+ ' ' + req.originalUrl + ' '
|
||||
+ '\033[' + color + 'm' + res.statusCode
|
||||
+ ' \033[90m'
|
||||
+ (new Date - req._startTime)
|
||||
+ 'ms\033[0m';
|
||||
});
|
||||
|
||||
// request url
|
||||
|
||||
exports.token('url', function(req){
|
||||
return req.originalUrl;
|
||||
});
|
||||
|
||||
// request method
|
||||
|
||||
exports.token('method', function(req){
|
||||
return req.method;
|
||||
});
|
||||
|
||||
// response time in milliseconds
|
||||
|
||||
exports.token('response-time', function(req){
|
||||
return new Date - req._startTime;
|
||||
});
|
||||
|
||||
// UTC date
|
||||
|
||||
exports.token('date', function(){
|
||||
return new Date().toUTCString();
|
||||
});
|
||||
|
||||
// response status code
|
||||
|
||||
exports.token('status', function(req, res){
|
||||
return res.statusCode;
|
||||
});
|
||||
|
||||
// normalized referrer
|
||||
|
||||
exports.token('referrer', function(req){
|
||||
return req.headers['referer'] || req.headers['referrer'];
|
||||
});
|
||||
|
||||
// remote address
|
||||
|
||||
exports.token('remote-addr', function(req){
|
||||
return req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.remoteAddress));
|
||||
});
|
||||
|
||||
// HTTP version
|
||||
|
||||
exports.token('http-version', function(req){
|
||||
return req.httpVersionMajor + '.' + req.httpVersionMinor;
|
||||
});
|
||||
|
||||
// UA string
|
||||
|
||||
exports.token('user-agent', function(req){
|
||||
return req.headers['user-agent'];
|
||||
});
|
||||
|
||||
// request header
|
||||
|
||||
exports.token('req', function(req, res, field){
|
||||
return req.headers[field.toLowerCase()];
|
||||
});
|
||||
|
||||
// response header
|
||||
|
||||
exports.token('res', function(req, res, field){
|
||||
return (res._headers || {})[field.toLowerCase()];
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue