little css

This commit is contained in:
2013-02-14 08:18:17 -05:00
parent e96147b7ff
commit b603f2404c
73 changed files with 6191 additions and 24 deletions

5
app.js
View File

@@ -12,11 +12,13 @@ var dbURL = 'mongodb://localhost/database';
var db = require('mongoose').connect(dbURL);
var qs = require('qs');
var MongoStore = require('connect-mongo')(express);
var gzippo = require('gzippo');
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.compress());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('my secret string'));
@@ -34,7 +36,8 @@ app.configure(function(){
next();
});
app.set('port', 3000);
app.use(express.static(__dirname + '/public'));
//app.use(express.static(__dirname + '/public'));
app.use(gzippo.staticGzip(__dirname + '/public', {contentTypeMatch: /text|javascript|json|svg/}));
app.use(app.router);
});

13
node_modules/gzippo/.npmignore generated vendored Normal file
View File

@@ -0,0 +1,13 @@
node_modules/*
.DS_STORE
*.swp
*.monitor
nodemon-ignore
.*.sw[a-z]
*.un~i
.DS_Store
Icon?
._*
.Spotlight-V100
.Trashes
bench/*

4
node_modules/gzippo/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.6
- 0.8

5
node_modules/gzippo/CHANGELOG generated vendored Normal file
View File

@@ -0,0 +1,5 @@
Changes from version 0.1 to 0.2:
`clientMaxAge` now defaults to 0.
Zlib Deflate support
Gzippo should now support external stores, gridfs, redis etc...

70
node_modules/gzippo/README.md generated vendored Normal file
View File

@@ -0,0 +1,70 @@
# gzippo [![Build Status](https://secure.travis-ci.org/tomgco/gzippo.png?branch=master)](https://secure.travis-ci.org/tomgco/gzippo)
gzippo pronounced `g-zippo` is a gzip middleware for Connect / expressjs using node-compress for better performace, in node 0.6 and up will be using the new zlib api.
gzippo currently only supports only gzipping static content files however a release is in progress to introduce streaming support.
## Notice
Please note that gzippo@0.0.X branch will only be tested for nodejs 0.4, where the soon to be released gzippo@0.1.X will work for node 0.6
## Installation
$ npm install gzippo
### Usage
#### Static Gzip
In your express/connect server setup, use as follows:
var gzippo = require('gzippo');
//Replace the static provider with gzippo's
//app.use(express.static(__dirname + '/public'));
app.use(gzippo.staticGzip(__dirname + '/public'));
Options:
- `contentTypeMatch` - A regular expression tested against the Content-Type header to determine whether the response should be gzipped or not. The default value is `/text|javascript|json/`.
- `maxAge` - cache-control max-age directive, defaulting to 1 day
- `clientMaxAge` - browser cache-control max-age directive, defaulting to 1 week
- `prefix` - A url prefix. If you want all your static content in a root path such as /resource/. Any url paths not matching will be ignored
Currently the gzipped version is created and stored in memory. This is not final and was done to get a working version
up and about.
Gzippo now uses the native Zlib support found in node >= 0.6
#### Streaming Gzip
Starting in Connect 2.X Expressjs has the ability to use a streaming gzip module provided natively by connect. As this 2.X branch is not currently stable I have back ported the compress.js component into gzippo.
app.use(gzippo.staticGzip(__dirname + '/public'));
app.use(gzippo.compress());
This has no caching and is currently unsupported as it will be included in a future connect 1.X release, up until then compress.js will be included in gzippo.
## License
(The MIT License)
Copyright (c) 2011 Tom Gallacher &lt;<http://www.tomg.co>&gt;
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.

3
node_modules/gzippo/index.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
exports.staticGzip = require('./lib/staticGzip.js');
exports.compress = require('./lib/compress.js');
exports.Store = require('./lib/store.js');

139
node_modules/gzippo/lib/compress.js generated vendored Normal file
View File

@@ -0,0 +1,139 @@
/*!
* Connect - compress
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var zlib = require('zlib');
/**
* Supported content-encoding methods.
*/
exports.methods = {
gzip: zlib.createGzip,
deflate: zlib.createDeflate
};
/**
* Default filter function.
*/
exports.filter = function(req, res){
var type = res.getHeader('Content-Type') || '';
return type.match(/json|text|javascript/);
};
/**
* Compress response data with gzip/deflate.
*
* Filter:
*
* A `filter` callback function may be passed to
* replace the default logic of:
*
* exports.filter = function(req, res){
* var type = res.getHeader('Content-Type') || '';
* return type.match(/json|text|javascript/);
* };
*
* Options:
*
* All remaining options are passed to the gzip/deflate
* creation functions. Consult node's docs for additional details.
*
* - `chunkSize` (default: 16*1024)
* - `windowBits`
* - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
* - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
* - `strategy`: compression strategy
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function compress(options) {
var options = options || {}
, names = Object.keys(exports.methods)
, filter = options.filter || exports.filter;
return function(req, res, next){
var accept = req.headers['accept-encoding']
, write = res.write
, end = res.end
, stream
, method;
// vary
res.setHeader('Vary', 'Accept-Encoding');
// proxy
res.write = function(chunk, encoding){
if (!this.headerSent) this._implicitHeader();
return stream
? stream.write(chunk, encoding)
: write.call(res, chunk, encoding);
};
res.end = function(chunk, encoding){
if (chunk) this.write(chunk, encoding);
return stream
? stream.end()
: end.call(res);
};
res.on('header', function(){
// default request filter
if (!filter(req, res)) return;
// SHOULD use identity
if (!accept) return;
// head
if ('HEAD' == req.method) return;
// default to gzip
if ('*' == accept.trim()) method = 'gzip';
// compression method
if (!method) {
for (var i = 0, len = names.length; i < len; ++i) {
if (~accept.indexOf(names[i])) {
method = names[i];
break;
}
}
}
// compression method
if (!method) return;
// compression stream
stream = exports.methods[method](options);
// header fields
res.setHeader('Content-Encoding', method);
res.removeHeader('Content-Length');
// compression
stream.on('data', function(chunk){
write.call(res, chunk);
});
stream.on('end', function(){
end.call(res);
});
});
next();
};
}

61
node_modules/gzippo/lib/fileAsset.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
var FileAsset = module.exports = function FileAsset(name, options) {
options = options || {};
this._maxAge = options.maxAge || 86400000;
this._mtime = options.mtime || new Date();
this._fileName = name;
this._ctime = +Date.now();
this.fileContents = [];
this.fileContentsLength = 0;
};
/**
* Prototype.
*/
FileAsset.prototype = {
set maxAge(maxAge) {
this._maxAge = maxAge;
},
get maxAge() {
return this._maxAge;
},
get mtime() {
return this._mtime;
},
get isExpired() {
return (this._ctime + this._maxAge) < +Date.now();
},
get name() {
return this._fileName;
},
get content() {
// var file = Buffer(this.fileContentsLength);
// var pos = 0;
// for (var i = 0; i < this.fileContents.length; i++) {
// // this.fileContents[i] = this.fileContents[i].toString();
// // buffer.copy(file, pos);
// // pos += buffer.length;
// }
return this.fileContents;
},
get length() {
return this.fileContentsLength;
},
get data() {
return {
expires: this._expires,
mtime: this._mtime,
content: this.content,
length: this.fileContentsLength
};
}
};

103
node_modules/gzippo/lib/memory.js generated vendored Normal file
View File

@@ -0,0 +1,103 @@
/*!
* gzippo - MemoryStore
*
* MIT Licensed
*/
var Store = require('./store'),
util = require('util');
/**
* new `MemoryStore`.
*
* @api public
*/
var MemoryStore = module.exports = function MemoryStore() {
Store.call(this);
this.assets = {};
};
util.inherits(MemoryStore, Store);
/**
* Attempt to fetch an asset by its filename - `file`.
*
* @param {String} fileName
* @param {Function} cb
* @api public
*/
MemoryStore.prototype.get = function(fileName, cb) {
var that = this;
process.nextTick(function(){
var expires,
asset = that.assets[fileName];
if (asset) {
// expires = (typeof asset.expires === 'string') ?
// +Date.parse(asset.expires) :
// asset.expires;
// if (!expires || +Date.now() < expires) {
cb(null, asset);
// } else {
// that.purgeFile(file, cb);
// }
} else {
cb();
}
});
};
/**
*
* @param {FileAsset} asset
* @param {Function} cb
* @api public
*/
MemoryStore.prototype.set = function(asset, cb) {
var that = this;
process.nextTick(function() {
that.assets[asset.name] = asset.data;
if(cb instanceof Function) cb();
});
};
/**
* purge the cache
*
* @param {Function} cb
* @api public
*/
MemoryStore.prototype.purge = function(cb){
this.assets = {};
if(cb instanceof Function) cb();
};
/**
* purge the an item from thecache
*
* @param {FileAsset} asset
* @param {Function} cb
* @api public
*/
MemoryStore.prototype.purgeFile = function(asset, cb){
process.nextTick(function() {
delete this.assets[asset.name];
if(cb instanceof Function) cb();
});
};
/**
* Fetch number of cached files.
*
* @param {Function} fn
* @api public
*/
MemoryStore.prototype.length = function(cb){
cb(null, Object.keys(this.assets).length);
};

289
node_modules/gzippo/lib/staticGzip.js generated vendored Normal file
View File

@@ -0,0 +1,289 @@
/*!
* Tom Gallacher
*
* MIT Licensed
*/
/**
* Module dependencies.
*/
// Commented out as I think that connect is avalible from within express...
// try {
// var staticMiddleware = require('connect').static;
// } catch (e) {
// staticMiddleware = require('express').static;
// }
var fs = require('fs'),
parse = require('url').parse,
path = require('path'),
zlib = require('zlib'),
MemoryStore = require('./memory'),
StoreStream = require('./storeStream'),
FileAsset = require('./fileAsset'),
send = require('send'),
mime = send.mime
;
/**
* Strip `Content-*` headers from `res`.
*
* @param {ServerResponse} res
* @api public
*/
var removeContentHeaders = function(res){
Object.keys(res._headers).forEach(function(field){
if (0 === field.indexOf('content')) {
res.removeHeader(field);
}
});
};
/**
* Supported content-encoding methods.
*/
var methods = {
gzip: zlib.createGzip,
deflate: zlib.createDeflate
};
/**
* Default filter function.
*/
exports.filter = function(req, res){
var type = res.getHeader('Content-Type') || '';
return type.match(/json|text|javascript/);
};
/**
* Parse the `req` url with memoization.
*
* @param {ServerRequest} req
* @return {Object}
* @api private
*/
var parseUrl = function(req){
var parsed = req._parsedUrl;
if (parsed && parsed.href == req.url) {
return parsed;
} else {
return req._parsedUrl = parse(req.url);
}
};
/**
* By default gzip's static's that match the given regular expression /text|javascript|json/
* and then serves them with Connects static provider, denoted by the given `dirPath`.
*
* Options:
*
* - `maxAge` how long gzippo should cache gziped assets, defaulting to 1 day
* - `clientMaxAge` client cache-control max-age directive, defaulting to 0; 604800000 is one week.
* - `contentTypeMatch` - A regular expression tested against the Content-Type header to determine whether the response
* should be gzipped or not. The default value is `/text|javascript|json/`.
* - `prefix` - A url prefix. If you want all your static content in a root path such as /resource/. Any url paths not matching will be ignored
*
* Examples:
*
* connect.createServer(
* connect.staticGzip(__dirname + '/public/');
* );
*
* connect.createServer(
* connect.staticGzip(__dirname + '/public/', {maxAge: 86400000});
* );
*
* @param {String} path
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function staticGzip(dirPath, options){
options = options || {};
var maxAge = options.maxAge || 86400000,
contentTypeMatch = options.contentTypeMatch || /text|javascript|json/,
clientMaxAge = options.clientMaxAge || 604800000,
prefix = options.prefix || '',
names = Object.keys(methods),
compressionOptions = options.compression || {},
store = options.store || new MemoryStore();
if (!dirPath) throw new Error('You need to provide the directory to your static content.');
if (!contentTypeMatch.test) throw new Error('contentTypeMatch: must be a regular expression.');
dirPath = path.normalize(dirPath);
return function(req, res, next) {
var acceptEncoding = req.headers['accept-encoding'] || '',
url,
filename,
contentType,
charset,
method;
function pass(name) {
send(req, url.substring(prefix.length))
.maxage(clientMaxAge || 0)
.root(dirPath)
.pipe(res)
;
}
function setHeaders(stat, asset) {
res.setHeader('Content-Type', contentType);
res.setHeader('Content-Encoding', method);
res.setHeader('Vary', 'Accept-Encoding');
// if cache version is avalible then add this.
if (asset) {
// res.setHeader('Content-Length', asset.length);
res.setHeader('ETag', '"' + asset.length + '-' + Number(asset.mtime) + '"');
res.setHeader('Last-Modified', asset.mtime.toUTCString());
}
res.setHeader('Date', new Date().toUTCString());
res.setHeader('Expires', new Date(Date.now() + clientMaxAge).toUTCString());
res.setHeader('Cache-Control', 'public, max-age=' + (clientMaxAge / 1000));
}
// function gzipAndSend(filename, gzipName, mtime) {
// gzippo(filename, charset, function(gzippedData) {
// gzippoCache[gzipName] = {
// 'ctime': Date.now(),
// 'mtime': mtime,
// 'content': gzippedData
// };
// sendGzipped(gzippoCache[gzipName]);
// });
// }
function forbidden(res) {
var body = 'Forbidden';
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Length', body.length);
res.statusCode = 403;
res.end(body);
}
if (req.method !== 'GET' && req.method !== 'HEAD') {
return next();
}
url = decodeURI(parseUrl(req).pathname);
// Allow a url path prefix
if (url.substring(0, prefix.length) !== prefix) {
return next();
}
filename = path.normalize(path.join(dirPath, url.substring(prefix.length)));
// malicious path
if (0 != filename.indexOf(dirPath)){
return forbidden(res);
}
// directory index file support
if (filename.substr(-1) === '/') filename += 'index.html';
contentType = mime.lookup(filename);
charset = mime.charsets.lookup(contentType, 'UTF-8');
contentType = contentType + (charset ? '; charset=' + charset : '');
// default to gzip
if ('*' == acceptEncoding.trim()) method = 'gzip';
// compression method
if (!method) {
for (var i = 0, len = names.length; i < len; ++i) {
if (~acceptEncoding.indexOf(names[i])) {
method = names[i];
break;
}
}
}
if (!method) return pass(filename);
fs.stat(filename, function(err, stat) {
if (err) {
return next();
}
if (stat.isDirectory()) {
return next();
}
if (!contentTypeMatch.test(contentType)) {
return pass(filename);
}
// superceeded by if (!method) return;
// if (!~acceptEncoding.indexOf('gzip')) {
// return pass(filename);
// }
var base = path.basename(filename),
dir = path.dirname(filename),
gzipName = path.join(dir, base + '.gz');
var sendGzipped = function(filename) {
var stream = fs.createReadStream(filename);
req.on('close', stream.destroy.bind(stream));
var storeStream = new StoreStream(store, filename, {
mtime: stat.mtime,
maxAge: options.maxAge
});
var compressionStream = methods[method](options.compression);
stream.pipe(compressionStream).pipe(storeStream).pipe(res);
stream.on('error', function(err){
if (res.headerSent) {
console.error(err.stack);
req.destroy();
} else {
next(err);
}
});
};
store.get(decodeURI(filename), function(err, asset) {
setHeaders(stat, asset);
if (err) {
// handle error
} else if (!asset) {
sendGzipped(decodeURI(filename));
} else if ((asset.mtime < stat.mtime) || asset.isExpired) {
sendGzipped(decodeURI(filename));
}
else if (req.headers['if-modified-since'] && asset &&
// Optimisation: new Date().getTime is 90% faster that Date.parse()
+stat.mtime <= new Date(req.headers['if-modified-since']).getTime()) {
removeContentHeaders(res);
res.statusCode = 304;
return res.end();
}
else {
// StoreReadStream to pipe to res.
// console.log("hit: " + filename + " length: " + asset.length);
for (var i = 0; i < asset.content.length; i++) {
res.write(asset.content[i], 'binary');
}
res.end();
}
});
});
};
};

11
node_modules/gzippo/lib/store.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
var util = require('util');
/*
* gzippo - store
* Copyright(c) 2012 Tom Gallacher
* MIT Licensed
*/
var Store = module.exports = function Store(options) {
if (!(this instanceof Store)) return new Store(options);
};

119
node_modules/gzippo/lib/storeStream.js generated vendored Normal file
View File

@@ -0,0 +1,119 @@
var util = require('util'),
stream = require('stream'),
FileAsset = require('./fileAsset');
/*
* gzippo - StoreStream
* Copyright(c) 2012 Tom Gallacher
* MIT Licensed
*/
var StoreStream = module.exports = function StoreStream(store, fileName, options) {
if (!(this instanceof StoreStream)) return new StoreStream(store, options);
options = options || {};
this._queue = [];
this._processing = false;
this._ended = false;
this.readable = true;
this.writable = true;
this._asset = new FileAsset(fileName, options);
this._store = store;
};
util.inherits(StoreStream, stream.Stream);
StoreStream.prototype.write = function write(chunk, cb) {
if (this._ended) {
return this.emit('error', new Error('Cannot write after end'));
}
if (arguments.length === 1 && typeof chunk === 'function') {
cb = chunk;
chunk = null;
}
if (!chunk) {
chunk = null;
} else if (typeof chunk === 'string') {
chunk = new Buffer(chunk);
} else if (!Buffer.isBuffer(chunk)) {
return this.emit('error', new Error('Invalid argument'));
}
var empty = this._queue.length === 0;
this._queue.push([chunk, cb]);
this._process();
if (!empty) {
this._needDrain = true;
}
return empty;
};
StoreStream.prototype.flush = function flush(cb) {
return this.write(cb);
};
StoreStream.prototype.end = function end(chunk, cb) {
var self = this;
this._ending = true;
var ret = this.write(chunk, function() {
self.emit('end');
process.nextTick(function() {
self._store.set(self._asset);
});
if (cb) cb();
});
this._ended = true;
return ret;
};
StoreStream.prototype._process = function() {
var self = this;
if (this._processing || this._paused) return;
if (this._queue.length === 0) {
if (this._needDrain) {
this._needDrain = false;
this.emit('drain');
}
// nothing to do, waiting for more data at this point.
return;
}
var req = this._queue.shift();
var cb = req.pop();
var chunk = req.pop();
if (this._ending && this._queue.length === 0) {
this._flush = true;
}
if (chunk !== null) {
self.emit('data', chunk);
this._asset.fileContents.push(chunk);
}
// finished with the chunk.
self._processing = false;
if (cb) cb();
self._process();
};
StoreStream.prototype.destory = function() {
this._paused = true;
StoreStream.prototype.end.call(this);
};
StoreStream.prototype.pause = function() {
this._paused = true;
this.emit('pause');
};
StoreStream.prototype.resume = function() {
this._paused = false;
this._process();
};

4
node_modules/gzippo/node_modules/send/.npmignore generated vendored Normal file
View File

@@ -0,0 +1,4 @@
support
test
examples
*.sock

25
node_modules/gzippo/node_modules/send/History.md generated vendored Normal file
View File

@@ -0,0 +1,25 @@
0.1.0 / 2012-08-25
==================
* add options parameter to send() that is passed to fs.createReadStream() [kanongil]
0.0.4 / 2012-08-16
==================
* allow custom "Accept-Ranges" definition
0.0.3 / 2012-07-16
==================
* fix normalization of the root directory. Closes #3
0.0.2 / 2012-07-09
==================
* add passing of req explicitly for now (YUCK)
0.0.1 / 2010-01-03
==================
* Initial release

8
node_modules/gzippo/node_modules/send/Makefile generated vendored Normal file
View File

@@ -0,0 +1,8 @@
test:
@./node_modules/.bin/mocha \
--require should \
--reporter spec \
--bail
.PHONY: test

123
node_modules/gzippo/node_modules/send/Readme.md generated vendored Normal file
View File

@@ -0,0 +1,123 @@
# send
Send is Connect's `static()` extracted for generalized use, a streaming static file
server supporting partial responses (Ranges), conditional-GET negotiation, high test coverage, and granular events which may be leveraged to take appropriate actions in your application or framework.
## Installation
$ npm install send
## Examples
Small:
```js
var http = require('http');
var send = require('send');
var app = http.createServer(function(req, res){
send(req, req.url).pipe(res);
});
```
Serving from a root directory with custom error-handling:
```js
var http = require('http');
var send = require('send');
var app = http.createServer(function(req, res){
// your custom error-handling logic:
function error(err) {
res.statusCode = err.status || 500;
res.end(err.message);
}
// your custom directory handling logic:
function redirect() {
res.statusCode = 301;
res.setHeader('Location', req.url + '/');
res.end('Redirecting to ' + req.url + '/');
}
// transfer arbitrary files from within
// /www/example.com/public/*
send(req, url.parse(req.url).pathname)
.root('/www/example.com/public')
.on('error', error)
.on('directory', redirect)
.pipe(res);
});
```
## API
### Events
- `error` an error occurred `(err)`
- `directory` a directory was requested
- `stream` file streaming has started `(stream)`
- `end` streaming has completed
### .root(dir)
Serve files relative to `path`. Aliased as `.from(dir)`.
### .index(path)
By default send supports "index.html" files, to disable this
invoke `.index(false)` or to supply a new index pass a string.
### .maxage(ms)
Provide a max-age in milliseconds for http caching, defaults to 0.
## Error-handling
By default when no `error` listeners are present an automatic response will be made, otherwise you have full control over the response, aka you may show a 5xx page etc.
## Caching
It does _not_ perform internal caching, you should use a reverse proxy cache such
as Varnish for this, or those fancy things called CDNs. If your application is small enough that it would benefit from single-node memory caching, it's small enough that it does not need caching at all ;).
## Debugging
To enable `debug()` instrumentation output export __DEBUG__:
```
$ DEBUG=send node app
```
## Running tests
```
$ npm install
$ make test
```
## License
(The MIT License)
Copyright (c) 2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
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
node_modules/gzippo/node_modules/send/index.js generated vendored Normal file
View File

@@ -0,0 +1,2 @@
module.exports = require('./lib/send');

473
node_modules/gzippo/node_modules/send/lib/send.js generated vendored Normal file
View File

@@ -0,0 +1,473 @@
/**
* Module dependencies.
*/
var debug = require('debug')('send')
, parseRange = require('range-parser')
, Stream = require('stream')
, mime = require('mime')
, fresh = require('fresh')
, path = require('path')
, http = require('http')
, fs = require('fs')
, basename = path.basename
, normalize = path.normalize
, join = path.join
, utils = require('./utils');
/**
* Expose `send`.
*/
exports = module.exports = send;
/**
* Expose mime module.
*/
exports.mime = mime;
/**
* Return a `SendStream` for `req` and `path`.
*
* @param {Request} req
* @param {String} path
* @param {Object} options
* @return {SendStream}
* @api public
*/
function send(req, path, options) {
return new SendStream(req, path, options);
}
/**
* Initialize a `SendStream` with the given `path`.
*
* Events:
*
* - `error` an error occurred
* - `stream` file streaming has started
* - `end` streaming has completed
* - `directory` a directory was requested
*
* @param {Request} req
* @param {String} path
* @param {Object} options
* @api private
*/
function SendStream(req, path, options) {
var self = this;
this.req = req;
this.path = path;
this.options = options || {};
this.maxage(0);
this.hidden(false);
this.index('index.html');
}
/**
* Inherits from `Stream.prototype`.
*/
SendStream.prototype.__proto__ = Stream.prototype;
/**
* Enable or disable "hidden" (dot) files.
*
* @param {Boolean} path
* @return {SendStream}
* @api public
*/
SendStream.prototype.hidden = function(val){
debug('hidden %s', val);
this._hidden = val;
return this;
};
/**
* Set index `path`, set to a falsy
* value to disable index support.
*
* @param {String|Boolean} path
* @return {SendStream}
* @api public
*/
SendStream.prototype.index = function(path){
debug('index %s', path);
this._index = path;
return this;
};
/**
* Set root `path`.
*
* @param {String} path
* @return {SendStream}
* @api public
*/
SendStream.prototype.root =
SendStream.prototype.from = function(path){
this._root = normalize(path);
return this;
};
/**
* Set max-age to `ms`.
*
* @param {Number} ms
* @return {SendStream}
* @api public
*/
SendStream.prototype.maxage = function(ms){
if (Infinity == ms) ms = 60 * 60 * 24 * 365 * 1000;
debug('max-age %d', ms);
this._maxage = ms;
return this;
};
/**
* Emit error with `status`.
*
* @param {Number} status
* @api private
*/
SendStream.prototype.error = function(status, err){
var res = this.res;
var msg = http.STATUS_CODES[status];
err = err || new Error(msg);
err.status = status;
if (this.listeners('error').length) return this.emit('error', err);
res.statusCode = err.status;
res.end(msg);
};
/**
* Check if the pathname is potentially malicious.
*
* @return {Boolean}
* @api private
*/
SendStream.prototype.isMalicious = function(){
return !this._root && ~this.path.indexOf('..');
};
/**
* Check if the pathname ends with "/".
*
* @return {Boolean}
* @api private
*/
SendStream.prototype.hasTrailingSlash = function(){
return '/' == this.path[this.path.length - 1];
};
/**
* Check if the basename leads with ".".
*
* @return {Boolean}
* @api private
*/
SendStream.prototype.hasLeadingDot = function(){
return '.' == basename(this.path)[0];
};
/**
* Check if this is a conditional GET request.
*
* @return {Boolean}
* @api private
*/
SendStream.prototype.isConditionalGET = function(){
return this.req.headers['if-none-match']
|| this.req.headers['if-modified-since'];
};
/**
* Strip content-* header fields.
*
* @api private
*/
SendStream.prototype.removeContentHeaderFields = function(){
var res = this.res;
Object.keys(res._headers).forEach(function(field){
if (0 == field.indexOf('content')) {
res.removeHeader(field);
}
});
};
/**
* Respond with 304 not modified.
*
* @api private
*/
SendStream.prototype.notModified = function(){
var res = this.res;
debug('not modified');
this.removeContentHeaderFields();
res.statusCode = 304;
res.end();
};
/**
* Check if the request is cacheable, aka
* responded with 2xx or 304 (see RFC 2616 section 14.2{5,6}).
*
* @return {Boolean}
* @api private
*/
SendStream.prototype.isCachable = function(){
var res = this.res;
return (res.statusCode >= 200 && res.statusCode < 300) || 304 == res.statusCode;
};
/**
* Handle stat() error.
*
* @param {Error} err
* @api private
*/
SendStream.prototype.onStatError = function(err){
var notfound = ['ENOENT', 'ENAMETOOLONG', 'ENOTDIR'];
if (~notfound.indexOf(err.code)) return this.error(404, err);
this.error(500, err);
};
/**
* Check if the cache is fresh.
*
* @return {Boolean}
* @api private
*/
SendStream.prototype.isFresh = function(){
return fresh(this.req.headers, this.res._headers);
};
/**
* Redirect to `path`.
*
* @param {String} path
* @api private
*/
SendStream.prototype.redirect = function(path){
if (this.listeners('directory').length) return this.emit('directory');
var res = this.res;
path += '/';
res.statusCode = 301;
res.setHeader('Location', path);
res.end('Redirecting to ' + utils.escape(path));
};
/**
* Pipe to `res.
*
* @param {Stream} res
* @return {Stream} res
* @api public
*/
SendStream.prototype.pipe = function(res){
var self = this
, args = arguments
, path = this.path
, root = this._root;
// references
this.res = res;
// invalid request uri
path = utils.decode(path);
if (-1 == path) return this.error(400);
// null byte(s)
if (~path.indexOf('\0')) return this.error(400);
// join / normalize from optional root dir
if (root) path = normalize(join(this._root, path));
// ".." is malicious without "root"
if (this.isMalicious()) return this.error(403);
// malicious path
if (root && 0 != path.indexOf(root)) return this.error(403);
// hidden file support
if (!this._hidden && this.hasLeadingDot()) return this.error(404);
// index file support
if (this._index && this.hasTrailingSlash()) path += this._index;
debug('stat "%s"', path);
fs.stat(path, function(err, stat){
if (err) return self.onStatError(err);
if (stat.isDirectory()) return self.redirect(self.path);
self.send(path, stat);
});
return res;
};
/**
* Transfer `path`.
*
* @param {String} path
* @api public
*/
SendStream.prototype.send = function(path, stat){
var options = this.options;
var len = stat.size;
var res = this.res;
var req = this.req;
var ranges = req.headers.range;
var offset = options.start || 0;
// set header fields
this.setHeader(stat);
// set content-type
this.type(path);
// conditional GET support
if (this.isConditionalGET()
&& this.isCachable()
&& this.isFresh()) {
return this.notModified();
}
// adjust len to start/end options
len = Math.max(0, len - offset);
if (options.end !== undefined) {
var bytes = options.end - offset + 1;
if (len > bytes) len = bytes;
}
// Range support
if (ranges) {
ranges = parseRange(len, ranges);
// unsatisfiable
if (-1 == ranges) {
res.setHeader('Content-Range', 'bytes */' + stat.size);
return this.error(416);
}
// valid (syntactically invalid ranges are treated as a regular response)
if (-2 != ranges) {
options.start = offset + ranges[0].start;
options.end = offset + ranges[0].end;
// Content-Range
res.statusCode = 206;
res.setHeader('Content-Range', 'bytes '
+ ranges[0].start
+ '-'
+ ranges[0].end
+ '/'
+ len);
len = options.end - options.start + 1;
}
}
// content-length
res.setHeader('Content-Length', len);
// HEAD support
if ('HEAD' == req.method) return res.end();
this.stream(path, options);
};
/**
* Stream `path` to the response.
*
* @param {String} path
* @param {Object} options
* @api private
*/
SendStream.prototype.stream = function(path, options){
// TODO: this is all lame, refactor meeee
var self = this;
var res = this.res;
var req = this.req;
// pipe
var stream = fs.createReadStream(path, options);
this.emit('stream', stream);
stream.pipe(res);
// socket closed, done with the fd
req.on('close', stream.destroy.bind(stream));
// error handling code-smell
stream.on('error', function(err){
// no hope in responding
if (res._header) {
console.error(err.stack);
req.destroy();
return;
}
// 500
err.status = 500;
self.emit('error', err);
});
// end
stream.on('end', function(){
self.emit('end');
});
};
/**
* Set content-type based on `path`
* if it hasn't been explicitly set.
*
* @param {String} path
* @api private
*/
SendStream.prototype.type = function(path){
var res = this.res;
if (res.getHeader('Content-Type')) return;
var type = mime.lookup(path);
var charset = mime.charsets.lookup(type);
debug('content-type %s', type);
res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''));
};
/**
* Set reaponse header fields, most
* fields may be pre-defined.
*
* @param {Object} stat
* @api private
*/
SendStream.prototype.setHeader = function(stat){
var res = this.res;
if (!res.getHeader('Accept-Ranges')) res.setHeader('Accept-Ranges', 'bytes');
if (!res.getHeader('ETag')) res.setHeader('ETag', utils.etag(stat));
if (!res.getHeader('Date')) res.setHeader('Date', new Date().toUTCString());
if (!res.getHeader('Cache-Control')) res.setHeader('Cache-Control', 'public, max-age=' + (this._maxage / 1000));
if (!res.getHeader('Last-Modified')) res.setHeader('Last-Modified', stat.mtime.toUTCString());
};

47
node_modules/gzippo/node_modules/send/lib/utils.js generated vendored Normal file
View File

@@ -0,0 +1,47 @@
/**
* Return an ETag in the form of `"<size>-<mtime>"`
* from the given `stat`.
*
* @param {Object} stat
* @return {String}
* @api private
*/
exports.etag = function(stat) {
return '"' + stat.size + '-' + Number(stat.mtime) + '"';
};
/**
* decodeURIComponent.
*
* Allows V8 to only deoptimize this fn instead of all
* of send().
*
* @param {String} path
* @api private
*/
exports.decode = function(path){
try {
return decodeURIComponent(path);
} catch (err) {
return -1;
}
};
/**
* Escape the given string of `html`.
*
* @param {String} html
* @return {String}
* @api private
*/
exports.escape = function(html){
return String(html)
.replace(/&(?!\w+;)/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};

View File

@@ -0,0 +1,4 @@
support
test
examples
*.sock

View File

@@ -0,0 +1,62 @@
0.7.2 / 2013-02-06
==================
* fix package.json
* fix: Mobile Safari (private mode) is broken with debug
* fix: Use unicode to send escape character to shell instead of octal to work with strict mode javascript
0.7.1 / 2013-02-05
==================
* add repository URL to package.json
* add DEBUG_COLORED to force colored output
* add browserify support
* fix component. Closes #24
0.7.0 / 2012-05-04
==================
* Added .component to package.json
* Added debug.component.js build
0.6.0 / 2012-03-16
==================
* Added support for "-" prefix in DEBUG [Vinay Pulim]
* Added `.enabled` flag to the node version [TooTallNate]
0.5.0 / 2012-02-02
==================
* Added: humanize diffs. Closes #8
* Added `debug.disable()` to the CS variant
* Removed padding. Closes #10
* Fixed: persist client-side variant again. Closes #9
0.4.0 / 2012-02-01
==================
* Added browser variant support for older browsers [TooTallNate]
* Added `debug.enable('project:*')` to browser variant [TooTallNate]
* Added padding to diff (moved it to the right)
0.3.0 / 2012-01-26
==================
* Added millisecond diff when isatty, otherwise UTC string
0.2.0 / 2012-01-22
==================
* Added wildcard support
0.1.0 / 2011-12-02
==================
* Added: remove colors unless stderr isatty [TooTallNate]
0.0.1 / 2010-01-03
==================
* Initial release

View File

@@ -0,0 +1,115 @@
# debug
tiny node.js debugging utility modelled after node core's debugging technique.
## Installation
```
$ npm install debug
```
## Usage
With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.
Example _app.js_:
```js
var debug = require('debug')('http')
, http = require('http')
, name = 'My App';
// fake app
debug('booting %s', name);
http.createServer(function(req, res){
debug(req.method + ' ' + req.url);
res.end('hello\n');
}).listen(3000, function(){
debug('listening');
});
// fake worker of some kind
require('./worker');
```
Example _worker.js_:
```js
var debug = require('debug')('worker');
setInterval(function(){
debug('doing some work');
}, 1000);
```
The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:
![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)
![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)
## Millisecond diff
When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)
When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:
![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)
## Conventions
If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".
## Wildcards
The "*" character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=* -connect:*` would include all debuggers except those starting with "connect:".
## Browser support
Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`.
```js
a = debug('worker:a');
b = debug('worker:b');
setInterval(function(){
a('doing some work');
}, 1000);
setInterval(function(){
a('doing some work');
}, 1200);
```
## License
(The MIT License)
Copyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
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.

View File

@@ -0,0 +1,9 @@
{
"name": "debug",
"repo": "visionmedia/debug",
"description": "small debugging utility",
"version": "0.7.2",
"keywords": ["debug", "log", "debugger"],
"scripts": ["index.js", "debug.js"],
"dependencies": {}
}

View File

@@ -0,0 +1,124 @@
/**
* Expose `debug()` as the module.
*/
module.exports = debug;
/**
* Create a debugger with the given `name`.
*
* @param {String} name
* @return {Type}
* @api public
*/
function debug(name) {
if (!debug.enabled(name)) return function(){};
return function(fmt){
var curr = new Date;
var ms = curr - (debug[name] || curr);
debug[name] = curr;
fmt = name
+ ' '
+ fmt
+ ' +' + debug.humanize(ms);
// This hackery is required for IE8
// where `console.log` doesn't have 'apply'
window.console
&& console.log
&& Function.prototype.apply.call(console.log, console, arguments);
}
}
/**
* The currently active debug mode names.
*/
debug.names = [];
debug.skips = [];
/**
* Enables a debug mode by name. This can include modes
* separated by a colon and wildcards.
*
* @param {String} name
* @api public
*/
debug.enable = function(name) {
try {
localStorage.debug = name;
} catch(e){}
var split = (name || '').split(/[\s,]+/)
, len = split.length;
for (var i = 0; i < len; i++) {
name = split[i].replace('*', '.*?');
if (name[0] === '-') {
debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
}
else {
debug.names.push(new RegExp('^' + name + '$'));
}
}
};
/**
* Disable debug output.
*
* @api public
*/
debug.disable = function(){
debug.enable('');
};
/**
* Humanize the given `ms`.
*
* @param {Number} m
* @return {String}
* @api private
*/
debug.humanize = function(ms) {
var sec = 1000
, min = 60 * 1000
, hour = 60 * min;
if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
if (ms >= min) return (ms / min).toFixed(1) + 'm';
if (ms >= sec) return (ms / sec | 0) + 's';
return ms + 'ms';
};
/**
* Returns true if the given mode name is enabled, false otherwise.
*
* @param {String} name
* @return {Boolean}
* @api public
*/
debug.enabled = function(name) {
for (var i = 0, len = debug.skips.length; i < len; i++) {
if (debug.skips[i].test(name)) {
return false;
}
}
for (var i = 0, len = debug.names.length; i < len; i++) {
if (debug.names[i].test(name)) {
return true;
}
}
return false;
};
// persist
if (window.localStorage) debug.enable(localStorage.debug);

View File

@@ -0,0 +1,19 @@
var debug = require('../')('http')
, http = require('http')
, name = 'My App';
// fake app
debug('booting %s', name);
http.createServer(function(req, res){
debug(req.method + ' ' + req.url);
res.end('hello\n');
}).listen(3000, function(){
debug('listening');
});
// fake worker of some kind
require('./worker');

View File

@@ -0,0 +1,24 @@
<html>
<head>
<title>debug()</title>
<script src="../debug.js"></script>
<script>
// type debug.enable('*') in
// the console and refresh :)
a = debug('worker:a');
b = debug('worker:b');
setInterval(function(){
a('doing some work');
}, 1000);
setInterval(function(){
a('doing some work');
}, 1200);
</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,10 @@
var debug = {
foo: require('../')('test:foo'),
bar: require('../')('test:bar'),
baz: require('../')('test:baz')
};
debug.foo('foo')
debug.bar('bar')
debug.baz('baz')

View File

@@ -0,0 +1,22 @@
// DEBUG=* node example/worker
// DEBUG=worker:* node example/worker
// DEBUG=worker:a node example/worker
// DEBUG=worker:b node example/worker
var a = require('../')('worker:a')
, b = require('../')('worker:b');
function work() {
a('doing lots of uninteresting work');
setTimeout(work, Math.random() * 1000);
}
work();
function workb() {
b('doing some work');
setTimeout(workb, Math.random() * 2000);
}
workb();

View File

@@ -0,0 +1,5 @@
if ('undefined' == typeof window) {
module.exports = require('./lib/debug');
} else {
module.exports = require('./debug');
}

View File

@@ -0,0 +1,134 @@
/**
* Module dependencies.
*/
var tty = require('tty');
/**
* Expose `debug()` as the module.
*/
module.exports = debug;
/**
* Enabled debuggers.
*/
var names = []
, skips = [];
(process.env.DEBUG || '')
.split(/[\s,]+/)
.forEach(function(name){
name = name.replace('*', '.*?');
if (name[0] === '-') {
skips.push(new RegExp('^' + name.substr(1) + '$'));
} else {
names.push(new RegExp('^' + name + '$'));
}
});
/**
* Colors.
*/
var colors = [6, 2, 3, 4, 5, 1];
/**
* Previous debug() call.
*/
var prev = {};
/**
* Previously assigned color.
*/
var prevColor = 0;
/**
* Is stdout a TTY? Colored output is disabled when `true`.
*/
var isatty = tty.isatty(2);
/**
* Select a color.
*
* @return {Number}
* @api private
*/
function color() {
return colors[prevColor++ % colors.length];
}
/**
* Humanize the given `ms`.
*
* @param {Number} m
* @return {String}
* @api private
*/
function humanize(ms) {
var sec = 1000
, min = 60 * 1000
, hour = 60 * min;
if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
if (ms >= min) return (ms / min).toFixed(1) + 'm';
if (ms >= sec) return (ms / sec | 0) + 's';
return ms + 'ms';
}
/**
* Create a debugger with the given `name`.
*
* @param {String} name
* @return {Type}
* @api public
*/
function debug(name) {
function disabled(){}
disabled.enabled = false;
var match = skips.some(function(re){
return re.test(name);
});
if (match) return disabled;
match = names.some(function(re){
return re.test(name);
});
if (!match) return disabled;
var c = color();
function colored(fmt) {
var curr = new Date;
var ms = curr - (prev[name] || curr);
prev[name] = curr;
fmt = ' \u001b[9' + c + 'm' + name + ' '
+ '\u001b[3' + c + 'm\u001b[90m'
+ fmt + '\u001b[3' + c + 'm'
+ ' +' + humanize(ms) + '\u001b[0m';
console.error.apply(this, arguments);
}
function plain(fmt) {
fmt = new Date().toUTCString()
+ ' ' + name + ' ' + fmt;
console.error.apply(this, arguments);
}
colored.enabled = plain.enabled = true;
return isatty || process.env.DEBUG_COLORS
? colored
: plain;
}

View File

@@ -0,0 +1,43 @@
{
"name": "debug",
"version": "0.7.2",
"repository": {
"type": "git",
"url": "git://github.com/visionmedia/debug.git"
},
"description": "small debugging utility",
"keywords": [
"debug",
"log",
"debugger"
],
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"dependencies": {},
"devDependencies": {
"mocha": "*"
},
"main": "lib/debug.js",
"browserify": "debug.js",
"engines": {
"node": "*"
},
"component": {
"scripts": {
"debug/index.js": "index.js",
"debug/debug.js": "debug.js"
}
},
"_id": "debug@0.7.2",
"optionalDependencies": {},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"dist": {
"shasum": "22ebd8ee1bf8378ea8da9c8b27d4e0de4bfc2845"
},
"_from": "debug@*"
}

View File

@@ -0,0 +1 @@
test

View File

@@ -0,0 +1,7 @@
test:
@./node_modules/.bin/mocha \
--reporter spec \
--require should
.PHONY: test

View File

@@ -0,0 +1,32 @@
# node-fresh
HTTP response freshness testing
## fresh(req, res)
Check freshness of `req` and `res` headers.
When the cache is "fresh" __true__ is returned,
otherwise __false__ is returned to indicate that
the cache is now stale.
## Example:
```js
var req = { 'if-none-match': 'tobi' };
var res = { 'etag': 'luna' };
fresh(req, res);
// => false
var req = { 'if-none-match': 'tobi' };
var res = { 'etag': 'tobi' };
fresh(req, res);
// => true
```
## Installation
```
$ npm install fresh
```

View File

@@ -0,0 +1,49 @@
/**
* Expose `fresh()`.
*/
module.exports = fresh;
/**
* Check freshness of `req` and `res` headers.
*
* When the cache is "fresh" __true__ is returned,
* otherwise __false__ is returned to indicate that
* the cache is now stale.
*
* @param {Object} req
* @param {Object} res
* @return {Boolean}
* @api public
*/
function fresh(req, res) {
// defaults
var etagMatches = true;
var notModified = true;
// fields
var modifiedSince = req['if-modified-since'];
var noneMatch = req['if-none-match'];
var lastModified = res['last-modified'];
var etag = res['etag'];
// unconditional request
if (!modifiedSince && !noneMatch) return false;
// parse if-none-match
if (noneMatch) noneMatch = noneMatch.split(/ *, */);
// if-none-match
if (noneMatch) etagMatches = ~noneMatch.indexOf(etag) || '*' == noneMatch[0];
// if-modified-since
if (modifiedSince) {
modifiedSince = new Date(modifiedSince);
lastModified = new Date(lastModified);
notModified = lastModified <= modifiedSince;
}
return !! (etagMatches && notModified);
}

View File

@@ -0,0 +1,29 @@
{
"name": "fresh",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca",
"url": "http://tjholowaychuk.com"
},
"description": "HTTP response freshness testing",
"version": "0.1.0",
"main": "index.js",
"dependencies": {},
"devDependencies": {
"mocha": "*",
"should": "*"
},
"_id": "fresh@0.1.0",
"optionalDependencies": {},
"engines": {
"node": "*"
},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"dist": {
"shasum": "7dbe9f8603e489758d42d5a694cae0602fba8ed4"
},
"_from": "fresh@0.1.0"
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2010 Benjamin Thomas, Robert Kieffer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,63 @@
# mime
Comprehensive MIME type mapping API. Includes all 600+ types and 800+ extensions defined by the Apache project, plus additional types submitted by the node.js community.
## Install
Install with [npm](http://github.com/isaacs/npm):
npm install mime
## API - Queries
### mime.lookup(path)
Get the mime type associated with a file. Performs a case-insensitive lookup using the extension in `path` (the substring after the last '/' or '.'). E.g.
var mime = require('mime');
mime.lookup('/path/to/file.txt'); // => 'text/plain'
mime.lookup('file.txt'); // => 'text/plain'
mime.lookup('.TXT'); // => 'text/plain'
mime.lookup('htm'); // => 'text/html'
### mime.extension(type)
Get the default extension for `type`
mime.extension('text/html'); // => 'html'
mime.extension('application/octet-stream'); // => 'bin'
### mime.charsets.lookup()
Map mime-type to charset
mime.charsets.lookup('text/plain'); // => 'UTF-8'
(The logic for charset lookups is pretty rudimentary. Feel free to suggest improvements.)
## API - Defining Custom Types
The following APIs allow you to add your own type mappings within your project. If you feel a type should be included as part of node-mime, see [requesting new types](https://github.com/bentomas/node-mime/wiki/Requesting-New-Types).
### mime.define()
Add custom mime/extension mappings
mime.define({
'text/x-some-format': ['x-sf', 'x-sft', 'x-sfml'],
'application/x-my-type': ['x-mt', 'x-mtt'],
// etc ...
});
mime.lookup('x-sft'); // => 'text/x-some-format'
The first entry in the extensions array is returned by `mime.extension()`. E.g.
mime.extension('text/x-some-format'); // => 'x-sf'
### mime.load(filepath)
Load mappings from an Apache ".types" format file
mime.load('./my_project.types');
The .types file format is simple - See the `types` dir for examples.

View File

@@ -0,0 +1,104 @@
var path = require('path');
var fs = require('fs');
function Mime() {
// Map of extension -> mime type
this.types = Object.create(null);
// Map of mime type -> extension
this.extensions = Object.create(null);
}
/**
* Define mimetype -> extension mappings. Each key is a mime-type that maps
* to an array of extensions associated with the type. The first extension is
* used as the default extension for the type.
*
* e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']});
*
* @param map (Object) type definitions
*/
Mime.prototype.define = function (map) {
for (var type in map) {
var exts = map[type];
for (var i = 0; i < exts.length; i++) {
this.types[exts[i]] = type;
}
// Default extension is the first one we encounter
if (!this.extensions[type]) {
this.extensions[type] = exts[0];
}
}
};
/**
* Load an Apache2-style ".types" file
*
* This may be called multiple times (it's expected). Where files declare
* overlapping types/extensions, the last file wins.
*
* @param file (String) path of file to load.
*/
Mime.prototype.load = function(file) {
// Read file and split into lines
var map = {},
content = fs.readFileSync(file, 'ascii'),
lines = content.split(/[\r\n]+/);
lines.forEach(function(line) {
// Clean up whitespace/comments, and split into fields
var fields = line.replace(/\s*#.*|^\s*|\s*$/g, '').split(/\s+/);
map[fields.shift()] = fields;
});
this.define(map);
};
/**
* Lookup a mime type based on extension
*/
Mime.prototype.lookup = function(path, fallback) {
var ext = path.replace(/.*[\.\/]/, '').toLowerCase();
return this.types[ext] || fallback || this.default_type;
};
/**
* Return file extension associated with a mime type
*/
Mime.prototype.extension = function(mimeType) {
return this.extensions[mimeType];
};
// Default instance
var mime = new Mime();
// Load local copy of
// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
mime.load(path.join(__dirname, 'types/mime.types'));
// Load additional types from node.js community
mime.load(path.join(__dirname, 'types/node.types'));
// Default type
mime.default_type = mime.lookup('bin');
//
// Additional API specific to the default instance
//
mime.Mime = Mime;
/**
* Lookup a charset based on mime type.
*/
mime.charsets = {
lookup: function(mimeType, fallback) {
// Assume text types are utf8
return (/^text\//).test(mimeType) ? 'UTF-8' : fallback;
}
}
module.exports = mime;

View File

@@ -0,0 +1,41 @@
{
"author": {
"name": "Robert Kieffer",
"email": "robert@broofa.com",
"url": "http://github.com/broofa"
},
"contributors": [
{
"name": "Benjamin Thomas",
"email": "benjamin@benjaminthomas.org",
"url": "http://github.com/bentomas"
}
],
"dependencies": {},
"description": "A comprehensive library for mime-type mapping",
"devDependencies": {},
"keywords": [
"util",
"mime"
],
"main": "mime.js",
"name": "mime",
"repository": {
"url": "git://github.com/broofa/node-mime.git",
"type": "git"
},
"version": "1.2.6",
"_id": "mime@1.2.6",
"optionalDependencies": {},
"engines": {
"node": "*"
},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"dist": {
"shasum": "e66b214a4c2f94dc15ce22f0bda388b216bf0370"
},
"_from": "mime@1.2.6"
}

View File

@@ -0,0 +1,55 @@
/**
* Usage: node test.js
*/
var mime = require('./mime');
var assert = require('assert');
function eq(a, b) {
console.log('Test: ' + a + ' === ' + b);
assert.strictEqual.apply(null, arguments);
}
console.log(Object.keys(mime.extensions).length + ' types');
console.log(Object.keys(mime.types).length + ' extensions\n');
//
// Test mime lookups
//
eq('text/plain', mime.lookup('text.txt'));
eq('text/plain', mime.lookup('.text.txt'));
eq('text/plain', mime.lookup('.txt'));
eq('text/plain', mime.lookup('txt'));
eq('application/octet-stream', mime.lookup('text.nope'));
eq('fallback', mime.lookup('text.fallback', 'fallback'));
eq('application/octet-stream', mime.lookup('constructor'));
eq('text/plain', mime.lookup('TEXT.TXT'));
eq('text/event-stream', mime.lookup('text/event-stream'));
eq('application/x-web-app-manifest+json', mime.lookup('text.webapp'));
//
// Test extensions
//
eq('txt', mime.extension(mime.types.text));
eq('html', mime.extension(mime.types.htm));
eq('bin', mime.extension('application/octet-stream'));
eq(undefined, mime.extension('constructor'));
//
// Test node types
//
eq('application/octet-stream', mime.lookup('file.buffer'));
eq('audio/mp4', mime.lookup('file.m4a'));
//
// Test charsets
//
eq('UTF-8', mime.charsets.lookup('text/plain'));
eq(undefined, mime.charsets.lookup(mime.types.js));
eq('fallback', mime.charsets.lookup('application/octet-stream', 'fallback'));
console.log('\nOK');

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
# What: Google Chrome Extension
# Why: To allow apps to (work) be served with the right content type header.
# http://codereview.chromium.org/2830017
# Added by: niftylettuce
application/x-chrome-extension crx
# What: OTF Message Silencer
# Why: To silence the "Resource interpreted as font but transferred with MIME
# type font/otf" message that occurs in Google Chrome
# Added by: niftylettuce
font/opentype otf
# What: HTC support
# Why: To properly render .htc files such as CSS3PIE
# Added by: niftylettuce
text/x-component htc
# What: HTML5 application cache manifest
# Why: De-facto standard. Required by Mozilla browser when serving HTML5 apps
# per https://developer.mozilla.org/en/offline_resources_in_firefox
# Added by: louisremi
text/cache-manifest appcache manifest
# What: node binary buffer format
# Why: semi-standard extension w/in the node community
# Added by: tootallnate
application/octet-stream buffer
# What: The "protected" MP-4 formats used by iTunes.
# Why: Required for streaming music to browsers (?)
# Added by: broofa
application/mp4 m4p
audio/mp4 m4a
# What: Music playlist format (http://en.wikipedia.org/wiki/M3U)
# Why: See https://github.com/bentomas/node-mime/pull/6
# Added by: mjrusso
application/x-mpegURL m3u8
# What: Video format, Part of RFC1890
# Why: See https://github.com/bentomas/node-mime/pull/6
# Added by: mjrusso
video/MP2T ts
# What: The FLAC lossless codec format
# Why: Streaming and serving FLAC audio
# Added by: jacobrask
audio/flac flac
# What: EventSource mime type
# Why: mime type of Server-Sent Events stream
# http://www.w3.org/TR/eventsource/#text-event-stream
# Added by: francois2metz
text/event-stream event-stream
# What: Mozilla App manifest mime type
# Why: https://developer.mozilla.org/en/Apps/Manifest#Serving_manifests
# Added by: ednapiranha
application/x-web-app-manifest+json webapp
# What: Matroska Mime Types
# Why: http://en.wikipedia.org/wiki/Matroska
# Added by: aduncan88
video/x-matroska mkv
audio/x-matroska mka

View File

@@ -0,0 +1 @@
test

View File

@@ -0,0 +1,15 @@
0.0.4 / 2012-06-17
==================
* changed: ret -1 for unsatisfiable and -2 when invalid
0.0.3 / 2012-06-17
==================
* fix last-byte-pos default to len - 1
0.0.2 / 2012-06-14
==================
* add `.type`

View File

@@ -0,0 +1,7 @@
test:
@./node_modules/.bin/mocha \
--reporter spec \
--require should
.PHONY: test

View File

@@ -0,0 +1,28 @@
# node-range-parser
Range header field parser.
## Example:
```js
assert(-1 == parse(200, 'bytes=500-20'));
assert(-2 == parse(200, 'bytes=malformed'));
parse(200, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 199 }]));
parse(1000, 'bytes=0-499').should.eql(arr('bytes', [{ start: 0, end: 499 }]));
parse(1000, 'bytes=40-80').should.eql(arr('bytes', [{ start: 40, end: 80 }]));
parse(1000, 'bytes=-500').should.eql(arr('bytes', [{ start: 500, end: 999 }]));
parse(1000, 'bytes=-400').should.eql(arr('bytes', [{ start: 600, end: 999 }]));
parse(1000, 'bytes=500-').should.eql(arr('bytes', [{ start: 500, end: 999 }]));
parse(1000, 'bytes=400-').should.eql(arr('bytes', [{ start: 400, end: 999 }]));
parse(1000, 'bytes=0-0').should.eql(arr('bytes', [{ start: 0, end: 0 }]));
parse(1000, 'bytes=-1').should.eql(arr('bytes', [{ start: 999, end: 999 }]));
parse(1000, 'items=0-5').should.eql(arr('items', [{ start: 0, end: 5 }]));
parse(1000, 'bytes=40-80,-1').should.eql(arr('bytes', [{ start: 40, end: 80 }, { start: 999, end: 999 }]));
```
## Installation
```
$ npm install range-parser
```

View File

@@ -0,0 +1,49 @@
/**
* Parse "Range" header `str` relative to the given file `size`.
*
* @param {Number} size
* @param {String} str
* @return {Array}
* @api public
*/
module.exports = function(size, str){
var valid = true;
var i = str.indexOf('=');
if (-1 == i) return -2;
var arr = str.slice(i + 1).split(',').map(function(range){
var range = range.split('-')
, start = parseInt(range[0], 10)
, end = parseInt(range[1], 10);
// -nnn
if (isNaN(start)) {
start = size - end;
end = size - 1;
// nnn-
} else if (isNaN(end)) {
end = size - 1;
}
// limit last-byte-pos to current length
if (end > size - 1) end = size - 1;
// invalid
if (isNaN(start)
|| isNaN(end)
|| start > end
|| start < 0) valid = false;
return {
start: start,
end: end
};
});
arr.type = str.slice(0, i);
return valid ? arr : -1;
};

View File

@@ -0,0 +1,29 @@
{
"name": "range-parser",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca",
"url": "http://tjholowaychuk.com"
},
"description": "Range header field string parser",
"version": "0.0.4",
"main": "index.js",
"dependencies": {},
"devDependencies": {
"mocha": "*",
"should": "*"
},
"_id": "range-parser@0.0.4",
"optionalDependencies": {},
"engines": {
"node": "*"
},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"dist": {
"shasum": "aefe40cc8e78149013af07fe2c75ddfcd0ef2a4b"
},
"_from": "range-parser@0.0.4"
}

40
node_modules/gzippo/node_modules/send/package.json generated vendored Normal file
View File

@@ -0,0 +1,40 @@
{
"name": "send",
"version": "0.1.0",
"description": "Better streaming static file server with Range and conditional-GET support",
"keywords": [
"static",
"file",
"server"
],
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"dependencies": {
"debug": "*",
"mime": "1.2.6",
"fresh": "0.1.0",
"range-parser": "0.0.4"
},
"devDependencies": {
"mocha": "*",
"should": "*",
"supertest": "0.0.1",
"connect": "2.x"
},
"scripts": {
"test": "make test"
},
"main": "index",
"_id": "send@0.1.0",
"optionalDependencies": {},
"engines": {
"node": "*"
},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"_from": "send@*"
}

44
node_modules/gzippo/package.json generated vendored Normal file
View File

@@ -0,0 +1,44 @@
{
"name": "gzippo",
"version": "0.2.0",
"author": {
"name": "Tom Gallacher"
},
"description": "Gzip middleware for Connect using the native zlib library in node >= 0.6",
"homepage": "http://www.tomg.co/gzippo",
"repository": {
"type": "git",
"url": "git://github.com/tomgco/gzippo.git"
},
"keywords": [
"compression",
"gzip",
"compress"
],
"engines": {
"node": ">= 0.5 < 0.9"
},
"scripts": {
"test": "mocha"
},
"main": "./index.js",
"dependencies": {
"send": "*"
},
"devDependencies": {
"should": "*",
"connect": "~2",
"express": "~3",
"mocha": "*"
},
"_id": "gzippo@0.2.0",
"optionalDependencies": {},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"dist": {
"shasum": "da568f98101358ca6c3a8297f79102a20c2a309e"
},
"_from": "gzippo"
}

View File

@@ -0,0 +1,14 @@
<!doctype html>
<html>
<head><title>Index Test</title></head>
<body>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</body>
</html>

0
node_modules/gzippo/test/fixtures/js/nestedTest.js generated vendored Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

1
node_modules/gzippo/test/fixtures/test.js generated vendored Normal file
View File

@@ -0,0 +1 @@
alert("hello");

BIN
node_modules/gzippo/test/fixtures/test.js.gzip generated vendored Normal file

Binary file not shown.

BIN
node_modules/gzippo/test/fixtures/tomg.co.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
node_modules/gzippo/test/fixtures/user.gzip generated vendored Normal file

Binary file not shown.

4
node_modules/gzippo/test/fixtures/user.json generated vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "tomgallacher",
"website": "www.tomgallacher.info"
}

0
node_modules/gzippo/test/fixtures/utf8.gz generated vendored Normal file
View File

32
node_modules/gzippo/test/fixtures/utf8.txt generated vendored Normal file
View File

@@ -0,0 +1,32 @@
English: The quick brown fox jumps over the lazy dog.
Jamaican: Chruu, a kwik di kwik brong fox a jomp huova di liezi daag de, yu no siit?
Irish: "An ḃfuil do ċroí ag bualaḋ ó ḟaitíos an ġrá a ṁeall lena ṗóg éada ó ṡlí do leasa ṫú?" "D'ḟuascail Íosa Úrṁac na hÓiġe Beannaiṫe pór Éava agus Áḋaiṁ."
Dutch: Pa's wijze lynx bezag vroom het fikse aquaduct.
German: Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. (1)
German: Im finſteren Jagdſchloß am offenen Felsquellwaſſer patzte der affig-flatterhafte kauzig-höfliche Bäcker über ſeinem verſifften kniffligen C-Xylophon. (2)
Norwegian: Blåbærsyltetøy ("blueberry jam", includes every extra letter used in Norwegian).
Swedish: Flygande bäckasiner söka strax hwila på mjuka tuvor.
Icelandic: Sævör grét áðan því úlpan var ónýt.
Finnish: (5) Törkylempijävongahdus (This is a perfect pangram, every letter appears only once. Translating it is an art on its own, but I'll say "rude lover's yelp". :-D)
Finnish: (5) Albert osti fagotin ja töräytti puhkuvan melodian. (Albert bought a bassoon and hooted an impressive melody.)
Finnish: (5) On sangen hauskaa, että polkupyörä on maanteiden jokapäiväinen ilmiö. (It's pleasantly amusing, that the bicycle is an everyday sight on the roads.)
Polish: Pchnąć w tę łódź jeża lub osiem skrzyń fig.
Czech: Příliš žluťoučký kůň úpěl ďábelské kódy.
Slovak: Starý kôň na hŕbe kníh žuje tíško povädnuté ruže, na stĺpe sa ďateľ učí kvákať novú ódu o živote.
Greek (monotonic): ξεσκεπάζω την ψυχοφθόρα βδελυγμία
Greek (polytonic): ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία
Russian: Съешь же ещё этих мягких французских булок да выпей чаю.
Russian: В чащах юга жил-был цитрус? Да, но фальшивый экземпляр! ёъ.
Bulgarian: Жълтата дюля беше щастлива, че пухът, който цъфна, замръзна като гьон.
Sami (Northern): Vuol Ruoŧa geđggiid leat máŋga luosa ja čuovžža.
Hungarian: Árvíztűrő tükörfúrógép.
Spanish: El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.
Portuguese: O próximo vôo à noite sobre o Atlântico, põe freqüentemente o único médico. (3)
French: Les naïfs ægithales hâtifs pondant à Noël où il gèle sont sûrs d'être déçus en voyant leurs drôles d'œufs abîmés.
Esperanto: Eĥoŝanĝo ĉiuĵaŭde.
Hebrew: זה כיף סתם לשמוע איך תנצח קרפד עץ טוב בגן.
Japanese (Hiragana):
いろはにほへど ちりぬるを
わがよたれぞ つねならむ
うゐのおくやま けふこえて
あさきゆめみじ ゑひもせず (4)

BIN
node_modules/gzippo/test/fixtures/utf8.txt.gz generated vendored Normal file

Binary file not shown.

88
node_modules/gzippo/test/prefexTest.js generated vendored Normal file
View File

@@ -0,0 +1,88 @@
/**
* Module dependencies.
*/
var staticProvider,
assert = require('assert'),
should = require('should'),
http = require('http'),
gzippo = require('../');
try {
staticProvider = require('connect');
} catch (e) {
staticProvider = require('express');
}
/**
* Path to ./test/fixtures/
*/
var fixturesPath = __dirname + '/fixtures';
module.exports = {
'requesting without a prefix succeeds': function() {
var app = staticProvider.createServer(
gzippo.staticGzip(fixturesPath)
);
assert.response(app,
{
url: '/user.json',
headers: {
'Accept-Encoding':"gzip"
}
},
function(res){
var gzippedData = res.body;
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/json; charset=UTF-8');
res.headers.should.have.property('content-length', '69');
res.headers.should.have.property('content-encoding', 'gzip');
}
);
},
'requesting with a prefix succeeds': function() {
var app = staticProvider.createServer(
gzippo.staticGzip(fixturesPath, { prefix: '/resource' })
);
assert.response(app,
{
url: '/resource/user.json',
headers: {
'Accept-Encoding':"gzip"
}
},
function(res){
var gzippedData = res.body;
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/json; charset=UTF-8');
res.headers.should.have.property('content-length', '69');
res.headers.should.have.property('content-encoding', 'gzip');
}
);
},
'requesting with a / prefix succeeds': function() {
var app = staticProvider.createServer(
gzippo.staticGzip(fixturesPath, { prefix: '/'})
);
assert.response(app,
{
url: '/user.json',
headers: {
'Accept-Encoding':"gzip"
}
},
function(res){
var gzippedData = res.body;
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/json; charset=UTF-8');
res.headers.should.have.property('content-length', '69');
res.headers.should.have.property('content-encoding', 'gzip');
}
);
}
};

67
node_modules/gzippo/test/prefix.test.js generated vendored Normal file
View File

@@ -0,0 +1,67 @@
var assert = require('assert')
, http = require('http')
, fs = require('fs')
, connect = require('connect')
, join = require('path').join
, gzippo = require('../')
;
var fixtures = join(__dirname, 'fixtures')
, port = 32124
, app
, request
;
// read a fixture file synchronously
function file(name) {
return fs.readFileSync(join(fixtures, name));
}
describe('gzippo.statisGzip (with prefix)', function() {
it('should successfully serve a .json file with a path prefix', function(done) {
var app = connect.createServer();
app.use(gzippo.staticGzip(fixtures, { prefix: '/foo' }));
request = require('./request')({ port: port + 5 });
app.listen(port + 5, function() {
request('/foo/user.json', { 'Accept-Encoding': 'gzip' },
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
assert.equal(res.headers['content-type'], 'application/json; charset=UTF-8');
assert.equal(data.length, '69');
assert.equal(res.headers['content-encoding'], 'gzip');
assert.deepEqual(data, file('user.gzip'));
done();
}
);
});
});
it('should serve files as expected with a / prefix', function(done) {
var app = connect.createServer();
app.use(gzippo.staticGzip(fixtures, { prefix: '/' }));
request = require('./request')({ port: port + 6});
app.listen(port + 6, function() {
request('/user.json', { 'Accept-Encoding': 'gzip' },
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
assert.equal(res.headers['content-type'], 'application/json; charset=UTF-8');
assert.equal(data.length, '69');
assert.equal(res.headers['content-encoding'], 'gzip');
assert.deepEqual(data, file('user.gzip'));
done();
}
);
});
});
});

51
node_modules/gzippo/test/request.js generated vendored Normal file
View File

@@ -0,0 +1,51 @@
var http = require('http')
;
var port;
// basic request mocking function
module.exports = function (options) {
port = options.port || 32123;
return request;
};
var request = function(path, headers, callback) {
var options = {
host: '127.0.0.1',
port: port,
path: path,
headers: headers || {},
method: 'GET'
};
var req = http.request(options, function(res) {
var buffers = []
, total = 0;
res.on('data', function(buf) {
buffers.push(buf);
total += buf.length;
});
res.on('end', function() {
var data = new Buffer(total)
, offset = 0;
for (var i = 0; i < buffers.length; i++) {
buffers[i].copy(data, offset);
offset += buffers[i].length;
}
callback(null, res, data);
});
res.on('error', function(err) {
callback(err);
});
});
req.on('error', function(err) {
callback(err);
});
req.end();
};

180
node_modules/gzippo/test/staticGzipTest.js generated vendored Normal file
View File

@@ -0,0 +1,180 @@
/**
* Module dependencies.
*/
var staticProvider,
assert = require('assert'),
should = require('should'),
http = require('http'),
gzippo = require('../'),
crypto = require('crypto'),
fs = require('fs'),
shasum = crypto.createHash('sha1');
try {
staticProvider = require('connect');
} catch (e) {
staticProvider = require('express');
}
/**
* Path to ./test/fixtures/
*/
var fixturesPath = __dirname + '/fixtures';
function getApp() {
return staticProvider.createServer(gzippo.staticGzip(fixturesPath, {clientMaxAge: 604800000}));
}
module.exports = {
'requesting gzipped json file succeeds': function() {
assert.response(getApp(),
{
url: '/user.json',
headers: {
'Accept-Encoding':"gzip"
}
},
function(res){
var gzippedData = res.body;
assert.response(getApp(), { url: '/user.gzip' }, function(res) {
assert.equal(gzippedData, res.body, "Data is not gzipped");
});
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/json; charset=UTF-8');
// res.headers.should.have.property('content-length', '69');
res.headers.should.have.property('content-encoding', 'gzip');
}
);
},
'requesting gzipped js file succeeds': function() {
assert.response(getApp(),
{
url: '/test.js',
headers: {
'Accept-Encoding':"gzip"
}
},
function(res){
var gzippedData = res.body;
assert.response(getApp(), { url: '/test.js.gzip' }, function(res) {
assert.equal(gzippedData, res.body, "Data is not gzipped");
});
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/javascript; charset=UTF-8');
res.headers.should.have.property('content-length', '35');
res.headers.should.have.property('content-encoding', 'gzip');
}
);
},
'requesting js file without gzip succeeds': function() {
assert.response(getApp(),
{
url: '/test.js'
},
function(res){
var gzippedData = res.body;
fs.readFile(fixturesPath + '/test.js', function (err, data) {
if (err) throw err;
assert.equal(gzippedData, data, "Data returned does not match file data on filesystem");
});
res.statusCode.should.equal(200);
res.headers.should.have.property('content-length', '15');
}
);
},
'requesting gzipped utf-8 file succeeds': function() {
assert.response(getApp(),
{
url: '/utf8.txt',
headers: {
'Accept-Encoding':"gzip"
}
},
function(res){
var gzippedData = res.body;
assert.response(getApp(), { url: '/utf8.txt.gz' }, function(res) {
assert.equal(gzippedData, res.body, "Data is not gzipped");
});
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'text/plain; charset=UTF-8');
res.headers.should.have.property('content-length', '2031');
res.headers.should.have.property('content-encoding', 'gzip');
}
);
},
'requesting gzipped utf-8 file returns 304': function() {
assert.response(getApp(),
{
url: '/utf8.txt',
headers: {
'Accept-Encoding': "gzip"
}
},
function(res) {
res.statusCode.should.equal(200);
assert.response(getApp(),
{
url: '/utf8.txt',
headers: {
'Accept-Encoding': "gzip",
'If-Modified-Since': res.headers['last-modified']
}
},
function(res2) {
res2.statusCode.should.equal(304);
}
);
}
);
},
'requesting gzipped utf-8 file returns 200': function() {
assert.response(getApp(),
{
url: '/utf8.txt',
headers: {
'Accept-Encoding': "gzip"
}
},
function(res) {
res.statusCode.should.equal(200);
}
);
},
'ensuring max age is set on resources which are passed to the default static content provider': function() {
assert.response(getApp(),
{
url: '/tomg.co.png'
},
function(res) {
res.headers.should.have.property('cache-control', 'public, max-age=604800');
}
);
},
'Ensuring that when viewing a directory a redirect works correctly': function() {
assert.response(getApp(),
{
url: '/js'
},
function(res) {
res.statusCode.should.not.equal(301);
}
);
},
'ensuring that gzippo works with a space in a static content path': function() {
assert.response(getApp(),
{
url: '/space%20the%20final%20frontier/tomg.co.png'
},
function(res) {
res.statusCode.should.not.equal(404);
}
);
}
};

203
node_modules/gzippo/test/test-static.js generated vendored Normal file
View File

@@ -0,0 +1,203 @@
var assert = require('assert')
, fs = require('fs')
, express = require('express')
, join = require('path').join
, gzippo = require('../')
;
var fixtures = join(__dirname, 'fixtures')
, port = 32123
, app
, request = require('./request')({ port: port })
;
// builds a `request` callback which asserts that the response's statusCode is
// what we expect
function statusCode(expected, callback) {
return function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, expected);
callback();
};
}
// read a fixture file synchronously
function file(name) {
return fs.readFileSync(join(fixtures, name));
}
describe('gzippo.staticGzip', function() {
app = express();
app.use(gzippo.staticGzip(fixtures));
app.use(app.router);
app.listen(port);
// set up a new server for each test
// beforeEach(function(done) {
// });
// afterEach(function() {
// app.exit();
// });
it('should gzip static .json file', function(done) {
request('/user.json', { 'Accept-Encoding': 'gzip' },
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
assert.equal(res.headers['content-type'], 'application/json; charset=UTF-8');
assert.equal(data.length, '69');
assert.equal(res.headers['content-encoding'], 'gzip');
assert.deepEqual(data, file('user.gzip'));
done();
}
);
});
// it('should get a route', function(done) {
// request('/', { },
// function(err, res, data) {
// console.log(data.toString());
// if (err) throw err;
// assert.equal(res.statusCode, 200);
// assert.deepEqual(data, 'ok');
// done();
// }
// );
// });
it('should gzip static .js file', function(done) {
request('/test.js', { 'Accept-Encoding': 'gzip' },
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
assert.equal(res.headers['content-type'], 'application/javascript; charset=UTF-8');
assert.equal(data.length, '35');
assert.equal(res.headers['content-encoding'], 'gzip');
assert.deepEqual(data, file('test.js.gzip'));
done();
}
);
});
it('should serve a .js file uncompressed when the accept-encoding header has not been set', function(done) {
request('/test.js', {}, function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
assert.equal(data.length, '15');
assert.deepEqual(data, file('test.js'));
done();
});
});
it('should successfully gzip a utf-8 file', function(done) {
request('/utf8.txt', { 'Accept-Encoding': 'gzip' },
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
assert.equal(res.headers['content-type'], 'text/plain; charset=UTF-8');
assert.equal(data.length, '2031');
assert.equal(res.headers['content-encoding'], 'gzip');
assert.deepEqual(data, file('utf8.txt.gz'));
done();
}
);
});
it('should cache a previously gzipped utf-8 file (and respond with a 304 Not Modified)', function(done) {
request('/utf8.txt', { 'Accept-Encoding': 'gzip' },
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
var headers = {
'Accept-Encoding': 'gzip',
'If-Modified-Since': res.headers['last-modified']
};
request('/utf8.txt', headers, statusCode(304, done));
}
);
});
it('should set max age resources which are passed to the default static content provider', function(done) {
request('/tomg.co.png', {},
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
assert.notEqual(res.headers['cache-control'].indexOf('max-age=604800'), -1);
done();
}
);
});
it('should allow normal traversal', function(done) {
request('/nom/../tomg.co.png', {},
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
assert.deepEqual(data, file('tomg.co.png'));
done();
}
);
});
it('should redirect on directories', function(done) {
request('/js', {}, statusCode(301, done));
});
it('should work for paths containing URI-encoded spaces', function(done) {
request('/space%20the%20final%20frontier/tomg.co.png', { 'Accept-Encoding': 'gzip' }, statusCode(200, done));
});
it('should not let the user access files outside of the static directory (urlencoded)', function(done) {
request('/../test-static.js', { 'Accept-Encoding': 'gzip' }, statusCode(403, done));
});
it('should not let the user access files outside of the static directory', function(done) {
request('/%2e%2e/test-static.js', { 'Accept-Encoding': 'gzip' }, statusCode(403, done));
});
it('should not let the user access files from root of file system', function(done) {
request('/etc/password', { 'Accept-Encoding': 'gzip' }, statusCode(404, done));
});
it('should serve index.html for directories (if found)', function(done) {
request('/index_test/', { 'Accept-Encoding': 'gzip' },
function(err, res, data) {
if (err) throw err;
assert.equal(res.statusCode, 200);
// assert.equal(res.headers['content-length'], '616');
done();
}
);
});
});

1230
public/images/BlankBody.js Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

View File

@@ -40,12 +40,14 @@ $(document).ready(function() {
// settings: {width: '10cm', height: '5cm'}, // Additional settings for SVG element
// initPath: ''});
$('span.SVGBODY').empty().load("/images/BlankBody.svg", function(){
//$("button").button();
});
var colors = "0f0 0ff f60 f0f 00f f00".split(' '), i=0;
$(document).on('click', 'g',(function() {
$(document).on('click', '.SVGBODYFilter g',(function() {
console.log('click ' + this.id);
$(this).children('path').css("fill",'#'+colors[i++%colors.length] +'');
})
@@ -143,6 +145,9 @@ $(document).ready(function() {
var id = $(this).attr('value');
$('div#Rightpane').empty().load("/workouts/"+ id + "/recent/", function(){
$("button").button();
$('span.SVGBODY').empty().load("/images/BlankBody.svg", function(){
//$("button").button();
});
});
$('div#Leftpane').empty().load("/users/"+ id + "/sidebar", function(){
$("button").button();
@@ -154,6 +159,10 @@ $(document).ready(function() {
var id = $(this).attr('value');
$('div#Rightpane').empty().load(id);
$('div#Leftpane').empty().load("/workouts/filters", function(){
$('span.SVGBODYFilter').empty().load("/images/BlankBody.svg", function(){
//$("button").button();
});
PopulateExerciseList(originalExerciselist);
$("ul#exercises").sortable({
items: "> li",
@@ -170,7 +179,6 @@ $(document).ready(function() {
});
$("button").button();
$(document).on('click', 'path#F_x5F_Pectorals', function(){alert('hello2');});
});
$("#top").delegate("button.home-link", "click",function() {
@@ -180,6 +188,10 @@ $(document).ready(function() {
var id = $(this).attr('value');
$('div#Rightpane').empty().load("/workouts/"+ id + "/recent/", function(){
$("button").button();
console.log('here');
$('span.SVGBODY').empty().load("/images/BlankBody.svg", function(){
//$("button").button();
});
});
$('div#Leftpane').empty().load("/users/"+ id + "/sidebar", function(){
$("button").button();

View File

@@ -1,5 +1,5 @@
body {
padding: 50px;
xxpadding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
@@ -15,6 +15,11 @@ list-style-type: none;
list-style-type: none;
}
.labelli {
height : 30px;
}
.floatright {
float: right;
}
@@ -23,6 +28,12 @@ list-style-type: none;
clear: right;
}
li.floatleft {
display: block;
float: none;
overflow: hidden;
}
.floatleft {
display: block;
float: left;
@@ -32,12 +43,15 @@ list-style-type: none;
#Leftpane {
display: block;
float: left;
xxxwidth: 190px;
overflow: hidden;
}
#Rightpane {
display: block;
float: left;
overflow: hidden;
}
#userphoto {

View File

@@ -2,21 +2,30 @@ h1 New workout
div#filters
h3 Filters
label Search
input#searchbox (type="text", placeholder="Type here....")
label Free Weights
input.filter(type="checkbox", checked=true, value="Free Weights")
label Bodyweight
input.filter(type="checkbox", checked=true, value="Bodyweight")
label Exercise Machines
input.filter(type="checkbox", checked=true, value='Exercise Machine')
label Kettlebells
input.filter(type="checkbox", checked=true, value='Kettlebells')
label Cardio
input.filter(type="checkbox", checked=true, value='Cardio')
div
object(data='/images/BlankBody.svg', id='BlankBodyFilter', type='image/svg+xml')
div.floatleftx
label Search
input#searchbox (type="text", placeholder="Type here....")
span(class="SVGBODYFilter floatleft")
span.floatleft
ul
li.labelli
label Free Weights
input.filter(type="checkbox", checked=true, value="Free Weights")
li.labelli
label Bodyweight
input.filter(type="checkbox", checked=true, value="Bodyweight")
li.labelli
label Exercise Machines
input.filter(type="checkbox", checked=true, value='Exercise Machine')
li.labelli
label Kettlebells
input.filter(type="checkbox", checked=true, value='Kettlebells')
li.labelli
label Cardio
input.filter(type="checkbox", checked=true, value='Cardio')
h3 Exercises (dynamically loaded from database)
ul#exerciselist
li Unpopulated
div.floatleft
h3 Exercises (dynamically loaded from database)
ul#exerciselist
li Unpopulated

View File

@@ -9,6 +9,7 @@ h3 Recent workouts:
ol
each split in element.splits
li Reps: #{split.reps} Weight: #{split.weight}
span(class="floatleft")
include ../../public/images/BlankBody.svg
span(class="floatleft SVGBODY")
//include ../../public/images/BlankBody.svg
span(class="clearright")
- });