mirror of
https://github.com/atlanticbiomedical/biomedjs.git
synced 2025-07-02 00:47:26 -04:00
Latest Code
This commit is contained in:
@ -4,12 +4,18 @@ var mongoose = require('mongoose'),
|
|||||||
|
|
||||||
var md5 = require('MD5');
|
var md5 = require('MD5');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
var markdown = require('markdown').markdown;
|
||||||
var log = require('log4node');
|
var log = require('log4node');
|
||||||
|
|
||||||
exports.index = function(req, res) {
|
exports.index = function(req, res) {
|
||||||
|
var criteria = {};
|
||||||
|
var page = req.param('page');
|
||||||
|
if (page) {
|
||||||
|
criteria = { pages: page };
|
||||||
|
}
|
||||||
|
|
||||||
log.info('posts.index');
|
log.info('posts.index');
|
||||||
var query = Post.find()
|
var query = Post.find(criteria)
|
||||||
.populate('author', 'name')
|
.populate('author', 'name')
|
||||||
.sort('-createdOn')
|
.sort('-createdOn')
|
||||||
.exec(function(err, results) {
|
.exec(function(err, results) {
|
||||||
@ -32,19 +38,64 @@ exports.get = function(req, res, next) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function renderHtml(input) {
|
||||||
|
if (input) {
|
||||||
|
try {
|
||||||
|
return markdown.toHTML(input);
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Failed to render html', err);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanTags(tags) {
|
||||||
|
if (!tags) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(tags)) {
|
||||||
|
tags = [tags];
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < tags.length; i++) {
|
||||||
|
var tag = tags[i].toString()
|
||||||
|
.replace(/^#/, '')
|
||||||
|
.replace(/(\W|\d)/g, '$1 ')
|
||||||
|
.replace(/\b\w+/g, function(txt) {
|
||||||
|
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||||
|
})
|
||||||
|
.replace(/\s/g, '')
|
||||||
|
|
||||||
|
if (tag) {
|
||||||
|
results.push(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
exports.create = function(req, res, next) {
|
exports.create = function(req, res, next) {
|
||||||
log.info('posts.create %j', req.body);
|
log.info('posts.create %j', req.body);
|
||||||
|
|
||||||
var post = new Post({
|
var post = new Post({
|
||||||
title: req.body.title,
|
title: req.body.title,
|
||||||
preview: req.body.preview,
|
preview: req.body.preview,
|
||||||
|
previewHtml: renderHtml(req.body.preview),
|
||||||
details: req.body.details,
|
details: req.body.details,
|
||||||
|
detailsHtml: renderHtml(req.body.details),
|
||||||
image: req.body.image,
|
image: req.body.image,
|
||||||
gallery: req.body.gallery,
|
gallery: req.body.gallery,
|
||||||
status: req.body.status,
|
status: req.body.status,
|
||||||
createdOn: req.body.createdOn,
|
createdOn: req.body.createdOn,
|
||||||
postedOn: req.body.postedOn,
|
postedOn: req.body.postedOn,
|
||||||
author: req.user
|
author: req.user,
|
||||||
|
pages: req.body.pages,
|
||||||
|
tags: cleanTags(req.body.tags),
|
||||||
});
|
});
|
||||||
|
|
||||||
return post.save(function(err) {
|
return post.save(function(err) {
|
||||||
@ -60,13 +111,17 @@ exports.update = function(req, res, next) {
|
|||||||
console.log('updating post');
|
console.log('updating post');
|
||||||
|
|
||||||
return Post.findById(id, function(err, post) {
|
return Post.findById(id, function(err, post) {
|
||||||
post.title = req.body.title;
|
post.title = req.body.title;
|
||||||
post.preview = req.body.preview;
|
post.preview = req.body.preview;
|
||||||
post.details = req.body.details;
|
post.previewHtml = renderHtml(req.body.preview);
|
||||||
post.image = req.body.image;
|
post.details = req.body.details;
|
||||||
post.gallery = req.body.gallery;
|
post.detailsHtml = renderHtml(req.body.details);
|
||||||
post.status = req.body.status;
|
post.image = req.body.image;
|
||||||
post.postedOn = req.body.postedOn;
|
post.gallery = req.body.gallery;
|
||||||
|
post.status = req.body.status;
|
||||||
|
post.postedOn = req.body.postedOn;
|
||||||
|
post.pages = req.body.pages;
|
||||||
|
post.tags = cleanTags(req.body.tags);
|
||||||
|
|
||||||
return post.save(function(err) {
|
return post.save(function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -130,18 +130,47 @@ module.exports = function(config, calendar) {
|
|||||||
if (!notify)
|
if (!notify)
|
||||||
return callback(null);
|
return callback(null);
|
||||||
|
|
||||||
var to = generateToLine(techs).concat(req.body.emails);
|
var description = generateDescription(client, workorder, req.user, null, techs);
|
||||||
if (!to)
|
var techDescription = appendNotes(description, client);
|
||||||
return callback(null);
|
|
||||||
|
|
||||||
server.send({
|
var to = req.body.emails;
|
||||||
text: generateDescription(client, workorder, req.user, null, techs),
|
var techTo = generateToLine(techs);
|
||||||
from: config.email.user,
|
|
||||||
to: to,
|
var subject = 'Workorder created: ' + workorder.biomedId;
|
||||||
subject: 'Workorder created: ' + workorder.biomedId
|
|
||||||
}, function(err, message) {
|
console.log('-------------------------');
|
||||||
callback(err);
|
console.log(to);
|
||||||
});
|
|
||||||
|
async.waterfall([
|
||||||
|
function(cb) {
|
||||||
|
if (to && to.length > 0) {
|
||||||
|
var msg = {
|
||||||
|
text: description,
|
||||||
|
from: config.email.user,
|
||||||
|
to: to,
|
||||||
|
subject: subject
|
||||||
|
};
|
||||||
|
console.log(msg);
|
||||||
|
server.send(msg, function(err, message) { cb(err); });
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(cb) {
|
||||||
|
if (techTo) {
|
||||||
|
var msg = {
|
||||||
|
text: techDescription,
|
||||||
|
from: config.email.user,
|
||||||
|
to: techTo,
|
||||||
|
subject: subject
|
||||||
|
};
|
||||||
|
console.log(msg);
|
||||||
|
server.send(msg, function(err, message) { cb(err); });
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
},
|
},
|
||||||
function(callback) {
|
function(callback) {
|
||||||
workorder.save(function(err, result) { callback(err, result); });
|
workorder.save(function(err, result) { callback(err, result); });
|
||||||
@ -265,18 +294,45 @@ module.exports = function(config, calendar) {
|
|||||||
if (!notify)
|
if (!notify)
|
||||||
return callback(null);
|
return callback(null);
|
||||||
|
|
||||||
var to = generateToLine(techs);
|
|
||||||
if (!to)
|
var description = generateDescription(client, workorder, createdBy, modifiedBy, techs);
|
||||||
return callback(null);
|
var techDescription = appendNotes(description, client);
|
||||||
|
|
||||||
server.send({
|
var to = req.body.emails;
|
||||||
text: generateDescription(client, workorder, createdBy, modifiedBy, techs),
|
var techTo = generateToLine(techs);
|
||||||
from: config.email.user,
|
|
||||||
to: to,
|
var subject = 'Workorder updated: ' + workorder.biomedId;
|
||||||
subject: 'Workorder updated: ' + workorder.biomedId
|
|
||||||
}, function(err, message) {
|
async.waterfall([
|
||||||
callback(err);
|
function(cb) {
|
||||||
});
|
if (to && to.length > 0) {
|
||||||
|
var msg = {
|
||||||
|
text: description,
|
||||||
|
from: config.email.user,
|
||||||
|
to: to,
|
||||||
|
subject: subject
|
||||||
|
};
|
||||||
|
console.log(msg);
|
||||||
|
server.send(msg, function(err, message) { cb(err); });
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(cb) {
|
||||||
|
if (techTo) {
|
||||||
|
var msg = {
|
||||||
|
text: techDescription,
|
||||||
|
from: config.email.user,
|
||||||
|
to: techTo,
|
||||||
|
subject: subject
|
||||||
|
};
|
||||||
|
console.log(msg);
|
||||||
|
server.send(msg, function(err, message) { cb(err); });
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
},
|
},
|
||||||
function(callback) {
|
function(callback) {
|
||||||
workorder.save(function(err) {
|
workorder.save(function(err) {
|
||||||
@ -332,6 +388,26 @@ function generateLocation(client) {
|
|||||||
return sprintf("%(street1)s %(street2)s %(city)s, %(state)s. %(zip)s", data);
|
return sprintf("%(street1)s %(street2)s %(city)s, %(state)s. %(zip)s", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendNotes(message, client) {
|
||||||
|
var template =
|
||||||
|
"%(message)s\n" +
|
||||||
|
"Tech Notes:\n" +
|
||||||
|
" %(notes)s\n" +
|
||||||
|
"\n";
|
||||||
|
|
||||||
|
if (client.notes && client.notes['tech']) {
|
||||||
|
var resources = {
|
||||||
|
message: message || '',
|
||||||
|
notes: client.notes['tech'] || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
return sprintf(template, resources);
|
||||||
|
} else {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function generateDescription(client, workorder, createdBy, modifiedBy) {
|
function generateDescription(client, workorder, createdBy, modifiedBy) {
|
||||||
var template =
|
var template =
|
||||||
"Workorder ID:\n" +
|
"Workorder ID:\n" +
|
||||||
|
@ -5,13 +5,17 @@ var mongoose = require('mongoose'),
|
|||||||
var postSchema = new Schema({
|
var postSchema = new Schema({
|
||||||
title: { type: String },
|
title: { type: String },
|
||||||
preview: { type: String },
|
preview: { type: String },
|
||||||
|
previewHtml: { type: String },
|
||||||
details: { type: String },
|
details: { type: String },
|
||||||
|
detailsHtml: { type: String },
|
||||||
image: { type: String },
|
image: { type: String },
|
||||||
gallery: [{ type: String }],
|
gallery: [{ type: String }],
|
||||||
status: { type: String },
|
status: { type: String },
|
||||||
createdOn: { type: Date },
|
createdOn: { type: Date },
|
||||||
postedOn: { type: Date },
|
postedOn: { type: Date },
|
||||||
author: { type: ObjectId, ref: 'User' }
|
author: { type: ObjectId, ref: 'User' },
|
||||||
|
tags: [{ type: String }],
|
||||||
|
pages: [{ type: String }]
|
||||||
});
|
});
|
||||||
|
|
||||||
var Post = module.exports = mongoose.model('Post', postSchema);
|
var Post = module.exports = mongoose.model('Post', postSchema);
|
||||||
|
@ -63,6 +63,8 @@ html(lang="en", ng-app="biomed", ng-controller="biomed.PageCtrl")
|
|||||||
a(href='/admin')
|
a(href='/admin')
|
||||||
i.icon-wrench
|
i.icon-wrench
|
||||||
| Admin
|
| Admin
|
||||||
|
li.day-of-year
|
||||||
|
{{dayOfYear}}
|
||||||
.container-fluid
|
.container-fluid
|
||||||
ng-view
|
ng-view
|
||||||
!{js}
|
!{js}
|
||||||
|
@ -38,7 +38,7 @@ html(lang="en", ng-app="site", ng-controller="site.PageCtrl")
|
|||||||
.controls
|
.controls
|
||||||
.dropzone(dropzone='titleImageOptions')
|
.dropzone(dropzone='titleImageOptions')
|
||||||
|
|
||||||
.control-group
|
.control-group(ng-show='model.image')
|
||||||
label.control-label Gallery
|
label.control-label Gallery
|
||||||
.controls
|
.controls
|
||||||
.dropzone(dropzone='galleryImageOptions')
|
.dropzone(dropzone='galleryImageOptions')
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
var express = require('express');
|
var express = require('express');
|
||||||
|
var ClusterStore = require('strong-cluster-connect-store')(express.session);
|
||||||
|
|
||||||
module.exports = function(app, config, passport, piler) {
|
module.exports = function(app, config, passport, piler) {
|
||||||
app.set('showStackError', true);
|
app.set('showStackError', true);
|
||||||
@ -16,9 +17,7 @@ module.exports = function(app, config, passport, piler) {
|
|||||||
app.use(express.bodyParser());
|
app.use(express.bodyParser());
|
||||||
app.use(express.methodOverride());
|
app.use(express.methodOverride());
|
||||||
|
|
||||||
app.use(express.session({
|
app.use(express.session({ store: new ClusterStore(), secret: 'atlantic_biomed_server_secret' }));
|
||||||
secret: 'atlantic_biomed_server_secret'
|
|
||||||
}));
|
|
||||||
|
|
||||||
// use passport session
|
// use passport session
|
||||||
app.use(passport.initialize());
|
app.use(passport.initialize());
|
||||||
|
22
launcher.js
Normal file
22
launcher.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
var cluster = require('cluster');
|
||||||
|
|
||||||
|
require('strong-cluster-connect-store').setup();
|
||||||
|
|
||||||
|
cluster.setupMaster({
|
||||||
|
exec: 'server.js'
|
||||||
|
});
|
||||||
|
|
||||||
|
var cpus = 1;
|
||||||
|
for (var i = 0; i < cpus; i++) {
|
||||||
|
cluster.fork();
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster.on('online', function(worker) {
|
||||||
|
console.log('worker ' + worker.process.pid + ' started.');
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.on('exit', function(worker, code, signal) {
|
||||||
|
console.log('worker ' + worker.process.pid + ' died');
|
||||||
|
cluster.fork();
|
||||||
|
});
|
||||||
|
|
1
node_modules/.bin/md2html
generated
vendored
Symbolic link
1
node_modules/.bin/md2html
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../markdown/bin/md2html.js
|
2
node_modules/markdown/.npmignore
generated
vendored
Normal file
2
node_modules/markdown/.npmignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.seed.yml
|
||||||
|
test
|
7
node_modules/markdown/.travis.yml
generated
vendored
Normal file
7
node_modules/markdown/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.6"
|
||||||
|
- "0.8"
|
||||||
|
- "0.9"
|
||||||
|
- "0.10"
|
||||||
|
- "0.11"
|
35
node_modules/markdown/Changes.markdown
generated
vendored
Normal file
35
node_modules/markdown/Changes.markdown
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Changelog for markdown
|
||||||
|
|
||||||
|
## v0.5.0 - 2013-07-26
|
||||||
|
|
||||||
|
There might be other bug fixes then the ones listed - I've been a bit lax at
|
||||||
|
updating the changes file, sorry :(
|
||||||
|
|
||||||
|
- Fix 'undefined' appearing in output for some cases with blockquotes
|
||||||
|
- Fix (multiple) global variable leaks. Ooops
|
||||||
|
- Fix IE8 issues (#68, #74, #97)
|
||||||
|
- Fix IE8 issue (#86)
|
||||||
|
- Handle windows line endings (#58)
|
||||||
|
- Allow spaces in img/link paths (#48)
|
||||||
|
- Add explicit text of the license to the readme (#74)
|
||||||
|
- Style tweaks by Xhmikosr (#83, #81, #82)
|
||||||
|
- Build now tested by TravisCI thanks to sebs (#85)
|
||||||
|
- Fix 'cuddled' header parsing (#94)
|
||||||
|
- Fix images inside links mistakenly requiring a title attribute to parse
|
||||||
|
correctly (#71)
|
||||||
|
|
||||||
|
|
||||||
|
## v0.4.0 - 2012-06-09
|
||||||
|
|
||||||
|
- Fix for anchors enclosed by parenthesis (issue #46)
|
||||||
|
- `npm test` will now run the entire test suite cleanly. (switch tests over to
|
||||||
|
node-tap). (#21)
|
||||||
|
- Allow inline elements to appear inside link text (#27)
|
||||||
|
- Improve link parsing when link is inside parenthesis (#38)
|
||||||
|
- Actually render image references (#36)
|
||||||
|
- Improve link parsing when multiple on a line (#5)
|
||||||
|
- Make it work in IE7/8 (#37)
|
||||||
|
- Fix blockquote merging/implicit conversion between string/String (#44, #24)
|
||||||
|
- md2html can now process stdin (#43)
|
||||||
|
- Fix jslint warnings (#42)
|
||||||
|
- Fix to correctly render self-closing tags (#40, #35, #28)
|
185
node_modules/markdown/README.markdown
generated
vendored
Normal file
185
node_modules/markdown/README.markdown
generated
vendored
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
# markdown-js
|
||||||
|
|
||||||
|
Yet another markdown parser, this time for JavaScript. There's a few
|
||||||
|
options that precede this project but they all treat markdown to HTML
|
||||||
|
conversion as a single step process. You pass markdown in and get HTML
|
||||||
|
out, end of story. We had some pretty particular views on how the
|
||||||
|
process should actually look, which include:
|
||||||
|
|
||||||
|
* producing well-formed HTML. This means that `em` and `strong` nesting
|
||||||
|
is important, as is the ability to output as both HTML and XHTML
|
||||||
|
|
||||||
|
* having an intermediate representation to allow processing of parsed
|
||||||
|
data (we in fact have two, both [JsonML]: a markdown tree and an HTML tree)
|
||||||
|
|
||||||
|
* being easily extensible to add new dialects without having to
|
||||||
|
rewrite the entire parsing mechanics
|
||||||
|
|
||||||
|
* having a good test suite. The only test suites we could find tested
|
||||||
|
massive blocks of input, and passing depended on outputting the HTML
|
||||||
|
with exactly the same whitespace as the original implementation
|
||||||
|
|
||||||
|
[JsonML]: http://jsonml.org/ "JSON Markup Language"
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Just the `markdown` library:
|
||||||
|
|
||||||
|
npm install markdown
|
||||||
|
|
||||||
|
Optionally, install `md2html` into your path
|
||||||
|
|
||||||
|
npm install -g markdown
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Node
|
||||||
|
|
||||||
|
The simple way to use it with node is:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var markdown = require( "markdown" ).markdown;
|
||||||
|
console.log( markdown.toHTML( "Hello *World*!" ) );
|
||||||
|
```
|
||||||
|
|
||||||
|
### Browser
|
||||||
|
|
||||||
|
It also works in a browser; here is a complete example:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<textarea id="text-input" oninput="this.editor.update()"
|
||||||
|
rows="6" cols="60">Type **Markdown** here.</textarea>
|
||||||
|
<div id="preview"> </div>
|
||||||
|
<script src="lib/markdown.js"></script>
|
||||||
|
<script>
|
||||||
|
function Editor(input, preview) {
|
||||||
|
this.update = function () {
|
||||||
|
preview.innerHTML = markdown.toHTML(input.value);
|
||||||
|
};
|
||||||
|
input.editor = this;
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
var $ = function (id) { return document.getElementById(id); };
|
||||||
|
new Editor($("text-input"), $("preview"));
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command line
|
||||||
|
|
||||||
|
Assuming you've installed the `md2html` script (see Installation,
|
||||||
|
above), you can convert markdown to html:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# read from a file
|
||||||
|
md2html /path/to/doc.md > /path/to/doc.html
|
||||||
|
|
||||||
|
# or from stdin
|
||||||
|
echo 'Hello *World*!' | md2html
|
||||||
|
```
|
||||||
|
|
||||||
|
### More options
|
||||||
|
|
||||||
|
If you want more control check out the documentation in
|
||||||
|
[lib/markdown.js] which details all the methods and parameters
|
||||||
|
available (including examples!). One day we'll get the docs generated
|
||||||
|
and hosted somewhere for nicer browsing.
|
||||||
|
|
||||||
|
[lib/markdown.js]: http://github.com/evilstreak/markdown-js/blob/master/lib/markdown.js
|
||||||
|
|
||||||
|
Meanwhile, here's an example of using the multi-step processing to
|
||||||
|
make wiki-style linking work by filling in missing link references:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var md = require( "markdown" ).markdown,
|
||||||
|
text = "[Markdown] is a simple text-based [markup language]\n" +
|
||||||
|
"created by [John Gruber]\n\n" +
|
||||||
|
"[John Gruber]: http://daringfireball.net";
|
||||||
|
|
||||||
|
// parse the markdown into a tree and grab the link references
|
||||||
|
var tree = md.parse( text ),
|
||||||
|
refs = tree[ 1 ].references;
|
||||||
|
|
||||||
|
// iterate through the tree finding link references
|
||||||
|
( function find_link_refs( jsonml ) {
|
||||||
|
if ( jsonml[ 0 ] === "link_ref" ) {
|
||||||
|
var ref = jsonml[ 1 ].ref;
|
||||||
|
|
||||||
|
// if there's no reference, define a wiki link
|
||||||
|
if ( !refs[ ref ] ) {
|
||||||
|
refs[ ref ] = {
|
||||||
|
href: "http://en.wikipedia.org/wiki/" + ref.replace(/\s+/, "_" )
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( Array.isArray( jsonml[ 1 ] ) ) {
|
||||||
|
jsonml[ 1 ].forEach( find_link_refs );
|
||||||
|
}
|
||||||
|
else if ( Array.isArray( jsonml[ 2 ] ) ) {
|
||||||
|
jsonml[ 2 ].forEach( find_link_refs );
|
||||||
|
}
|
||||||
|
} )( tree );
|
||||||
|
|
||||||
|
// convert the tree into html
|
||||||
|
var html = md.renderJsonML( md.toHTMLTree( tree ) );
|
||||||
|
console.log( html );
|
||||||
|
```
|
||||||
|
|
||||||
|
## Intermediate Representation
|
||||||
|
|
||||||
|
Internally the process to convert a chunk of markdown into a chunk of
|
||||||
|
HTML has three steps:
|
||||||
|
|
||||||
|
1. Parse the markdown into a JsonML tree. Any references found in the
|
||||||
|
parsing are stored in the attribute hash of the root node under the
|
||||||
|
key `references`.
|
||||||
|
|
||||||
|
2. Convert the markdown tree into an HTML tree. Rename any nodes that
|
||||||
|
need it (`bulletlist` to `ul` for example) and lookup any references
|
||||||
|
used by links or images. Remove the references attribute once done.
|
||||||
|
|
||||||
|
3. Stringify the HTML tree being careful not to wreck whitespace where
|
||||||
|
whitespace is important (surrounding inline elements for example).
|
||||||
|
|
||||||
|
Each step of this process can be called individually if you need to do
|
||||||
|
some processing or modification of the data at an intermediate stage.
|
||||||
|
For example, you may want to grab a list of all URLs linked to in the
|
||||||
|
document before rendering it to HTML which you could do by recursing
|
||||||
|
through the HTML tree looking for `a` nodes.
|
||||||
|
|
||||||
|
## Running tests
|
||||||
|
|
||||||
|
To run the tests under node you will need tap installed (it's listed as a
|
||||||
|
`devDependencies` so `npm install` from the checkout should be enough), then do
|
||||||
|
|
||||||
|
$ npm test
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Do the usual github fork and pull request dance. Add yourself to the
|
||||||
|
contributors section of [package.json](/package.json) too if you want to.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Released under the MIT license.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
52
node_modules/markdown/bin/md2html.js
generated
vendored
Executable file
52
node_modules/markdown/bin/md2html.js
generated
vendored
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var fs = require("fs")
|
||||||
|
, markdown = require("markdown").markdown
|
||||||
|
, nopt = require("nopt")
|
||||||
|
, stream
|
||||||
|
, opts
|
||||||
|
, buffer = ""
|
||||||
|
;
|
||||||
|
|
||||||
|
opts = nopt(
|
||||||
|
{ "dialect": [ "Gruber", "Maruku"]
|
||||||
|
, "help": Boolean
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
var name = process.argv[1].split("/").pop()
|
||||||
|
console.warn( require("util").format(
|
||||||
|
"usage: %s [--dialect=DIALECT] FILE\n\nValid dialects are Gruber (the default) or Maruku",
|
||||||
|
name
|
||||||
|
) );
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var fullpath = opts.argv.remain[0];
|
||||||
|
|
||||||
|
if (fullpath && fullpath !== "-") {
|
||||||
|
stream = fs.createReadStream(fullpath);
|
||||||
|
} else {
|
||||||
|
stream = process.stdin;
|
||||||
|
}
|
||||||
|
stream.resume();
|
||||||
|
stream.setEncoding("utf8");
|
||||||
|
|
||||||
|
stream.on("error", function(error) {
|
||||||
|
console.error(error.toString());
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on("data", function(data) {
|
||||||
|
buffer += data;
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on("end", function() {
|
||||||
|
var html = markdown.toHTML(buffer, opts.dialect);
|
||||||
|
console.log(html);
|
||||||
|
});
|
||||||
|
|
||||||
|
}())
|
3
node_modules/markdown/lib/index.js
generated
vendored
Normal file
3
node_modules/markdown/lib/index.js
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// super simple module for the most common nodejs use case.
|
||||||
|
exports.markdown = require("./markdown");
|
||||||
|
exports.parse = exports.markdown.toHTML;
|
1725
node_modules/markdown/lib/markdown.js
generated
vendored
Normal file
1725
node_modules/markdown/lib/markdown.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
node_modules/markdown/markdown-js.sublime-project
generated
vendored
Normal file
10
node_modules/markdown/markdown-js.sublime-project
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"folders":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "/Users/ash/code/js/markdown-js",
|
||||||
|
"folder_exclude_patterns": ["node_modules"],
|
||||||
|
"file_exclude_patterns": ["*.sublime-*"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1993
node_modules/markdown/markdown-js.sublime-workspace
generated
vendored
Normal file
1993
node_modules/markdown/markdown-js.sublime-workspace
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/markdown/node_modules/.bin/nopt
generated
vendored
Symbolic link
1
node_modules/markdown/node_modules/.bin/nopt
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../nopt/bin/nopt.js
|
1
node_modules/markdown/node_modules/nopt/.npmignore
generated
vendored
Normal file
1
node_modules/markdown/node_modules/nopt/.npmignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
23
node_modules/markdown/node_modules/nopt/LICENSE
generated
vendored
Normal file
23
node_modules/markdown/node_modules/nopt/LICENSE
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
210
node_modules/markdown/node_modules/nopt/README.md
generated
vendored
Normal file
210
node_modules/markdown/node_modules/nopt/README.md
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
If you want to write an option parser, and have it be good, there are
|
||||||
|
two ways to do it. The Right Way, and the Wrong Way.
|
||||||
|
|
||||||
|
The Wrong Way is to sit down and write an option parser. We've all done
|
||||||
|
that.
|
||||||
|
|
||||||
|
The Right Way is to write some complex configurable program with so many
|
||||||
|
options that you go half-insane just trying to manage them all, and put
|
||||||
|
it off with duct-tape solutions until you see exactly to the core of the
|
||||||
|
problem, and finally snap and write an awesome option parser.
|
||||||
|
|
||||||
|
If you want to write an option parser, don't write an option parser.
|
||||||
|
Write a package manager, or a source control system, or a service
|
||||||
|
restarter, or an operating system. You probably won't end up with a
|
||||||
|
good one of those, but if you don't give up, and you are relentless and
|
||||||
|
diligent enough in your procrastination, you may just end up with a very
|
||||||
|
nice option parser.
|
||||||
|
|
||||||
|
## USAGE
|
||||||
|
|
||||||
|
// my-program.js
|
||||||
|
var nopt = require("nopt")
|
||||||
|
, Stream = require("stream").Stream
|
||||||
|
, path = require("path")
|
||||||
|
, knownOpts = { "foo" : [String, null]
|
||||||
|
, "bar" : [Stream, Number]
|
||||||
|
, "baz" : path
|
||||||
|
, "bloo" : [ "big", "medium", "small" ]
|
||||||
|
, "flag" : Boolean
|
||||||
|
, "pick" : Boolean
|
||||||
|
, "many" : [String, Array]
|
||||||
|
}
|
||||||
|
, shortHands = { "foofoo" : ["--foo", "Mr. Foo"]
|
||||||
|
, "b7" : ["--bar", "7"]
|
||||||
|
, "m" : ["--bloo", "medium"]
|
||||||
|
, "p" : ["--pick"]
|
||||||
|
, "f" : ["--flag"]
|
||||||
|
}
|
||||||
|
// everything is optional.
|
||||||
|
// knownOpts and shorthands default to {}
|
||||||
|
// arg list defaults to process.argv
|
||||||
|
// slice defaults to 2
|
||||||
|
, parsed = nopt(knownOpts, shortHands, process.argv, 2)
|
||||||
|
console.log(parsed)
|
||||||
|
|
||||||
|
This would give you support for any of the following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ node my-program.js --foo "blerp" --no-flag
|
||||||
|
{ "foo" : "blerp", "flag" : false }
|
||||||
|
|
||||||
|
$ node my-program.js ---bar 7 --foo "Mr. Hand" --flag
|
||||||
|
{ bar: 7, foo: "Mr. Hand", flag: true }
|
||||||
|
|
||||||
|
$ node my-program.js --foo "blerp" -f -----p
|
||||||
|
{ foo: "blerp", flag: true, pick: true }
|
||||||
|
|
||||||
|
$ node my-program.js -fp --foofoo
|
||||||
|
{ foo: "Mr. Foo", flag: true, pick: true }
|
||||||
|
|
||||||
|
$ node my-program.js --foofoo -- -fp # -- stops the flag parsing.
|
||||||
|
{ foo: "Mr. Foo", argv: { remain: ["-fp"] } }
|
||||||
|
|
||||||
|
$ node my-program.js --blatzk 1000 -fp # unknown opts are ok.
|
||||||
|
{ blatzk: 1000, flag: true, pick: true }
|
||||||
|
|
||||||
|
$ node my-program.js --blatzk true -fp # but they need a value
|
||||||
|
{ blatzk: true, flag: true, pick: true }
|
||||||
|
|
||||||
|
$ node my-program.js --no-blatzk -fp # unless they start with "no-"
|
||||||
|
{ blatzk: false, flag: true, pick: true }
|
||||||
|
|
||||||
|
$ node my-program.js --baz b/a/z # known paths are resolved.
|
||||||
|
{ baz: "/Users/isaacs/b/a/z" }
|
||||||
|
|
||||||
|
# if Array is one of the types, then it can take many
|
||||||
|
# values, and will always be an array. The other types provided
|
||||||
|
# specify what types are allowed in the list.
|
||||||
|
|
||||||
|
$ node my-program.js --many 1 --many null --many foo
|
||||||
|
{ many: ["1", "null", "foo"] }
|
||||||
|
|
||||||
|
$ node my-program.js --many foo
|
||||||
|
{ many: ["foo"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
Read the tests at the bottom of `lib/nopt.js` for more examples of
|
||||||
|
what this puppy can do.
|
||||||
|
|
||||||
|
## Types
|
||||||
|
|
||||||
|
The following types are supported, and defined on `nopt.typeDefs`
|
||||||
|
|
||||||
|
* String: A normal string. No parsing is done.
|
||||||
|
* path: A file system path. Gets resolved against cwd if not absolute.
|
||||||
|
* url: A url. If it doesn't parse, it isn't accepted.
|
||||||
|
* Number: Must be numeric.
|
||||||
|
* Date: Must parse as a date. If it does, and `Date` is one of the options,
|
||||||
|
then it will return a Date object, not a string.
|
||||||
|
* Boolean: Must be either `true` or `false`. If an option is a boolean,
|
||||||
|
then it does not need a value, and its presence will imply `true` as
|
||||||
|
the value. To negate boolean flags, do `--no-whatever` or `--whatever
|
||||||
|
false`
|
||||||
|
* NaN: Means that the option is strictly not allowed. Any value will
|
||||||
|
fail.
|
||||||
|
* Stream: An object matching the "Stream" class in node. Valuable
|
||||||
|
for use when validating programmatically. (npm uses this to let you
|
||||||
|
supply any WriteStream on the `outfd` and `logfd` config options.)
|
||||||
|
* Array: If `Array` is specified as one of the types, then the value
|
||||||
|
will be parsed as a list of options. This means that multiple values
|
||||||
|
can be specified, and that the value will always be an array.
|
||||||
|
|
||||||
|
If a type is an array of values not on this list, then those are
|
||||||
|
considered valid values. For instance, in the example above, the
|
||||||
|
`--bloo` option can only be one of `"big"`, `"medium"`, or `"small"`,
|
||||||
|
and any other value will be rejected.
|
||||||
|
|
||||||
|
When parsing unknown fields, `"true"`, `"false"`, and `"null"` will be
|
||||||
|
interpreted as their JavaScript equivalents, and numeric values will be
|
||||||
|
interpreted as a number.
|
||||||
|
|
||||||
|
You can also mix types and values, or multiple types, in a list. For
|
||||||
|
instance `{ blah: [Number, null] }` would allow a value to be set to
|
||||||
|
either a Number or null. When types are ordered, this implies a
|
||||||
|
preference, and the first type that can be used to properly interpret
|
||||||
|
the value will be used.
|
||||||
|
|
||||||
|
To define a new type, add it to `nopt.typeDefs`. Each item in that
|
||||||
|
hash is an object with a `type` member and a `validate` method. The
|
||||||
|
`type` member is an object that matches what goes in the type list. The
|
||||||
|
`validate` method is a function that gets called with `validate(data,
|
||||||
|
key, val)`. Validate methods should assign `data[key]` to the valid
|
||||||
|
value of `val` if it can be handled properly, or return boolean
|
||||||
|
`false` if it cannot.
|
||||||
|
|
||||||
|
You can also call `nopt.clean(data, types, typeDefs)` to clean up a
|
||||||
|
config object and remove its invalid properties.
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
By default, nopt outputs a warning to standard error when invalid
|
||||||
|
options are found. You can change this behavior by assigning a method
|
||||||
|
to `nopt.invalidHandler`. This method will be called with
|
||||||
|
the offending `nopt.invalidHandler(key, val, types)`.
|
||||||
|
|
||||||
|
If no `nopt.invalidHandler` is assigned, then it will console.error
|
||||||
|
its whining. If it is assigned to boolean `false` then the warning is
|
||||||
|
suppressed.
|
||||||
|
|
||||||
|
## Abbreviations
|
||||||
|
|
||||||
|
Yes, they are supported. If you define options like this:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{ "foolhardyelephants" : Boolean
|
||||||
|
, "pileofmonkeys" : Boolean }
|
||||||
|
```
|
||||||
|
|
||||||
|
Then this will work:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node program.js --foolhar --pil
|
||||||
|
node program.js --no-f --pileofmon
|
||||||
|
# etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Shorthands
|
||||||
|
|
||||||
|
Shorthands are a hash of shorter option names to a snippet of args that
|
||||||
|
they expand to.
|
||||||
|
|
||||||
|
If multiple one-character shorthands are all combined, and the
|
||||||
|
combination does not unambiguously match any other option or shorthand,
|
||||||
|
then they will be broken up into their constituent parts. For example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "s" : ["--loglevel", "silent"]
|
||||||
|
, "g" : "--global"
|
||||||
|
, "f" : "--force"
|
||||||
|
, "p" : "--parseable"
|
||||||
|
, "l" : "--long"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm ls -sgflp
|
||||||
|
# just like doing this:
|
||||||
|
npm ls --loglevel silent --global --force --long --parseable
|
||||||
|
```
|
||||||
|
|
||||||
|
## The Rest of the args
|
||||||
|
|
||||||
|
The config object returned by nopt is given a special member called
|
||||||
|
`argv`, which is an object with the following fields:
|
||||||
|
|
||||||
|
* `remain`: The remaining args after all the parsing has occurred.
|
||||||
|
* `original`: The args as they originally appeared.
|
||||||
|
* `cooked`: The args after flags and shorthands are expanded.
|
||||||
|
|
||||||
|
## Slicing
|
||||||
|
|
||||||
|
Node programs are called with more or less the exact argv as it appears
|
||||||
|
in C land, after the v8 and node-specific options have been plucked off.
|
||||||
|
As such, `argv[0]` is always `node` and `argv[1]` is always the
|
||||||
|
JavaScript program being run.
|
||||||
|
|
||||||
|
That's usually not very useful to you. So they're sliced off by
|
||||||
|
default. If you want them, then you can pass in `0` as the last
|
||||||
|
argument, or any other number that you'd like to slice off the start of
|
||||||
|
the list.
|
51
node_modules/markdown/node_modules/nopt/bin/nopt.js
generated
vendored
Executable file
51
node_modules/markdown/node_modules/nopt/bin/nopt.js
generated
vendored
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
var nopt = require("../lib/nopt")
|
||||||
|
, types = { num: Number
|
||||||
|
, bool: Boolean
|
||||||
|
, help: Boolean
|
||||||
|
, list: Array
|
||||||
|
, "num-list": [Number, Array]
|
||||||
|
, "str-list": [String, Array]
|
||||||
|
, "bool-list": [Boolean, Array]
|
||||||
|
, str: String
|
||||||
|
, clear: Boolean
|
||||||
|
, config: Boolean
|
||||||
|
, length: Number
|
||||||
|
}
|
||||||
|
, shorthands = { s: [ "--str", "astring" ]
|
||||||
|
, b: [ "--bool" ]
|
||||||
|
, nb: [ "--no-bool" ]
|
||||||
|
, tft: [ "--bool-list", "--no-bool-list", "--bool-list", "true" ]
|
||||||
|
, "?": ["--help"]
|
||||||
|
, h: ["--help"]
|
||||||
|
, H: ["--help"]
|
||||||
|
, n: [ "--num", "125" ]
|
||||||
|
, c: ["--config"]
|
||||||
|
, l: ["--length"]
|
||||||
|
}
|
||||||
|
, parsed = nopt( types
|
||||||
|
, shorthands
|
||||||
|
, process.argv
|
||||||
|
, 2 )
|
||||||
|
|
||||||
|
console.log("parsed", parsed)
|
||||||
|
|
||||||
|
if (parsed.help) {
|
||||||
|
console.log("")
|
||||||
|
console.log("nopt cli tester")
|
||||||
|
console.log("")
|
||||||
|
console.log("types")
|
||||||
|
console.log(Object.keys(types).map(function M (t) {
|
||||||
|
var type = types[t]
|
||||||
|
if (Array.isArray(type)) {
|
||||||
|
return [t, type.map(function (type) { return type.name })]
|
||||||
|
}
|
||||||
|
return [t, type && type.name]
|
||||||
|
}).reduce(function (s, i) {
|
||||||
|
s[i[0]] = i[1]
|
||||||
|
return s
|
||||||
|
}, {}))
|
||||||
|
console.log("")
|
||||||
|
console.log("shorthands")
|
||||||
|
console.log(shorthands)
|
||||||
|
}
|
30
node_modules/markdown/node_modules/nopt/examples/my-program.js
generated
vendored
Executable file
30
node_modules/markdown/node_modules/nopt/examples/my-program.js
generated
vendored
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
//process.env.DEBUG_NOPT = 1
|
||||||
|
|
||||||
|
// my-program.js
|
||||||
|
var nopt = require("../lib/nopt")
|
||||||
|
, Stream = require("stream").Stream
|
||||||
|
, path = require("path")
|
||||||
|
, knownOpts = { "foo" : [String, null]
|
||||||
|
, "bar" : [Stream, Number]
|
||||||
|
, "baz" : path
|
||||||
|
, "bloo" : [ "big", "medium", "small" ]
|
||||||
|
, "flag" : Boolean
|
||||||
|
, "pick" : Boolean
|
||||||
|
}
|
||||||
|
, shortHands = { "foofoo" : ["--foo", "Mr. Foo"]
|
||||||
|
, "b7" : ["--bar", "7"]
|
||||||
|
, "m" : ["--bloo", "medium"]
|
||||||
|
, "p" : ["--pick"]
|
||||||
|
, "f" : ["--flag", "true"]
|
||||||
|
, "g" : ["--flag"]
|
||||||
|
, "s" : "--flag"
|
||||||
|
}
|
||||||
|
// everything is optional.
|
||||||
|
// knownOpts and shorthands default to {}
|
||||||
|
// arg list defaults to process.argv
|
||||||
|
// slice defaults to 2
|
||||||
|
, parsed = nopt(knownOpts, shortHands, process.argv, 2)
|
||||||
|
|
||||||
|
console.log("parsed =\n"+ require("util").inspect(parsed))
|
612
node_modules/markdown/node_modules/nopt/lib/nopt.js
generated
vendored
Normal file
612
node_modules/markdown/node_modules/nopt/lib/nopt.js
generated
vendored
Normal file
@ -0,0 +1,612 @@
|
|||||||
|
// info about each config option.
|
||||||
|
|
||||||
|
var debug = process.env.DEBUG_NOPT || process.env.NOPT_DEBUG
|
||||||
|
? function () { console.error.apply(console, arguments) }
|
||||||
|
: function () {}
|
||||||
|
|
||||||
|
var url = require("url")
|
||||||
|
, path = require("path")
|
||||||
|
, Stream = require("stream").Stream
|
||||||
|
, abbrev = require("abbrev")
|
||||||
|
|
||||||
|
module.exports = exports = nopt
|
||||||
|
exports.clean = clean
|
||||||
|
|
||||||
|
exports.typeDefs =
|
||||||
|
{ String : { type: String, validate: validateString }
|
||||||
|
, Boolean : { type: Boolean, validate: validateBoolean }
|
||||||
|
, url : { type: url, validate: validateUrl }
|
||||||
|
, Number : { type: Number, validate: validateNumber }
|
||||||
|
, path : { type: path, validate: validatePath }
|
||||||
|
, Stream : { type: Stream, validate: validateStream }
|
||||||
|
, Date : { type: Date, validate: validateDate }
|
||||||
|
}
|
||||||
|
|
||||||
|
function nopt (types, shorthands, args, slice) {
|
||||||
|
args = args || process.argv
|
||||||
|
types = types || {}
|
||||||
|
shorthands = shorthands || {}
|
||||||
|
if (typeof slice !== "number") slice = 2
|
||||||
|
|
||||||
|
debug(types, shorthands, args, slice)
|
||||||
|
|
||||||
|
args = args.slice(slice)
|
||||||
|
var data = {}
|
||||||
|
, key
|
||||||
|
, remain = []
|
||||||
|
, cooked = args
|
||||||
|
, original = args.slice(0)
|
||||||
|
|
||||||
|
parse(args, data, remain, types, shorthands)
|
||||||
|
// now data is full
|
||||||
|
clean(data, types, exports.typeDefs)
|
||||||
|
data.argv = {remain:remain,cooked:cooked,original:original}
|
||||||
|
Object.defineProperty(data.argv, 'toString', { value: function () {
|
||||||
|
return this.original.map(JSON.stringify).join(" ")
|
||||||
|
}, enumerable: false })
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean (data, types, typeDefs) {
|
||||||
|
typeDefs = typeDefs || exports.typeDefs
|
||||||
|
var remove = {}
|
||||||
|
, typeDefault = [false, true, null, String, Number, Array]
|
||||||
|
|
||||||
|
Object.keys(data).forEach(function (k) {
|
||||||
|
if (k === "argv") return
|
||||||
|
var val = data[k]
|
||||||
|
, isArray = Array.isArray(val)
|
||||||
|
, type = types[k]
|
||||||
|
if (!isArray) val = [val]
|
||||||
|
if (!type) type = typeDefault
|
||||||
|
if (type === Array) type = typeDefault.concat(Array)
|
||||||
|
if (!Array.isArray(type)) type = [type]
|
||||||
|
|
||||||
|
debug("val=%j", val)
|
||||||
|
debug("types=", type)
|
||||||
|
val = val.map(function (val) {
|
||||||
|
// if it's an unknown value, then parse false/true/null/numbers/dates
|
||||||
|
if (typeof val === "string") {
|
||||||
|
debug("string %j", val)
|
||||||
|
val = val.trim()
|
||||||
|
if ((val === "null" && ~type.indexOf(null))
|
||||||
|
|| (val === "true" &&
|
||||||
|
(~type.indexOf(true) || ~type.indexOf(Boolean)))
|
||||||
|
|| (val === "false" &&
|
||||||
|
(~type.indexOf(false) || ~type.indexOf(Boolean)))) {
|
||||||
|
val = JSON.parse(val)
|
||||||
|
debug("jsonable %j", val)
|
||||||
|
} else if (~type.indexOf(Number) && !isNaN(val)) {
|
||||||
|
debug("convert to number", val)
|
||||||
|
val = +val
|
||||||
|
} else if (~type.indexOf(Date) && !isNaN(Date.parse(val))) {
|
||||||
|
debug("convert to date", val)
|
||||||
|
val = new Date(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!types.hasOwnProperty(k)) {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow `--no-blah` to set 'blah' to null if null is allowed
|
||||||
|
if (val === false && ~type.indexOf(null) &&
|
||||||
|
!(~type.indexOf(false) || ~type.indexOf(Boolean))) {
|
||||||
|
val = null
|
||||||
|
}
|
||||||
|
|
||||||
|
var d = {}
|
||||||
|
d[k] = val
|
||||||
|
debug("prevalidated val", d, val, types[k])
|
||||||
|
if (!validate(d, k, val, types[k], typeDefs)) {
|
||||||
|
if (exports.invalidHandler) {
|
||||||
|
exports.invalidHandler(k, val, types[k], data)
|
||||||
|
} else if (exports.invalidHandler !== false) {
|
||||||
|
debug("invalid: "+k+"="+val, types[k])
|
||||||
|
}
|
||||||
|
return remove
|
||||||
|
}
|
||||||
|
debug("validated val", d, val, types[k])
|
||||||
|
return d[k]
|
||||||
|
}).filter(function (val) { return val !== remove })
|
||||||
|
|
||||||
|
if (!val.length) delete data[k]
|
||||||
|
else if (isArray) {
|
||||||
|
debug(isArray, data[k], val)
|
||||||
|
data[k] = val
|
||||||
|
} else data[k] = val[0]
|
||||||
|
|
||||||
|
debug("k=%s val=%j", k, val, data[k])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateString (data, k, val) {
|
||||||
|
data[k] = String(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePath (data, k, val) {
|
||||||
|
data[k] = path.resolve(String(val))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateNumber (data, k, val) {
|
||||||
|
debug("validate Number %j %j %j", k, val, isNaN(val))
|
||||||
|
if (isNaN(val)) return false
|
||||||
|
data[k] = +val
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateDate (data, k, val) {
|
||||||
|
debug("validate Date %j %j %j", k, val, Date.parse(val))
|
||||||
|
var s = Date.parse(val)
|
||||||
|
if (isNaN(s)) return false
|
||||||
|
data[k] = new Date(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateBoolean (data, k, val) {
|
||||||
|
if (val instanceof Boolean) val = val.valueOf()
|
||||||
|
else if (typeof val === "string") {
|
||||||
|
if (!isNaN(val)) val = !!(+val)
|
||||||
|
else if (val === "null" || val === "false") val = false
|
||||||
|
else val = true
|
||||||
|
} else val = !!val
|
||||||
|
data[k] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateUrl (data, k, val) {
|
||||||
|
val = url.parse(String(val))
|
||||||
|
if (!val.host) return false
|
||||||
|
data[k] = val.href
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateStream (data, k, val) {
|
||||||
|
if (!(val instanceof Stream)) return false
|
||||||
|
data[k] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
function validate (data, k, val, type, typeDefs) {
|
||||||
|
// arrays are lists of types.
|
||||||
|
if (Array.isArray(type)) {
|
||||||
|
for (var i = 0, l = type.length; i < l; i ++) {
|
||||||
|
if (type[i] === Array) continue
|
||||||
|
if (validate(data, k, val, type[i], typeDefs)) return true
|
||||||
|
}
|
||||||
|
delete data[k]
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// an array of anything?
|
||||||
|
if (type === Array) return true
|
||||||
|
|
||||||
|
// NaN is poisonous. Means that something is not allowed.
|
||||||
|
if (type !== type) {
|
||||||
|
debug("Poison NaN", k, val, type)
|
||||||
|
delete data[k]
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// explicit list of values
|
||||||
|
if (val === type) {
|
||||||
|
debug("Explicitly allowed %j", val)
|
||||||
|
// if (isArray) (data[k] = data[k] || []).push(val)
|
||||||
|
// else data[k] = val
|
||||||
|
data[k] = val
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go through the list of typeDefs, validate against each one.
|
||||||
|
var ok = false
|
||||||
|
, types = Object.keys(typeDefs)
|
||||||
|
for (var i = 0, l = types.length; i < l; i ++) {
|
||||||
|
debug("test type %j %j %j", k, val, types[i])
|
||||||
|
var t = typeDefs[types[i]]
|
||||||
|
if (t && type === t.type) {
|
||||||
|
var d = {}
|
||||||
|
ok = false !== t.validate(d, k, val)
|
||||||
|
val = d[k]
|
||||||
|
if (ok) {
|
||||||
|
// if (isArray) (data[k] = data[k] || []).push(val)
|
||||||
|
// else data[k] = val
|
||||||
|
data[k] = val
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug("OK? %j (%j %j %j)", ok, k, val, types[i])
|
||||||
|
|
||||||
|
if (!ok) delete data[k]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse (args, data, remain, types, shorthands) {
|
||||||
|
debug("parse", args, data, remain)
|
||||||
|
|
||||||
|
var key = null
|
||||||
|
, abbrevs = abbrev(Object.keys(types))
|
||||||
|
, shortAbbr = abbrev(Object.keys(shorthands))
|
||||||
|
|
||||||
|
for (var i = 0; i < args.length; i ++) {
|
||||||
|
var arg = args[i]
|
||||||
|
debug("arg", arg)
|
||||||
|
|
||||||
|
if (arg.match(/^-{2,}$/)) {
|
||||||
|
// done with keys.
|
||||||
|
// the rest are args.
|
||||||
|
remain.push.apply(remain, args.slice(i + 1))
|
||||||
|
args[i] = "--"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var hadEq = false
|
||||||
|
if (arg.charAt(0) === "-" && arg.length > 1) {
|
||||||
|
if (arg.indexOf("=") !== -1) {
|
||||||
|
hadEq = true
|
||||||
|
var v = arg.split("=")
|
||||||
|
arg = v.shift()
|
||||||
|
v = v.join("=")
|
||||||
|
args.splice.apply(args, [i, 1].concat([arg, v]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if it's a shorthand
|
||||||
|
// if so, splice and back up to re-parse it.
|
||||||
|
var shRes = resolveShort(arg, shorthands, shortAbbr, abbrevs)
|
||||||
|
debug("arg=%j shRes=%j", arg, shRes)
|
||||||
|
if (shRes) {
|
||||||
|
debug(arg, shRes)
|
||||||
|
args.splice.apply(args, [i, 1].concat(shRes))
|
||||||
|
if (arg !== shRes[0]) {
|
||||||
|
i --
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arg = arg.replace(/^-+/, "")
|
||||||
|
var no = null
|
||||||
|
while (arg.toLowerCase().indexOf("no-") === 0) {
|
||||||
|
no = !no
|
||||||
|
arg = arg.substr(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abbrevs[arg]) arg = abbrevs[arg]
|
||||||
|
|
||||||
|
var isArray = types[arg] === Array ||
|
||||||
|
Array.isArray(types[arg]) && types[arg].indexOf(Array) !== -1
|
||||||
|
|
||||||
|
// allow unknown things to be arrays if specified multiple times.
|
||||||
|
if (!types.hasOwnProperty(arg) && data.hasOwnProperty(arg)) {
|
||||||
|
if (!Array.isArray(data[arg]))
|
||||||
|
data[arg] = [data[arg]]
|
||||||
|
isArray = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var val
|
||||||
|
, la = args[i + 1]
|
||||||
|
|
||||||
|
var isBool = typeof no === 'boolean' ||
|
||||||
|
types[arg] === Boolean ||
|
||||||
|
Array.isArray(types[arg]) && types[arg].indexOf(Boolean) !== -1 ||
|
||||||
|
(typeof types[arg] === 'undefined' && !hadEq) ||
|
||||||
|
(la === "false" &&
|
||||||
|
(types[arg] === null ||
|
||||||
|
Array.isArray(types[arg]) && ~types[arg].indexOf(null)))
|
||||||
|
|
||||||
|
if (isBool) {
|
||||||
|
// just set and move along
|
||||||
|
val = !no
|
||||||
|
// however, also support --bool true or --bool false
|
||||||
|
if (la === "true" || la === "false") {
|
||||||
|
val = JSON.parse(la)
|
||||||
|
la = null
|
||||||
|
if (no) val = !val
|
||||||
|
i ++
|
||||||
|
}
|
||||||
|
|
||||||
|
// also support "foo":[Boolean, "bar"] and "--foo bar"
|
||||||
|
if (Array.isArray(types[arg]) && la) {
|
||||||
|
if (~types[arg].indexOf(la)) {
|
||||||
|
// an explicit type
|
||||||
|
val = la
|
||||||
|
i ++
|
||||||
|
} else if ( la === "null" && ~types[arg].indexOf(null) ) {
|
||||||
|
// null allowed
|
||||||
|
val = null
|
||||||
|
i ++
|
||||||
|
} else if ( !la.match(/^-{2,}[^-]/) &&
|
||||||
|
!isNaN(la) &&
|
||||||
|
~types[arg].indexOf(Number) ) {
|
||||||
|
// number
|
||||||
|
val = +la
|
||||||
|
i ++
|
||||||
|
} else if ( !la.match(/^-[^-]/) && ~types[arg].indexOf(String) ) {
|
||||||
|
// string
|
||||||
|
val = la
|
||||||
|
i ++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArray) (data[arg] = data[arg] || []).push(val)
|
||||||
|
else data[arg] = val
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (la && la.match(/^-{2,}$/)) {
|
||||||
|
la = undefined
|
||||||
|
i --
|
||||||
|
}
|
||||||
|
|
||||||
|
val = la === undefined ? true : la
|
||||||
|
if (isArray) (data[arg] = data[arg] || []).push(val)
|
||||||
|
else data[arg] = val
|
||||||
|
|
||||||
|
i ++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
remain.push(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveShort (arg, shorthands, shortAbbr, abbrevs) {
|
||||||
|
// handle single-char shorthands glommed together, like
|
||||||
|
// npm ls -glp, but only if there is one dash, and only if
|
||||||
|
// all of the chars are single-char shorthands, and it's
|
||||||
|
// not a match to some other abbrev.
|
||||||
|
arg = arg.replace(/^-+/, '')
|
||||||
|
|
||||||
|
// if it's an exact known option, then don't go any further
|
||||||
|
if (abbrevs[arg] === arg)
|
||||||
|
return null
|
||||||
|
|
||||||
|
// if it's an exact known shortopt, same deal
|
||||||
|
if (shorthands[arg]) {
|
||||||
|
// make it an array, if it's a list of words
|
||||||
|
if (shorthands[arg] && !Array.isArray(shorthands[arg]))
|
||||||
|
shorthands[arg] = shorthands[arg].split(/\s+/)
|
||||||
|
|
||||||
|
return shorthands[arg]
|
||||||
|
}
|
||||||
|
|
||||||
|
// first check to see if this arg is a set of single-char shorthands
|
||||||
|
var singles = shorthands.___singles
|
||||||
|
if (!singles) {
|
||||||
|
singles = Object.keys(shorthands).filter(function (s) {
|
||||||
|
return s.length === 1
|
||||||
|
}).reduce(function (l,r) {
|
||||||
|
l[r] = true
|
||||||
|
return l
|
||||||
|
}, {})
|
||||||
|
shorthands.___singles = singles
|
||||||
|
debug('shorthand singles', singles)
|
||||||
|
}
|
||||||
|
|
||||||
|
var chrs = arg.split("").filter(function (c) {
|
||||||
|
return singles[c]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (chrs.join("") === arg) return chrs.map(function (c) {
|
||||||
|
return shorthands[c]
|
||||||
|
}).reduce(function (l, r) {
|
||||||
|
return l.concat(r)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
// if it's an arg abbrev, and not a literal shorthand, then prefer the arg
|
||||||
|
if (abbrevs[arg] && !shorthands[arg])
|
||||||
|
return null
|
||||||
|
|
||||||
|
// if it's an abbr for a shorthand, then use that
|
||||||
|
if (shortAbbr[arg])
|
||||||
|
arg = shortAbbr[arg]
|
||||||
|
|
||||||
|
// make it an array, if it's a list of words
|
||||||
|
if (shorthands[arg] && !Array.isArray(shorthands[arg]))
|
||||||
|
shorthands[arg] = shorthands[arg].split(/\s+/)
|
||||||
|
|
||||||
|
return shorthands[arg]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module === require.main) {
|
||||||
|
var assert = require("assert")
|
||||||
|
, util = require("util")
|
||||||
|
|
||||||
|
, shorthands =
|
||||||
|
{ s : ["--loglevel", "silent"]
|
||||||
|
, d : ["--loglevel", "info"]
|
||||||
|
, dd : ["--loglevel", "verbose"]
|
||||||
|
, ddd : ["--loglevel", "silly"]
|
||||||
|
, noreg : ["--no-registry"]
|
||||||
|
, reg : ["--registry"]
|
||||||
|
, "no-reg" : ["--no-registry"]
|
||||||
|
, silent : ["--loglevel", "silent"]
|
||||||
|
, verbose : ["--loglevel", "verbose"]
|
||||||
|
, h : ["--usage"]
|
||||||
|
, H : ["--usage"]
|
||||||
|
, "?" : ["--usage"]
|
||||||
|
, help : ["--usage"]
|
||||||
|
, v : ["--version"]
|
||||||
|
, f : ["--force"]
|
||||||
|
, desc : ["--description"]
|
||||||
|
, "no-desc" : ["--no-description"]
|
||||||
|
, "local" : ["--no-global"]
|
||||||
|
, l : ["--long"]
|
||||||
|
, p : ["--parseable"]
|
||||||
|
, porcelain : ["--parseable"]
|
||||||
|
, g : ["--global"]
|
||||||
|
}
|
||||||
|
|
||||||
|
, types =
|
||||||
|
{ aoa: Array
|
||||||
|
, nullstream: [null, Stream]
|
||||||
|
, date: Date
|
||||||
|
, str: String
|
||||||
|
, browser : String
|
||||||
|
, cache : path
|
||||||
|
, color : ["always", Boolean]
|
||||||
|
, depth : Number
|
||||||
|
, description : Boolean
|
||||||
|
, dev : Boolean
|
||||||
|
, editor : path
|
||||||
|
, force : Boolean
|
||||||
|
, global : Boolean
|
||||||
|
, globalconfig : path
|
||||||
|
, group : [String, Number]
|
||||||
|
, gzipbin : String
|
||||||
|
, logfd : [Number, Stream]
|
||||||
|
, loglevel : ["silent","win","error","warn","info","verbose","silly"]
|
||||||
|
, long : Boolean
|
||||||
|
, "node-version" : [false, String]
|
||||||
|
, npaturl : url
|
||||||
|
, npat : Boolean
|
||||||
|
, "onload-script" : [false, String]
|
||||||
|
, outfd : [Number, Stream]
|
||||||
|
, parseable : Boolean
|
||||||
|
, pre: Boolean
|
||||||
|
, prefix: path
|
||||||
|
, proxy : url
|
||||||
|
, "rebuild-bundle" : Boolean
|
||||||
|
, registry : url
|
||||||
|
, searchopts : String
|
||||||
|
, searchexclude: [null, String]
|
||||||
|
, shell : path
|
||||||
|
, t: [Array, String]
|
||||||
|
, tag : String
|
||||||
|
, tar : String
|
||||||
|
, tmp : path
|
||||||
|
, "unsafe-perm" : Boolean
|
||||||
|
, usage : Boolean
|
||||||
|
, user : String
|
||||||
|
, username : String
|
||||||
|
, userconfig : path
|
||||||
|
, version : Boolean
|
||||||
|
, viewer: path
|
||||||
|
, _exit : Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
; [["-v", {version:true}, []]
|
||||||
|
,["---v", {version:true}, []]
|
||||||
|
,["ls -s --no-reg connect -d",
|
||||||
|
{loglevel:"info",registry:null},["ls","connect"]]
|
||||||
|
,["ls ---s foo",{loglevel:"silent"},["ls","foo"]]
|
||||||
|
,["ls --registry blargle", {}, ["ls"]]
|
||||||
|
,["--no-registry", {registry:null}, []]
|
||||||
|
,["--no-color true", {color:false}, []]
|
||||||
|
,["--no-color false", {color:true}, []]
|
||||||
|
,["--no-color", {color:false}, []]
|
||||||
|
,["--color false", {color:false}, []]
|
||||||
|
,["--color --logfd 7", {logfd:7,color:true}, []]
|
||||||
|
,["--color=true", {color:true}, []]
|
||||||
|
,["--logfd=10", {logfd:10}, []]
|
||||||
|
,["--tmp=/tmp -tar=gtar",{tmp:"/tmp",tar:"gtar"},[]]
|
||||||
|
,["--tmp=tmp -tar=gtar",
|
||||||
|
{tmp:path.resolve(process.cwd(), "tmp"),tar:"gtar"},[]]
|
||||||
|
,["--logfd x", {}, []]
|
||||||
|
,["a -true -- -no-false", {true:true},["a","-no-false"]]
|
||||||
|
,["a -no-false", {false:false},["a"]]
|
||||||
|
,["a -no-no-true", {true:true}, ["a"]]
|
||||||
|
,["a -no-no-no-false", {false:false}, ["a"]]
|
||||||
|
,["---NO-no-No-no-no-no-nO-no-no"+
|
||||||
|
"-No-no-no-no-no-no-no-no-no"+
|
||||||
|
"-no-no-no-no-NO-NO-no-no-no-no-no-no"+
|
||||||
|
"-no-body-can-do-the-boogaloo-like-I-do"
|
||||||
|
,{"body-can-do-the-boogaloo-like-I-do":false}, []]
|
||||||
|
,["we are -no-strangers-to-love "+
|
||||||
|
"--you-know=the-rules --and=so-do-i "+
|
||||||
|
"---im-thinking-of=a-full-commitment "+
|
||||||
|
"--no-you-would-get-this-from-any-other-guy "+
|
||||||
|
"--no-gonna-give-you-up "+
|
||||||
|
"-no-gonna-let-you-down=true "+
|
||||||
|
"--no-no-gonna-run-around false "+
|
||||||
|
"--desert-you=false "+
|
||||||
|
"--make-you-cry false "+
|
||||||
|
"--no-tell-a-lie "+
|
||||||
|
"--no-no-and-hurt-you false"
|
||||||
|
,{"strangers-to-love":false
|
||||||
|
,"you-know":"the-rules"
|
||||||
|
,"and":"so-do-i"
|
||||||
|
,"you-would-get-this-from-any-other-guy":false
|
||||||
|
,"gonna-give-you-up":false
|
||||||
|
,"gonna-let-you-down":false
|
||||||
|
,"gonna-run-around":false
|
||||||
|
,"desert-you":false
|
||||||
|
,"make-you-cry":false
|
||||||
|
,"tell-a-lie":false
|
||||||
|
,"and-hurt-you":false
|
||||||
|
},["we", "are"]]
|
||||||
|
,["-t one -t two -t three"
|
||||||
|
,{t: ["one", "two", "three"]}
|
||||||
|
,[]]
|
||||||
|
,["-t one -t null -t three four five null"
|
||||||
|
,{t: ["one", "null", "three"]}
|
||||||
|
,["four", "five", "null"]]
|
||||||
|
,["-t foo"
|
||||||
|
,{t:["foo"]}
|
||||||
|
,[]]
|
||||||
|
,["--no-t"
|
||||||
|
,{t:["false"]}
|
||||||
|
,[]]
|
||||||
|
,["-no-no-t"
|
||||||
|
,{t:["true"]}
|
||||||
|
,[]]
|
||||||
|
,["-aoa one -aoa null -aoa 100"
|
||||||
|
,{aoa:["one", null, 100]}
|
||||||
|
,[]]
|
||||||
|
,["-str 100"
|
||||||
|
,{str:"100"}
|
||||||
|
,[]]
|
||||||
|
,["--color always"
|
||||||
|
,{color:"always"}
|
||||||
|
,[]]
|
||||||
|
,["--no-nullstream"
|
||||||
|
,{nullstream:null}
|
||||||
|
,[]]
|
||||||
|
,["--nullstream false"
|
||||||
|
,{nullstream:null}
|
||||||
|
,[]]
|
||||||
|
,["--notadate=2011-01-25"
|
||||||
|
,{notadate: "2011-01-25"}
|
||||||
|
,[]]
|
||||||
|
,["--date 2011-01-25"
|
||||||
|
,{date: new Date("2011-01-25")}
|
||||||
|
,[]]
|
||||||
|
,["-cl 1"
|
||||||
|
,{config: true, length: 1}
|
||||||
|
,[]
|
||||||
|
,{config: Boolean, length: Number, clear: Boolean}
|
||||||
|
,{c: "--config", l: "--length"}]
|
||||||
|
,["--acount bla"
|
||||||
|
,{"acount":true}
|
||||||
|
,["bla"]
|
||||||
|
,{account: Boolean, credentials: Boolean, options: String}
|
||||||
|
,{a:"--account", c:"--credentials",o:"--options"}]
|
||||||
|
,["--clear"
|
||||||
|
,{clear:true}
|
||||||
|
,[]
|
||||||
|
,{clear:Boolean,con:Boolean,len:Boolean,exp:Boolean,add:Boolean,rep:Boolean}
|
||||||
|
,{c:"--con",l:"--len",e:"--exp",a:"--add",r:"--rep"}]
|
||||||
|
,["--file -"
|
||||||
|
,{"file":"-"}
|
||||||
|
,[]
|
||||||
|
,{file:String}
|
||||||
|
,{}]
|
||||||
|
,["--file -"
|
||||||
|
,{"file":true}
|
||||||
|
,["-"]
|
||||||
|
,{file:Boolean}
|
||||||
|
,{}]
|
||||||
|
].forEach(function (test) {
|
||||||
|
var argv = test[0].split(/\s+/)
|
||||||
|
, opts = test[1]
|
||||||
|
, rem = test[2]
|
||||||
|
, actual = nopt(test[3] || types, test[4] || shorthands, argv, 0)
|
||||||
|
, parsed = actual.argv
|
||||||
|
delete actual.argv
|
||||||
|
console.log(util.inspect(actual, false, 2, true), parsed.remain)
|
||||||
|
for (var i in opts) {
|
||||||
|
var e = JSON.stringify(opts[i])
|
||||||
|
, a = JSON.stringify(actual[i] === undefined ? null : actual[i])
|
||||||
|
if (e && typeof e === "object") {
|
||||||
|
assert.deepEqual(e, a)
|
||||||
|
} else {
|
||||||
|
assert.equal(e, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.deepEqual(rem, parsed.remain)
|
||||||
|
})
|
||||||
|
}
|
3
node_modules/markdown/node_modules/nopt/node_modules/abbrev/CONTRIBUTING.md
generated
vendored
Normal file
3
node_modules/markdown/node_modules/nopt/node_modules/abbrev/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
To get started, <a
|
||||||
|
href="http://www.clahub.com/agreements/isaacs/abbrev-js">sign the
|
||||||
|
Contributor License Agreement</a>.
|
23
node_modules/markdown/node_modules/nopt/node_modules/abbrev/LICENSE
generated
vendored
Normal file
23
node_modules/markdown/node_modules/nopt/node_modules/abbrev/LICENSE
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
23
node_modules/markdown/node_modules/nopt/node_modules/abbrev/README.md
generated
vendored
Normal file
23
node_modules/markdown/node_modules/nopt/node_modules/abbrev/README.md
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# abbrev-js
|
||||||
|
|
||||||
|
Just like [ruby's Abbrev](http://apidock.com/ruby/Abbrev).
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
var abbrev = require("abbrev");
|
||||||
|
abbrev("foo", "fool", "folding", "flop");
|
||||||
|
|
||||||
|
// returns:
|
||||||
|
{ fl: 'flop'
|
||||||
|
, flo: 'flop'
|
||||||
|
, flop: 'flop'
|
||||||
|
, fol: 'folding'
|
||||||
|
, fold: 'folding'
|
||||||
|
, foldi: 'folding'
|
||||||
|
, foldin: 'folding'
|
||||||
|
, folding: 'folding'
|
||||||
|
, foo: 'foo'
|
||||||
|
, fool: 'fool'
|
||||||
|
}
|
||||||
|
|
||||||
|
This is handy for command-line scripts, or other cases where you want to be able to accept shorthands.
|
62
node_modules/markdown/node_modules/nopt/node_modules/abbrev/abbrev.js
generated
vendored
Normal file
62
node_modules/markdown/node_modules/nopt/node_modules/abbrev/abbrev.js
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
module.exports = exports = abbrev.abbrev = abbrev
|
||||||
|
|
||||||
|
abbrev.monkeyPatch = monkeyPatch
|
||||||
|
|
||||||
|
function monkeyPatch () {
|
||||||
|
Object.defineProperty(Array.prototype, 'abbrev', {
|
||||||
|
value: function () { return abbrev(this) },
|
||||||
|
enumerable: false, configurable: true, writable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'abbrev', {
|
||||||
|
value: function () { return abbrev(Object.keys(this)) },
|
||||||
|
enumerable: false, configurable: true, writable: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function abbrev (list) {
|
||||||
|
if (arguments.length !== 1 || !Array.isArray(list)) {
|
||||||
|
list = Array.prototype.slice.call(arguments, 0)
|
||||||
|
}
|
||||||
|
for (var i = 0, l = list.length, args = [] ; i < l ; i ++) {
|
||||||
|
args[i] = typeof list[i] === "string" ? list[i] : String(list[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort them lexicographically, so that they're next to their nearest kin
|
||||||
|
args = args.sort(lexSort)
|
||||||
|
|
||||||
|
// walk through each, seeing how much it has in common with the next and previous
|
||||||
|
var abbrevs = {}
|
||||||
|
, prev = ""
|
||||||
|
for (var i = 0, l = args.length ; i < l ; i ++) {
|
||||||
|
var current = args[i]
|
||||||
|
, next = args[i + 1] || ""
|
||||||
|
, nextMatches = true
|
||||||
|
, prevMatches = true
|
||||||
|
if (current === next) continue
|
||||||
|
for (var j = 0, cl = current.length ; j < cl ; j ++) {
|
||||||
|
var curChar = current.charAt(j)
|
||||||
|
nextMatches = nextMatches && curChar === next.charAt(j)
|
||||||
|
prevMatches = prevMatches && curChar === prev.charAt(j)
|
||||||
|
if (!nextMatches && !prevMatches) {
|
||||||
|
j ++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = current
|
||||||
|
if (j === cl) {
|
||||||
|
abbrevs[current] = current
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for (var a = current.substr(0, j) ; j <= cl ; j ++) {
|
||||||
|
abbrevs[a] = current
|
||||||
|
a += current.charAt(j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return abbrevs
|
||||||
|
}
|
||||||
|
|
||||||
|
function lexSort (a, b) {
|
||||||
|
return a === b ? 0 : a > b ? 1 : -1
|
||||||
|
}
|
29
node_modules/markdown/node_modules/nopt/node_modules/abbrev/package.json
generated
vendored
Normal file
29
node_modules/markdown/node_modules/nopt/node_modules/abbrev/package.json
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "abbrev",
|
||||||
|
"version": "1.0.5",
|
||||||
|
"description": "Like ruby's abbrev module, but in js",
|
||||||
|
"author": {
|
||||||
|
"name": "Isaac Z. Schlueter",
|
||||||
|
"email": "i@izs.me"
|
||||||
|
},
|
||||||
|
"main": "abbrev.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "node test.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "http://github.com/isaacs/abbrev-js"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"type": "MIT",
|
||||||
|
"url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE"
|
||||||
|
},
|
||||||
|
"readme": "# abbrev-js\n\nJust like [ruby's Abbrev](http://apidock.com/ruby/Abbrev).\n\nUsage:\n\n var abbrev = require(\"abbrev\");\n abbrev(\"foo\", \"fool\", \"folding\", \"flop\");\n \n // returns:\n { fl: 'flop'\n , flo: 'flop'\n , flop: 'flop'\n , fol: 'folding'\n , fold: 'folding'\n , foldi: 'folding'\n , foldin: 'folding'\n , folding: 'folding'\n , foo: 'foo'\n , fool: 'fool'\n }\n\nThis is handy for command-line scripts, or other cases where you want to be able to accept shorthands.\n",
|
||||||
|
"readmeFilename": "README.md",
|
||||||
|
"_id": "abbrev@1.0.5",
|
||||||
|
"dist": {
|
||||||
|
"shasum": "8878621df7d367d2b65a37fd163e59df351fbfa4"
|
||||||
|
},
|
||||||
|
"_from": "abbrev@1",
|
||||||
|
"_resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz"
|
||||||
|
}
|
47
node_modules/markdown/node_modules/nopt/node_modules/abbrev/test.js
generated
vendored
Normal file
47
node_modules/markdown/node_modules/nopt/node_modules/abbrev/test.js
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
var abbrev = require('./abbrev.js')
|
||||||
|
var assert = require("assert")
|
||||||
|
var util = require("util")
|
||||||
|
|
||||||
|
console.log("TAP Version 13")
|
||||||
|
var count = 0
|
||||||
|
|
||||||
|
function test (list, expect) {
|
||||||
|
count++
|
||||||
|
var actual = abbrev(list)
|
||||||
|
assert.deepEqual(actual, expect,
|
||||||
|
"abbrev("+util.inspect(list)+") === " + util.inspect(expect) + "\n"+
|
||||||
|
"actual: "+util.inspect(actual))
|
||||||
|
actual = abbrev.apply(exports, list)
|
||||||
|
assert.deepEqual(abbrev.apply(exports, list), expect,
|
||||||
|
"abbrev("+list.map(JSON.stringify).join(",")+") === " + util.inspect(expect) + "\n"+
|
||||||
|
"actual: "+util.inspect(actual))
|
||||||
|
console.log('ok - ' + list.join(' '))
|
||||||
|
}
|
||||||
|
|
||||||
|
test([ "ruby", "ruby", "rules", "rules", "rules" ],
|
||||||
|
{ rub: 'ruby'
|
||||||
|
, ruby: 'ruby'
|
||||||
|
, rul: 'rules'
|
||||||
|
, rule: 'rules'
|
||||||
|
, rules: 'rules'
|
||||||
|
})
|
||||||
|
test(["fool", "foom", "pool", "pope"],
|
||||||
|
{ fool: 'fool'
|
||||||
|
, foom: 'foom'
|
||||||
|
, poo: 'pool'
|
||||||
|
, pool: 'pool'
|
||||||
|
, pop: 'pope'
|
||||||
|
, pope: 'pope'
|
||||||
|
})
|
||||||
|
test(["a", "ab", "abc", "abcd", "abcde", "acde"],
|
||||||
|
{ a: 'a'
|
||||||
|
, ab: 'ab'
|
||||||
|
, abc: 'abc'
|
||||||
|
, abcd: 'abcd'
|
||||||
|
, abcde: 'abcde'
|
||||||
|
, ac: 'acde'
|
||||||
|
, acd: 'acde'
|
||||||
|
, acde: 'acde'
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log("0..%d", count)
|
36
node_modules/markdown/node_modules/nopt/package.json
generated
vendored
Normal file
36
node_modules/markdown/node_modules/nopt/package.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
68
node_modules/markdown/package.json
generated
vendored
Normal file
68
node_modules/markdown/package.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
5
node_modules/markdown/seed.yml
generated
vendored
Normal file
5
node_modules/markdown/seed.yml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
name: markdown-js
|
||||||
|
description: JavaScript implementation of Markdown
|
||||||
|
tags: markdown parser
|
||||||
|
version: 0.1.2
|
1
node_modules/pushover-notifications/.npmignore
generated
vendored
Normal file
1
node_modules/pushover-notifications/.npmignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
npm-debug.log
|
16
node_modules/pushover-notifications/LICENSE
generated
vendored
Normal file
16
node_modules/pushover-notifications/LICENSE
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Aaron Bieber <deftly@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
89
node_modules/pushover-notifications/README.md
generated
vendored
Normal file
89
node_modules/pushover-notifications/README.md
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|

|
||||||
|
|
||||||
|
Send [pushover.net](http://pushover.net) notifications from Node.JS
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
npm install pushover-notifications
|
||||||
|
|
||||||
|
### Pushover API values
|
||||||
|
|
||||||
|
Any API paramaters, as found on https://pushover.net/api, can be passed in the object. For example, `retry` and `expire` can be added to the object being passed to `.send`! Here's an example with many different parameters.
|
||||||
|
```javascript
|
||||||
|
var msg = {
|
||||||
|
message: "This is a message",
|
||||||
|
title: "Well - this is fantastic",
|
||||||
|
sound: 'magic',
|
||||||
|
device: 'test_device',
|
||||||
|
priority: 2,
|
||||||
|
url: "http://pushover.net",
|
||||||
|
url_title: "Pushover Website"
|
||||||
|
};
|
||||||
|
```
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Sending a message
|
||||||
|
```javascript
|
||||||
|
|
||||||
|
var push = require( 'pushover-notifications' );
|
||||||
|
|
||||||
|
var p = new push( {
|
||||||
|
user: process.env['PUSHOVER_USER'],
|
||||||
|
token: process.env['PUSHOVER_TOKEN'],
|
||||||
|
// onerror: function(error) {},
|
||||||
|
// update_sounds: true // update the list of sounds every day - will
|
||||||
|
// prevent app from exiting.
|
||||||
|
});
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
// These values correspond to the parameters detailed on https://pushover.net/api
|
||||||
|
// 'message' is required. All other values are optional.
|
||||||
|
message: 'omg node test', // required
|
||||||
|
title: "Well - this is fantastic",
|
||||||
|
sound: 'magic',
|
||||||
|
device: 'devicename',
|
||||||
|
priority: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
p.send( msg, function( err, result ) {
|
||||||
|
if ( err ) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log( result );
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sending a message to multiple users
|
||||||
|
```javascript
|
||||||
|
|
||||||
|
var users = [
|
||||||
|
'token1',
|
||||||
|
'token2',
|
||||||
|
'token3'
|
||||||
|
];
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
message: 'omg node test',
|
||||||
|
title: "Well - this is fantastic",
|
||||||
|
sound: 'magic' // optional
|
||||||
|
priority: 1 // optional,
|
||||||
|
};
|
||||||
|
|
||||||
|
for ( var i = 0, l = users.length; i < l; i++ ) {
|
||||||
|
|
||||||
|
msg.user = users[i];
|
||||||
|
// token can be overwritten as well.
|
||||||
|
|
||||||
|
p.send( msg, function( err, result ) {
|
||||||
|
if ( err ) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log( result );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
1
node_modules/pushover-notifications/index.js
generated
vendored
Normal file
1
node_modules/pushover-notifications/index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require( './lib/pushover' );
|
180
node_modules/pushover-notifications/lib/pushover.js
generated
vendored
Normal file
180
node_modules/pushover-notifications/lib/pushover.js
generated
vendored
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
var https = require('https'),
|
||||||
|
url = require('url'),
|
||||||
|
qs = require('querystring'),
|
||||||
|
p_url = 'https://api.pushover.net/1/messages.json';
|
||||||
|
|
||||||
|
function setDefaults(o) {
|
||||||
|
var def = [
|
||||||
|
'device',
|
||||||
|
'title',
|
||||||
|
'url',
|
||||||
|
'url_title',
|
||||||
|
'priority',
|
||||||
|
'timestamp',
|
||||||
|
'sound'
|
||||||
|
];
|
||||||
|
|
||||||
|
var i = 0; l = def.length;
|
||||||
|
for (; i < l; i++) {
|
||||||
|
if (!o[def[i]]) {
|
||||||
|
o[def[i]] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Pushover(opts) {
|
||||||
|
var self = this;
|
||||||
|
this.token = opts.token;
|
||||||
|
this.user = opts.user;
|
||||||
|
this.httpOptions = opts.httpOptions;
|
||||||
|
this.sounds = {
|
||||||
|
"pushover":"Pushover (default)",
|
||||||
|
"bike":"Bike",
|
||||||
|
"bugle":"Bugle",
|
||||||
|
"cashregister":"Cash Register",
|
||||||
|
"classical":"Classical",
|
||||||
|
"cosmic":"Cosmic",
|
||||||
|
"falling":"Falling",
|
||||||
|
"gamelan":"Gamelan",
|
||||||
|
"incoming":"Incoming",
|
||||||
|
"intermission":"Intermission",
|
||||||
|
"magic":"Magic",
|
||||||
|
"mechanical":"Mechanical",
|
||||||
|
"pianobar":"Piano Bar",
|
||||||
|
"siren":"Siren",
|
||||||
|
"spacealarm":"Space Alarm",
|
||||||
|
"tugboat":"Tug Boat",
|
||||||
|
"alien":"Alien Alarm (long)",
|
||||||
|
"climb":"Climb (long)",
|
||||||
|
"persistent":"Persistent (long)",
|
||||||
|
"echo":"Pushover Echo (long)",
|
||||||
|
"updown":"Up Down (long)",
|
||||||
|
"none":"None (silent)"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (opts.debug) {
|
||||||
|
this.debug = opts.debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.onerror) {
|
||||||
|
this.onerror = opts.onerror;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.update_sounds) {
|
||||||
|
self.updateSounds();
|
||||||
|
setInterval(function() {
|
||||||
|
self.updateSounds();
|
||||||
|
}, 86400000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pushover.prototype.errors = function(d) {
|
||||||
|
if (typeof d === 'string') {
|
||||||
|
d = JSON.parse(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d.errors) {
|
||||||
|
if (this.onerror) {
|
||||||
|
this.onerror.call(null, d.errors[0]);
|
||||||
|
} else {
|
||||||
|
throw new Error(d.errors[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Pushover.prototype.updateSounds = function() {
|
||||||
|
var self = this, data = '';
|
||||||
|
var surl = 'https://api.pushover.net/1/sounds.json?token=' + self.token;
|
||||||
|
var req = https.request(url.parse(surl) , function(res) {
|
||||||
|
res.on('end', function() {
|
||||||
|
var j = JSON.parse(data);
|
||||||
|
self.errors(data);
|
||||||
|
self.sounds = j.sounds;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on('data', function(chunk) {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', function(e) {
|
||||||
|
err = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
req.write('');
|
||||||
|
req.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
Pushover.prototype.send = function(obj, fn) {
|
||||||
|
var self = this;
|
||||||
|
var o = url.parse(p_url);
|
||||||
|
o.method = "POST";
|
||||||
|
|
||||||
|
obj = setDefaults(obj);
|
||||||
|
|
||||||
|
if (! self.sounds[ obj.sound ]) {
|
||||||
|
obj.sound = 'pushover';
|
||||||
|
}
|
||||||
|
|
||||||
|
var req_string = {
|
||||||
|
token: self.token || obj.token,
|
||||||
|
user: self.user || obj.user
|
||||||
|
};
|
||||||
|
|
||||||
|
var p;
|
||||||
|
for (p in obj) {
|
||||||
|
req_string[ p ] = obj[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
req_string = qs.stringify(req_string);
|
||||||
|
|
||||||
|
o.headers = {
|
||||||
|
'Content-Length': req_string.length
|
||||||
|
};
|
||||||
|
|
||||||
|
var httpOpts = self.httpOptions;
|
||||||
|
if (httpOpts) {
|
||||||
|
Object.keys(httpOpts).forEach(function(key) {
|
||||||
|
o[key] = httpOpts[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var req = https.request(o, function(res) {
|
||||||
|
if (self.debug) {
|
||||||
|
console.log(res.statusCode);
|
||||||
|
}
|
||||||
|
var err;
|
||||||
|
var data = '';
|
||||||
|
res.on('end', function() {
|
||||||
|
self.errors(data);
|
||||||
|
if (fn) {
|
||||||
|
fn.call(null, err, data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on('data', function(chunk) {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', function(err) {
|
||||||
|
if (fn) {
|
||||||
|
fn.call(null, err);
|
||||||
|
}
|
||||||
|
// In the tests the "end" event did not get emitted if "error" was emitted,
|
||||||
|
// but to be sure that the callback is not get called twice, null the callback function
|
||||||
|
fn = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (self.debug) {
|
||||||
|
console.log (req_string);
|
||||||
|
}
|
||||||
|
req.write(req_string);
|
||||||
|
req.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
exports = module.exports = Pushover;
|
28
node_modules/pushover-notifications/package.json
generated
vendored
Normal file
28
node_modules/pushover-notifications/package.json
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"author": {
|
||||||
|
"name": "Aaron Bieber",
|
||||||
|
"email": "aaron@qbit.io"
|
||||||
|
},
|
||||||
|
"name": "pushover-notifications",
|
||||||
|
"description": "Pushover API for node.js",
|
||||||
|
"version": "0.2.2",
|
||||||
|
"homepage": "http://github.com/qbit/node-pushover",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/qbit/node-pushover.git"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {},
|
||||||
|
"optionalDependencies": {},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
},
|
||||||
|
"readme": "\n\nSend [pushover.net](http://pushover.net) notifications from Node.JS\n\n## Usage\n\n### Install\n\n\tnpm install pushover-notifications\n\t\n### Pushover API values\n\nAny API paramaters, as found on https://pushover.net/api, can be passed in the object. For example, `retry` and `expire` can be added to the object being passed to `.send`! Here's an example with many different parameters.\n```javascript\nvar msg = {\n\tmessage: \"This is a message\",\n\ttitle: \"Well - this is fantastic\",\n\tsound: 'magic',\n\tdevice: 'test_device',\n\tpriority: 2,\n\turl: \"http://pushover.net\",\n\turl_title: \"Pushover Website\"\n};\n```\n## Examples\n\n### Sending a message\n```javascript\n\nvar push = require( 'pushover-notifications' );\n\nvar p = new push( {\n\tuser: process.env['PUSHOVER_USER'],\n\ttoken: process.env['PUSHOVER_TOKEN'],\n\t// onerror: function(error) {},\n\t// update_sounds: true // update the list of sounds every day - will\n\t// prevent app from exiting.\n});\n\nvar msg = {\n\t// These values correspond to the parameters detailed on https://pushover.net/api\n\t// 'message' is required. All other values are optional.\n\tmessage: 'omg node test',\t// required\n\ttitle: \"Well - this is fantastic\",\n\tsound: 'magic',\n\tdevice: 'devicename',\n\tpriority: 1\n};\n\np.send( msg, function( err, result ) {\n\tif ( err ) {\n\t\tthrow err;\n\t}\n\n\tconsole.log( result );\n});\n```\n\n### Sending a message to multiple users\n```javascript\n\nvar users = [\n 'token1',\n 'token2',\n 'token3'\n];\n\nvar msg = {\n message: 'omg node test',\n title: \"Well - this is fantastic\",\n sound: 'magic' // optional\n priority: 1 // optional,\n};\n\nfor ( var i = 0, l = users.length; i < l; i++ ) {\n\n msg.user = users[i];\n // token can be overwritten as well.\n\n p.send( msg, function( err, result ) {\n if ( err ) {\n throw err;\n }\n\n console.log( result );\n });\n}\n\n```\n",
|
||||||
|
"readmeFilename": "README.md",
|
||||||
|
"_id": "pushover-notifications@0.2.2",
|
||||||
|
"dist": {
|
||||||
|
"shasum": "b151e5729b7014d84dcb71b1a86c247c124eb277"
|
||||||
|
},
|
||||||
|
"_from": "pushover-notifications@",
|
||||||
|
"_resolved": "https://registry.npmjs.org/pushover-notifications/-/pushover-notifications-0.2.2.tgz"
|
||||||
|
}
|
25
node_modules/pushover-notifications/test/test-onerror.js
generated
vendored
Normal file
25
node_modules/pushover-notifications/test/test-onerror.js
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
var push = require( '../lib/pushover.js' );
|
||||||
|
|
||||||
|
var p = new push( {
|
||||||
|
user: process.env['PUSHOVER_USER'],
|
||||||
|
token: process.env['PUSHOVER_TOKEN'],
|
||||||
|
update_sounds: false,
|
||||||
|
debug: true,
|
||||||
|
onerror: function(err) {
|
||||||
|
console.log('ERROR!', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
message: 'omg node test',
|
||||||
|
sound: 'magic',
|
||||||
|
title: "Well - this is fantastic",
|
||||||
|
};
|
||||||
|
|
||||||
|
// console.log( p );
|
||||||
|
|
||||||
|
p.send( msg, function( err, result ) {
|
||||||
|
console.log( 'error', err );
|
||||||
|
console.log( 'result', result );
|
||||||
|
// process.exit(0);
|
||||||
|
});
|
22
node_modules/pushover-notifications/test/test.js
generated
vendored
Normal file
22
node_modules/pushover-notifications/test/test.js
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
var push = require( '../lib/pushover.js' );
|
||||||
|
|
||||||
|
var p = new push( {
|
||||||
|
user: process.env['PUSHOVER_USER'],
|
||||||
|
token: process.env['PUSHOVER_TOKEN'],
|
||||||
|
update_sounds: false,
|
||||||
|
debug: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
message: 'omg node test',
|
||||||
|
sound: 'magic',
|
||||||
|
title: "Well - this is fantastic",
|
||||||
|
};
|
||||||
|
|
||||||
|
// console.log( p );
|
||||||
|
|
||||||
|
p.send( msg, function( err, result ) {
|
||||||
|
console.log( 'error', err );
|
||||||
|
console.log( 'result', result );
|
||||||
|
// process.exit(0);
|
||||||
|
});
|
21
node_modules/pushover-notifications/test/test_multi.js
generated
vendored
Normal file
21
node_modules/pushover-notifications/test/test_multi.js
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
var push = require( '../lib/pushover.js' );
|
||||||
|
|
||||||
|
var p = new push( {
|
||||||
|
// user: process.env['PUSHOVER_USER'],
|
||||||
|
token: process.env['PUSHOVER_TOKEN'],
|
||||||
|
debug: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var msg = {
|
||||||
|
message: 'omg node test',
|
||||||
|
title: "Well - this is fantastic",
|
||||||
|
user: process.env['PUSHOVER_USER']
|
||||||
|
};
|
||||||
|
|
||||||
|
// console.log( p );
|
||||||
|
|
||||||
|
p.send( msg, function( err, result ) {
|
||||||
|
console.log( err );
|
||||||
|
console.log( result );
|
||||||
|
process.exit(0);
|
||||||
|
});
|
5
node_modules/strong-cluster-connect-store/.idea/encodings.xml
generated
vendored
Normal file
5
node_modules/strong-cluster-connect-store/.idea/encodings.xml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||||
|
</project>
|
||||||
|
|
9
node_modules/strong-cluster-connect-store/.idea/inspectionProfiles/Project_Default.xml
generated
vendored
Normal file
9
node_modules/strong-cluster-connect-store/.idea/inspectionProfiles/Project_Default.xml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0" is_locked="false">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<option name="myLocal" value="false" />
|
||||||
|
<inspection_tool class="JSHint" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JSLastCommaInArrayLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="JSLastCommaInObjectLiteral" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
7
node_modules/strong-cluster-connect-store/.idea/inspectionProfiles/profiles_settings.xml
generated
vendored
Normal file
7
node_modules/strong-cluster-connect-store/.idea/inspectionProfiles/profiles_settings.xml
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="PROJECT_PROFILE" value="Project Default" />
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="true" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
11
node_modules/strong-cluster-connect-store/.idea/jsLibraryMappings.xml
generated
vendored
Normal file
11
node_modules/strong-cluster-connect-store/.idea/jsLibraryMappings.xml
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptLibraryMappings">
|
||||||
|
<file url="file://$PROJECT_DIR$" libraries="{Node.js Dependencies for strong-cluster-connect-store}" />
|
||||||
|
<file url="PROJECT" libraries="{Node.js v0.11.3 Core Modules}" />
|
||||||
|
<includedPredefinedLibrary name="Node.js Globals" />
|
||||||
|
<excludedPredefinedLibrary name="HTML" />
|
||||||
|
<excludedPredefinedLibrary name="HTML5 / EcmaScript 5" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
62
node_modules/strong-cluster-connect-store/.idea/jsLinters/jshint.xml
generated
vendored
Normal file
62
node_modules/strong-cluster-connect-store/.idea/jsLinters/jshint.xml
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JSHintConfiguration" version="2.1.4" use-config-file="true">
|
||||||
|
<option bitwise="true" />
|
||||||
|
<option camelcase="false" />
|
||||||
|
<option curly="true" />
|
||||||
|
<option eqeqeq="true" />
|
||||||
|
<option forin="true" />
|
||||||
|
<option immed="false" />
|
||||||
|
<option latedef="false" />
|
||||||
|
<option newcap="false" />
|
||||||
|
<option noarg="true" />
|
||||||
|
<option noempty="true" />
|
||||||
|
<option nonew="true" />
|
||||||
|
<option plusplus="false" />
|
||||||
|
<option undef="true" />
|
||||||
|
<option unused="false" />
|
||||||
|
<option strict="true" />
|
||||||
|
<option trailing="false" />
|
||||||
|
<option asi="false" />
|
||||||
|
<option boss="false" />
|
||||||
|
<option debug="false" />
|
||||||
|
<option eqnull="false" />
|
||||||
|
<option esnext="false" />
|
||||||
|
<option evil="false" />
|
||||||
|
<option expr="false" />
|
||||||
|
<option funcscope="false" />
|
||||||
|
<option globalstrict="false" />
|
||||||
|
<option iterator="false" />
|
||||||
|
<option lastsemic="false" />
|
||||||
|
<option laxbreak="false" />
|
||||||
|
<option laxcomma="false" />
|
||||||
|
<option loopfunc="false" />
|
||||||
|
<option multistr="false" />
|
||||||
|
<option proto="false" />
|
||||||
|
<option scripturl="false" />
|
||||||
|
<option smarttabs="false" />
|
||||||
|
<option shadow="false" />
|
||||||
|
<option sub="false" />
|
||||||
|
<option supernew="false" />
|
||||||
|
<option validthis="false" />
|
||||||
|
<option browser="true" />
|
||||||
|
<option couch="false" />
|
||||||
|
<option devel="false" />
|
||||||
|
<option dojo="false" />
|
||||||
|
<option jquery="false" />
|
||||||
|
<option mootools="false" />
|
||||||
|
<option node="false" />
|
||||||
|
<option nonstandard="false" />
|
||||||
|
<option prototypejs="false" />
|
||||||
|
<option rhino="false" />
|
||||||
|
<option worker="false" />
|
||||||
|
<option wsh="false" />
|
||||||
|
<option yui="false" />
|
||||||
|
<option nomen="false" />
|
||||||
|
<option onevar="false" />
|
||||||
|
<option passfail="false" />
|
||||||
|
<option white="false" />
|
||||||
|
<option maxerr="50" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
13
node_modules/strong-cluster-connect-store/.idea/libraries/Node_js_Dependencies_for_strong_cluster_connect_store.xml
generated
vendored
Normal file
13
node_modules/strong-cluster-connect-store/.idea/libraries/Node_js_Dependencies_for_strong_cluster_connect_store.xml
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="Node.js Dependencies for strong-cluster-connect-store" type="javaScript">
|
||||||
|
<properties>
|
||||||
|
<sourceFilesUrls>
|
||||||
|
<item url="file://$PROJECT_DIR$/node_modules" />
|
||||||
|
</sourceFilesUrls>
|
||||||
|
</properties>
|
||||||
|
<CLASSES>
|
||||||
|
<root url="file://$PROJECT_DIR$/node_modules" />
|
||||||
|
</CLASSES>
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
5
node_modules/strong-cluster-connect-store/.idea/misc.xml
generated
vendored
Normal file
5
node_modules/strong-cluster-connect-store/.idea/misc.xml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" />
|
||||||
|
</project>
|
||||||
|
|
9
node_modules/strong-cluster-connect-store/.idea/modules.xml
generated
vendored
Normal file
9
node_modules/strong-cluster-connect-store/.idea/modules.xml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/strong-cluster-connect-store.iml" filepath="$PROJECT_DIR$/.idea/strong-cluster-connect-store.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
5
node_modules/strong-cluster-connect-store/.idea/scopes/scope_settings.xml
generated
vendored
Normal file
5
node_modules/strong-cluster-connect-store/.idea/scopes/scope_settings.xml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="DependencyValidationManager">
|
||||||
|
<state>
|
||||||
|
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||||
|
</state>
|
||||||
|
</component>
|
11
node_modules/strong-cluster-connect-store/.idea/strong-cluster-connect-store.iml
generated
vendored
Normal file
11
node_modules/strong-cluster-connect-store/.idea/strong-cluster-connect-store.iml
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="Node.js v0.11.3 Core Modules" level="application" />
|
||||||
|
<orderEntry type="library" name="Node.js Dependencies for strong-cluster-connect-store" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
|
|
7
node_modules/strong-cluster-connect-store/.idea/vcs.xml
generated
vendored
Normal file
7
node_modules/strong-cluster-connect-store/.idea/vcs.xml
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
476
node_modules/strong-cluster-connect-store/.idea/workspace.xml
generated
vendored
Normal file
476
node_modules/strong-cluster-connect-store/.idea/workspace.xml
generated
vendored
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="c9cd60f5-0112-4cd0-aadd-d8bb05bbf943" name="Default" comment="">
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/cluster-store.js" afterPath="$PROJECT_DIR$/test/cluster-store.js" />
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/package.json" afterPath="$PROJECT_DIR$/package.json" />
|
||||||
|
</list>
|
||||||
|
<ignored path="strong-cluster-connect-store.iws" />
|
||||||
|
<ignored path=".idea/workspace.xml" />
|
||||||
|
<option name="TRACKING_ENABLED" value="true" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
|
||||||
|
<component name="CreatePatchCommitExecutor">
|
||||||
|
<option name="PATCH_PATH" value="" />
|
||||||
|
</component>
|
||||||
|
<component name="DaemonCodeAnalyzer">
|
||||||
|
<disable_hints />
|
||||||
|
</component>
|
||||||
|
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
|
||||||
|
<component name="FavoritesManager">
|
||||||
|
<favorites_list name="strong-cluster-connect-store" />
|
||||||
|
</component>
|
||||||
|
<component name="FileEditorManager">
|
||||||
|
<leaf>
|
||||||
|
<file leaf-file-name="cluster-store.js" pinned="false" current="true" current-in-tab="true">
|
||||||
|
<entry file="file://$PROJECT_DIR$/test/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.12448133" vertical-offset="1920" max-vertical-offset="2415">
|
||||||
|
<caret line="132" column="22" selection-start-line="132" selection-start-column="22" selection-end-line="132" selection-end-column="22" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="index.js" pinned="false" current="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/express-session/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="3660">
|
||||||
|
<caret line="167" column="10" selection-start-line="167" selection-start-column="10" selection-end-line="167" selection-end-column="10" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
<file leaf-file-name="cluster-store.js" pinned="false" current="false" current-in-tab="false">
|
||||||
|
<entry file="file://$PROJECT_DIR$/lib/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="945" max-vertical-offset="1815">
|
||||||
|
<caret line="47" column="32" selection-start-line="47" selection-start-column="32" selection-end-line="47" selection-end-column="32" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
</leaf>
|
||||||
|
</component>
|
||||||
|
<component name="FindManager">
|
||||||
|
<FindUsagesManager>
|
||||||
|
<setting name="OPEN_NEW_TAB" value="false" />
|
||||||
|
</FindUsagesManager>
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="GitLogSettings">
|
||||||
|
<option name="myDateState">
|
||||||
|
<MyDateState />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="IdeDocumentHistory">
|
||||||
|
<option name="changedFiles">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/lib/ClusterStore.js" />
|
||||||
|
<option value="$PROJECT_DIR$/test/ClusterStore.js" />
|
||||||
|
<option value="$PROJECT_DIR$/README.md" />
|
||||||
|
<option value="$PROJECT_DIR$/lib/cluster-store.js" />
|
||||||
|
<option value="$PROJECT_DIR$/test/cluster-store.js" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="NodeJsMochaPackageDirSetting">
|
||||||
|
<data>$PROJECT_DIR$/node_modules/mocha</data>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectFrameBounds">
|
||||||
|
<option name="x" value="55" />
|
||||||
|
<option name="y" value="22" />
|
||||||
|
<option name="width" value="1385" />
|
||||||
|
<option name="height" value="878" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||||
|
<OptionsSetting value="true" id="Add" />
|
||||||
|
<OptionsSetting value="true" id="Remove" />
|
||||||
|
<OptionsSetting value="true" id="Checkout" />
|
||||||
|
<OptionsSetting value="true" id="Update" />
|
||||||
|
<OptionsSetting value="true" id="Status" />
|
||||||
|
<OptionsSetting value="true" id="Edit" />
|
||||||
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectReloadState">
|
||||||
|
<option name="STATE" value="0" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectView">
|
||||||
|
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||||
|
<flattenPackages />
|
||||||
|
<showMembers />
|
||||||
|
<showModules />
|
||||||
|
<showLibraryContents />
|
||||||
|
<hideEmptyPackages />
|
||||||
|
<abbreviatePackageNames />
|
||||||
|
<autoscrollToSource />
|
||||||
|
<autoscrollFromSource />
|
||||||
|
<sortByType />
|
||||||
|
</navigator>
|
||||||
|
<panes>
|
||||||
|
<pane id="ProjectPane">
|
||||||
|
<subPane>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="cluster-connect-store" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="cluster-connect-store" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="cluster-connect-store" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="cluster-connect-store" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="cluster-connect-store" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="test" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="cluster-connect-store" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="cluster-connect-store" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="lib" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
|
<pane id="Scope" />
|
||||||
|
</panes>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
|
<property name="options.lastSelected" value="settings.nodejs" />
|
||||||
|
<property name="recentsLimit" value="5" />
|
||||||
|
<property name="restartRequiresConfirmation" value="true" />
|
||||||
|
<property name="GoToClass.includeJavaFiles" value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="RunManager" selected="Mocha.Unit-tests">
|
||||||
|
<configuration default="true" type="DartUnitRunConfigurationType" factoryName="DartUnit">
|
||||||
|
<option name="VMOptions" />
|
||||||
|
<option name="arguments" />
|
||||||
|
<option name="filePath" />
|
||||||
|
<option name="scope" value="ALL" />
|
||||||
|
<option name="testName" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application">
|
||||||
|
<option name="VMOptions" />
|
||||||
|
<option name="arguments" />
|
||||||
|
<option name="filePath" />
|
||||||
|
<option name="name" value="Dart" />
|
||||||
|
<option name="saveOutputToFile" value="false" />
|
||||||
|
<option name="showConsoleOnStdErr" value="false" />
|
||||||
|
<option name="showConsoleOnStdOut" value="false" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="JSTestDriver:ConfigurationType" factoryName="JsTestDriver">
|
||||||
|
<setting name="configLocationType" value="CONFIG_FILE" />
|
||||||
|
<setting name="settingsFile" value="" />
|
||||||
|
<setting name="serverType" value="INTERNAL" />
|
||||||
|
<setting name="preferredDebugBrowser" value="Chrome" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="JavaScriptTestRunnerKarma" factoryName="Karma" config-file="">
|
||||||
|
<envs />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="CucumberJavaScriptRunConfigurationType" factoryName="Cucumber.js">
|
||||||
|
<option name="cucumberJsArguments" />
|
||||||
|
<option name="executablePath" />
|
||||||
|
<option name="filePath" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="mocha-javascript-test-runner" factoryName="Mocha">
|
||||||
|
<node-options />
|
||||||
|
<working-directory>$PROJECT_DIR$</working-directory>
|
||||||
|
<pass-parent-env>true</pass-parent-env>
|
||||||
|
<envs />
|
||||||
|
<ui>BDD</ui>
|
||||||
|
<extra-mocha-options />
|
||||||
|
<test-directory />
|
||||||
|
<recursive>false</recursive>
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="NodeJSConfigurationType" factoryName="Node.js" working-dir="">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="false" name="Unit-tests" type="mocha-javascript-test-runner" factoryName="Mocha">
|
||||||
|
<node-options />
|
||||||
|
<working-directory>$PROJECT_DIR$</working-directory>
|
||||||
|
<pass-parent-env>true</pass-parent-env>
|
||||||
|
<envs />
|
||||||
|
<ui>BDD</ui>
|
||||||
|
<extra-mocha-options />
|
||||||
|
<test-directory>$PROJECT_DIR$/test</test-directory>
|
||||||
|
<recursive>false</recursive>
|
||||||
|
<RunnerSettings RunnerId="MochaDebugRunner" />
|
||||||
|
<RunnerSettings RunnerId="RunnerForMochaJavaScript" />
|
||||||
|
<ConfigurationWrapper RunnerId="MochaDebugRunner" />
|
||||||
|
<ConfigurationWrapper RunnerId="RunnerForMochaJavaScript" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<list size="1">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="Mocha.Unit-tests" />
|
||||||
|
</list>
|
||||||
|
</component>
|
||||||
|
<component name="ShelveChangesManager" show_recycled="false" />
|
||||||
|
<component name="SvnConfiguration">
|
||||||
|
<configuration />
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="c9cd60f5-0112-4cd0-aadd-d8bb05bbf943" name="Default" comment="" />
|
||||||
|
<created>1373452074532</created>
|
||||||
|
<updated>1373452074532</updated>
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="ToolWindowManager">
|
||||||
|
<frame x="55" y="22" width="1385" height="878" extended-state="6" />
|
||||||
|
<editor active="true" />
|
||||||
|
<layout>
|
||||||
|
<window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.24926686" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||||
|
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3986842" sideWeight="0.7503671" order="3" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.2496329" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.32894737" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32894737" sideWeight="0.7503671" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||||
|
</layout>
|
||||||
|
</component>
|
||||||
|
<component name="Vcs.Log.UiProperties">
|
||||||
|
<option name="RECENTLY_FILTERED_USER_GROUPS">
|
||||||
|
<collection />
|
||||||
|
</option>
|
||||||
|
<option name="RECENTLY_FILTERED_BRANCH_GROUPS">
|
||||||
|
<collection />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="VcsContentAnnotationSettings">
|
||||||
|
<option name="myLimit" value="2678400000" />
|
||||||
|
</component>
|
||||||
|
<component name="VcsManagerConfiguration">
|
||||||
|
<option name="myTodoPanelSettings">
|
||||||
|
<TodoPanelSettings />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="XDebuggerManager">
|
||||||
|
<breakpoint-manager>
|
||||||
|
<option name="time" value="1" />
|
||||||
|
</breakpoint-manager>
|
||||||
|
</component>
|
||||||
|
<component name="editorHistoryManager">
|
||||||
|
<entry file="file://$PROJECT_DIR$/test/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="105" max-vertical-offset="2385">
|
||||||
|
<caret line="7" column="34" selection-start-line="7" selection-start-column="34" selection-end-line="7" selection-end-column="34" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/lib/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="721" max-vertical-offset="1605">
|
||||||
|
<caret line="25" column="40" selection-start-line="25" selection-start-column="40" selection-end-line="25" selection-end-column="40" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/test/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="2370">
|
||||||
|
<caret line="11" column="21" selection-start-line="11" selection-start-column="21" selection-end-line="11" selection-end-column="21" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/lib/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="1155" max-vertical-offset="1545">
|
||||||
|
<caret line="77" column="9" selection-start-line="77" selection-start-column="9" selection-end-line="77" selection-end-column="9" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/test/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="1005" max-vertical-offset="2325">
|
||||||
|
<caret line="104" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/test/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="1005" max-vertical-offset="2325">
|
||||||
|
<caret line="104" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/lib/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="360" max-vertical-offset="1170">
|
||||||
|
<caret line="67" column="33" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/test/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="555" max-vertical-offset="2340">
|
||||||
|
<caret line="38" column="24" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/connect/lib/middleware/session/session.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="1020" max-vertical-offset="1830">
|
||||||
|
<caret line="99" column="18" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="105">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/lib/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="80" max-vertical-offset="1095">
|
||||||
|
<caret line="31" column="8" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/test/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="840" max-vertical-offset="1935">
|
||||||
|
<caret line="81" column="4" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/connect/lib/middleware/session/store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="1350">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/connect/lib/middleware/session.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.2260274" vertical-offset="0" max-vertical-offset="5340">
|
||||||
|
<caret line="16" column="28" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/connect/lib/middleware/session/session.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.6352459" vertical-offset="1020" max-vertical-offset="1830">
|
||||||
|
<caret line="99" column="18" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="730">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/README.md">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.062586926" vertical-offset="0" max-vertical-offset="1185">
|
||||||
|
<caret line="3" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/package.json">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="0" max-vertical-offset="750">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/lib/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="945" max-vertical-offset="1815">
|
||||||
|
<caret line="47" column="32" selection-start-line="47" selection-start-column="32" selection-end-line="47" selection-end-column="32" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/express-session/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.0" vertical-offset="2330" max-vertical-offset="3660">
|
||||||
|
<caret line="167" column="10" selection-start-line="167" selection-start-column="10" selection-end-line="167" selection-end-column="10" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/node_modules/body-parser/index.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.062240664" vertical-offset="75" max-vertical-offset="1590">
|
||||||
|
<caret line="7" column="8" selection-start-line="7" selection-start-column="8" selection-end-line="7" selection-end-column="8" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/test/cluster-store.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state vertical-scroll-proportion="0.12448133" vertical-offset="1920" max-vertical-offset="2415">
|
||||||
|
<caret line="132" column="22" selection-start-line="132" selection-start-column="22" selection-end-line="132" selection-end-column="22" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
5
node_modules/strong-cluster-connect-store/.jshintrc
generated
vendored
Normal file
5
node_modules/strong-cluster-connect-store/.jshintrc
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"camelcase": true
|
||||||
|
, "quotmark": "single"
|
||||||
|
, "eqnull": true
|
||||||
|
}
|
18
node_modules/strong-cluster-connect-store/.npmignore
generated
vendored
Normal file
18
node_modules/strong-cluster-connect-store/.npmignore
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
lib-cov
|
||||||
|
*.seed
|
||||||
|
*.log
|
||||||
|
*.csv
|
||||||
|
*.dat
|
||||||
|
*.out
|
||||||
|
*.pid
|
||||||
|
*.gz
|
||||||
|
|
||||||
|
pids
|
||||||
|
logs
|
||||||
|
results
|
||||||
|
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
strong-cluster-connect-store-*.tgz
|
||||||
|
coverage.html
|
||||||
|
node_modules
|
4
node_modules/strong-cluster-connect-store/.travis.yml
generated
vendored
Normal file
4
node_modules/strong-cluster-connect-store/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.10"
|
||||||
|
- "0.11"
|
311
node_modules/strong-cluster-connect-store/LICENSE
generated
vendored
Normal file
311
node_modules/strong-cluster-connect-store/LICENSE
generated
vendored
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
Copyright (c) 2013-2014 StrongLoop, Inc.
|
||||||
|
|
||||||
|
strong-cluster-connect-store uses a 'dual license' model. Users may use strong-cluster-connect-store under
|
||||||
|
the terms of the MIT license, or under the StrongLoop License. The text of both
|
||||||
|
is included below.
|
||||||
|
|
||||||
|
MIT license
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
StrongLoop License
|
||||||
|
|
||||||
|
STRONGLOOP SUBSCRIPTION AGREEMENT
|
||||||
|
PLEASE READ THIS AGREEMENT CAREFULLY BEFORE YOU AGREE TO THESE TERMS. IF YOU
|
||||||
|
ARE ACTING ON BEHALF OF AN ENTITY, THEN YOU REPRESENT THAT YOU HAVE THE
|
||||||
|
AUTHORITY TO ENTER INTO THIS AGREEMENT ON BEHALF OF THAT ENTITY. IF YOU DO NOT
|
||||||
|
AGREE TO THESE TERMS, YOU SHOULD NOT AGREE TO THE TERMS OF THIS AGREEMENT OR
|
||||||
|
INSTALL OR USE THE SOFTWARE.
|
||||||
|
This StrongLoop Subscription Agreement ("Agreement") is made by and between
|
||||||
|
StrongLoop, Inc. ("StrongLoop") with its principal place of business at 107 S.
|
||||||
|
B St, Suite 220, San Mateo, CA 94401 and the person or entity entering into this
|
||||||
|
Agreement ("Customer"). The effective date ("Effective Date") of this Agreement
|
||||||
|
is the date Customer agrees to these terms or installs or uses the Software (as
|
||||||
|
defined below). This Agreement applies to Customer's use of the Software but it
|
||||||
|
shall be superseded by any signed agreement between you and StrongLoop
|
||||||
|
concerning the Software.
|
||||||
|
1. Subscriptions and Licenses.
|
||||||
|
1.1 Subscriptions. StrongLoop offers five different subscription levels to its
|
||||||
|
customers, each as more particularly described on StrongLoop's website located
|
||||||
|
at www.strongloop.com (the "StrongLoop Site"): (1) Free; (2) Developer; (3)
|
||||||
|
Professional; (4) Gold; and (5) Platinum. The actual subscription level
|
||||||
|
applicable to Customer (the "Subscription") will be specified in the purchase
|
||||||
|
order that Customer issues to StrongLoop. This Agreement applies to Customer
|
||||||
|
regardless of the level of the Subscription selected by Customer and whether or
|
||||||
|
not Customer upgrades or downgrades its Subscription. StrongLoop hereby agrees
|
||||||
|
to provide the services as described on the StrongLoop Site for each
|
||||||
|
Subscription level during the term for which Customer has purchased the
|
||||||
|
applicable Subscription, subject to Customer paying the fees applicable to the
|
||||||
|
Subscription level purchased, if any (the "Subscription Fees"). StrongLoop may
|
||||||
|
modify the services to be provided under any Subscription upon notice to
|
||||||
|
Customer.
|
||||||
|
1.2 License Grant. Subject to the terms and conditions of this Agreement,
|
||||||
|
StrongLoop grants to Customer, during the Subscription Term (as defined in
|
||||||
|
Section 7.1 (Term and Termination) of this Agreement, a limited, non-exclusive,
|
||||||
|
non-transferable right and license, to install and use the StrongLoop Suite
|
||||||
|
software (the "Software") and the documentation made available electronically as
|
||||||
|
part of the Software (the "Documentation"), either of which may be modified
|
||||||
|
during the Term (as defined in Section 7.1 below), solely for development,
|
||||||
|
production and commercial purposes so long as Customer is using the Software to
|
||||||
|
run only one process on a given operating system at a time. This Agreement,
|
||||||
|
including but not limited to the license and restrictions contained herein,
|
||||||
|
apply to Customer regardless of whether Customer accesses the Software via
|
||||||
|
download from the StrongLoop Site or through a third-party website or service,
|
||||||
|
even if Customer acquired the Software prior to agreeing to this Agreement.
|
||||||
|
1.3 License Restrictions. Customer shall not itself, or through any parent,
|
||||||
|
subsidiary, affiliate, agent or other third party:
|
||||||
|
1.3.1 sell, lease, license, distribute, sublicense or otherwise transfer
|
||||||
|
in whole or in part, any Software or the Documentation to a third party;
|
||||||
|
or
|
||||||
|
1.3.2 decompile, disassemble, translate, reverse engineer or otherwise
|
||||||
|
attempt to derive source code from the Software, in whole or in part, nor
|
||||||
|
shall Customer use any mechanical, electronic or other method to trace,
|
||||||
|
decompile, disassemble, or identify the source code of the Software or
|
||||||
|
encourage others to do so, except to the limited extent, if any, that
|
||||||
|
applicable law permits such acts notwithstanding any contractual
|
||||||
|
prohibitions, provided, however, before Customer exercises any rights that
|
||||||
|
Customer believes to be entitled to based on mandatory law, Customer shall
|
||||||
|
provide StrongLoop with thirty (30) days prior written notice and provide
|
||||||
|
all reasonably requested information to allow StrongLoop to assess
|
||||||
|
Customer's claim and, at StrongLoop's sole discretion, to provide
|
||||||
|
alternatives that reduce any adverse impact on StrongLoop's intellectual
|
||||||
|
property or other rights; or
|
||||||
|
1.3.3 allow access or permit use of the Software by any users other than
|
||||||
|
Customer's employees or authorized third-party contractors who are
|
||||||
|
providing services to Customer and agree in writing to abide by the terms
|
||||||
|
of this Agreement, provided further that Customer shall be liable for any
|
||||||
|
failure by such employees and third-party contractors to comply with the
|
||||||
|
terms of this Agreement and no usage restrictions, if any, shall be
|
||||||
|
exceeded; or
|
||||||
|
1.3.4 create, develop, license, install, use, or deploy any third party
|
||||||
|
software or services to circumvent or provide access, permissions or
|
||||||
|
rights which violate the license keys embedded within the Software; or
|
||||||
|
1.3.5 modify or create derivative works based upon the Software or
|
||||||
|
Documentation; or disclose the results of any benchmark test of the
|
||||||
|
Software to any third party without StrongLoop's prior written approval;
|
||||||
|
or
|
||||||
|
1.3.6 change any proprietary rights notices which appear in the Software
|
||||||
|
or Documentation; or
|
||||||
|
1.3.7 use the Software as part of a time sharing or service bureau
|
||||||
|
purposes or in any other resale capacity.
|
||||||
|
1.4 Third-Party Software. The Software may include individual certain software
|
||||||
|
that is owned by third parties, including individual open source software
|
||||||
|
components (the "Third-Party Software"), each of which has its own copyright and
|
||||||
|
its own applicable license conditions. Such third-party software is licensed to
|
||||||
|
Customer under the terms of the applicable third-party licenses and/or copyright
|
||||||
|
notices that can be found in the LICENSES file, the Documentation or other
|
||||||
|
materials accompanying the Software, except that Sections 5 (Warranty
|
||||||
|
Disclaimer) and 6 (Limitation of Liability) also govern Customer's use of the
|
||||||
|
third-party software. Customer agrees to comply with the terms and conditions
|
||||||
|
of the relevant third-party software licenses.
|
||||||
|
2. Support Services. StrongLoop has no obligation to provide any support for
|
||||||
|
the Software other than the support services specifically described on the
|
||||||
|
StrongLoop Site for the Subscription level procured by Customer. However,
|
||||||
|
StrongLoop has endeavored to establish a community of users of the Software who
|
||||||
|
have provided their own feedback, hints and advice regarding their experiences
|
||||||
|
in using the Software. You can find that community and user feedback on the
|
||||||
|
StrongLoop Site. The use of any information, content or other materials from,
|
||||||
|
contained in or on the StrongLoop Site are subject to the StrongLoop website
|
||||||
|
terms of use located here http://www.strongloop.com/terms-of-service.
|
||||||
|
3. Confidentiality. For purposes of this Agreement, "Confidential Information"
|
||||||
|
means any and all information or proprietary materials (in every form and media)
|
||||||
|
not generally known in the relevant trade or industry and which has been or is
|
||||||
|
hereafter disclosed or made available by StrongLoop to Customer in connection
|
||||||
|
with the transactions contemplated under this Agreement, including (i) all trade
|
||||||
|
secrets, (ii) existing or contemplated Software, services, designs, technology,
|
||||||
|
processes, technical data, engineering, techniques, methodologies and concepts
|
||||||
|
and any related information, and (iii) information relating to business plans,
|
||||||
|
sales or marketing methods and customer lists or requirements. For a period of
|
||||||
|
five (5) years from the date of disclosure of the applicable Confidential
|
||||||
|
Information, Customer shall (i) hold the Confidential Information in trust and
|
||||||
|
confidence and avoid the disclosure or release thereof to any other person or
|
||||||
|
entity by using the same degree of care as it uses to avoid unauthorized use,
|
||||||
|
disclosure, or dissemination of its own Confidential Information of a similar
|
||||||
|
nature, but not less than reasonable care, and (ii) not use the Confidential
|
||||||
|
Information for any purpose whatsoever except as expressly contemplated under
|
||||||
|
this Agreement; provided that, to the extent the Confidential Information
|
||||||
|
constitutes a trade secret under law, Customer agrees to protect such
|
||||||
|
information for so long as it qualifies as a trade secret under applicable law.
|
||||||
|
Customer shall disclose the Confidential Information only to those of its
|
||||||
|
employees and contractors having a need to know such Confidential Information
|
||||||
|
and shall take all reasonable precautions to ensure that such employees and
|
||||||
|
contractors comply with the provisions of this Section. The obligations of
|
||||||
|
Customer under this Section shall not apply to information that Customer can
|
||||||
|
demonstrate (i) was in its possession at the time of disclosure and without
|
||||||
|
restriction as to confidentiality, (ii) at the time of disclosure is generally
|
||||||
|
available to the public or after disclosure becomes generally available to the
|
||||||
|
public through no breach of agreement or other wrongful act by Customer, (iii)
|
||||||
|
has been received from a third party without restriction on disclosure and
|
||||||
|
without breach of agreement by Customer, or (iv) is independently developed by
|
||||||
|
Customer without regard to the Confidential Information. In addition, Customer
|
||||||
|
may disclose Confidential Information as required to comply with binding orders
|
||||||
|
of governmental entities that have jurisdiction over it; provided that Customer
|
||||||
|
gives StrongLoop reasonable written notice to allow StrongLoop to seek a
|
||||||
|
protective order or other appropriate remedy, discloses only such Confidential
|
||||||
|
Information as is required by the governmental entity, and uses commercially
|
||||||
|
reasonable efforts to obtain confidential treatment for any Confidential
|
||||||
|
Information disclosed. Notwithstanding the above, Customer agrees that
|
||||||
|
StrongLoop, its employees and agents shall be free to use and employ their
|
||||||
|
general skills, know-how, and expertise, and to use, disclose, and employ any
|
||||||
|
generalized ideas, concepts, know-how, methods, techniques or skills gained or
|
||||||
|
learned during the Term or thereafter.
|
||||||
|
4. Ownership. StrongLoop shall retain all intellectual property and proprietary
|
||||||
|
rights in the Software, Documentation, and related works, including but not
|
||||||
|
limited to any derivative work of the foregoing and StrongLoop's licensors shall
|
||||||
|
retain all intellectual property and proprietary rights in any Third-Party
|
||||||
|
Software that may be provided with or as a part of the Software. Customer shall
|
||||||
|
do nothing inconsistent with StrongLoop's or its licensors' title to the
|
||||||
|
Software and the intellectual property rights embodied therein, including, but
|
||||||
|
not limited to, transferring, loaning, selling, assigning, pledging, or
|
||||||
|
otherwise disposing, encumbering, or suffering a lien or encumbrance upon or
|
||||||
|
against any interest in the Software. The Software (including any Third-Party
|
||||||
|
Software) contain copyrighted material, trade secrets and other proprietary
|
||||||
|
material of StrongLoop and/or its licensors.
|
||||||
|
5. Warranty Disclaimer. THE SOFTWARE (INCLUDING ANY THIRD-PARTY SOFTWARE) AND
|
||||||
|
DOCUMENTATION MADE AVAILABLE TO CUSTOMER ARE PROVIDED "AS-IS" AND STRONGLOOP,
|
||||||
|
ON BEHALF OF ITSELF AND ITS LICENSORS, EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY
|
||||||
|
KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, TITLE,
|
||||||
|
PERFORMANCE, AND ACCURACY AND ANY IMPLIED WARRANTIES ARISING FROM STATUTE,
|
||||||
|
COURSE OF DEALING, COURSE OF PERFORMANCE, OR USAGE OF TRADE. STRONGLOOP DOES
|
||||||
|
NOT WARRANT THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR
|
||||||
|
ERROR-FREE, THAT DEFECTS IN THE SOFTWARE WILL BE CORRECTED OR THAT THE SOFTWARE
|
||||||
|
WILL PROVIDE OR ENSURE ANY PARTICULAR RESULTS OR OUTCOME. NO ORAL OR WRITTEN
|
||||||
|
INFORMATION OR ADVICE GIVEN BY STRONGLOOP OR ITS AUTHORIZED REPRESENTATIVES
|
||||||
|
SHALL CREATE A WARRANTY OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY.
|
||||||
|
STRONGLOOP IS NOT OBLIGATED TO PROVIDE CUSTOMER WITH UPGRADES TO THE SOFTWARE,
|
||||||
|
BUT MAY ELECT TO DO SO IN ITS SOLE DISCRETION. SOME JURISDICTIONS DO NOT ALLOW
|
||||||
|
THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO
|
||||||
|
CUSTOMER.WITHOUT LIMITING THE GENERALITY OF THE FOREGOING DISCLAIMER, THE
|
||||||
|
SOFTWARE AND DOCUMENTATION ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE IN
|
||||||
|
THE PLANNING, CONSTRUCTION, MAINTENANCE, CONTROL, OR DIRECT OPERATION OF NUCLEAR
|
||||||
|
FACILITIES, AIRCRAFT NAVIGATION, CONTROL OR COMMUNICATION SYSTEMS, WEAPONS
|
||||||
|
SYSTEMS, OR DIRECT LIFE SUPPORT SYSTEMS.
|
||||||
|
6. Limitation of Liability.
|
||||||
|
6.1 Exclusion of Liability. IN NO EVENT WILL STRONGLOOP OR ITS LICENSORS
|
||||||
|
BE LIABLE UNDER THIS AGREEMENT FOR ANY INDIRECT, RELIANCE, PUNITIVE,
|
||||||
|
CONSEQUENTIAL, SPECIAL, EXEMPLARY, OR INCIDENTAL DAMAGES OF ANY KIND AND
|
||||||
|
HOWEVER CAUSED (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF
|
||||||
|
BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION AND
|
||||||
|
THE LIKE), EVEN IF STRONGLOOP HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES. CUSTOMER BEARS FULL RESPONSIBILITY FOR USE OF THE SOFTWARE AND
|
||||||
|
THE SUBSCRIPTION AND STRONGLOOP DOES NOT GUARANTEE THAT THE USE OF THE
|
||||||
|
SOFTWARE AND SUBSCRIPTION WILL ENSURE THAT CUSTOMER'S NETWORK WILL BE
|
||||||
|
AVAILABLE, SECURE, MONITORED OR PROTECTED AGAINST ANY DOWNTIME, DENIAL OF
|
||||||
|
SERVICE ATTACKS, SECUITY BREACHES, HACKERS AND THE LIKE. IN NO EVENT WILL
|
||||||
|
STRONGLOOP'S CUMULATIVE LIABILITY FOR ANY DAMAGES, LOSSES AND CAUSES OF
|
||||||
|
ACTION (WHETHER IN CONTRACT, TORT, INCLUDING NEGLIGENCE, OR OTHERWISE)
|
||||||
|
ARISING OUT OF OR RELATED TO THIS AGREEMENT EXCEED THE GREATER OF ONE
|
||||||
|
HUNDRED DOLLARS (US$100) OR THE TOTAL SUBSCRIPTION FEES PAID BY CUSTOMER
|
||||||
|
TO STRONGLOOP IN THE TWELVE (12) MONTHS PRECEDING THE DATE THE CLAIM
|
||||||
|
ARISES.
|
||||||
|
6.2 Limitation of Damages. IN NO EVENT WILL STRONGLOOP'S LICENSORS HAVE
|
||||||
|
ANY LIABILITY FOR ANY CLAIM ARISING IN CONNECTION WITH THIS AGREEMENT.
|
||||||
|
THE PROVISIONS OF THIS SECTION 6 ALLOCATE RISKS UNDER THIS AGREEMENT
|
||||||
|
BETWEEN CUSTOMER, STRONGLOOP AND STRONGLOOP'S SUPPLIERS. THE FOREGOING
|
||||||
|
LIMITATIONS, EXCLUSIONS AND DISCLAIMERS APPLY TO THE MAXIMUM EXTENT
|
||||||
|
PERMITTED BY APPLICABLE LAW, EVEN IF ANY REMEDY FAILS IN ITS ESSENTIAL
|
||||||
|
PURPOSE.
|
||||||
|
6.3 Failure of Essential Purpose. THE PARTIES AGREE THAT THESE
|
||||||
|
LIMITATIONS SHALL APPLY EVEN IF THIS AGREEMENT OR ANY LIMITED REMEDY
|
||||||
|
SPECIFIED HEREIN IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE.
|
||||||
|
6.4 Allocation of Risk. The sections on limitation of liability and
|
||||||
|
disclaimer of warranties allocate the risks in the Agreement between the
|
||||||
|
parties. This allocation is an essential element of the basis of the
|
||||||
|
bargain between the parties.
|
||||||
|
7. Term and Termination.
|
||||||
|
7.1 This Agreement shall commence on the Effective Date and continue for so long
|
||||||
|
as Customer has a valid Subscription and is current on the payment of any
|
||||||
|
Subscription Fees required to be paid for that Subscription (the "Subscription
|
||||||
|
Term"). Either party may terminate this Agreement immediately upon written
|
||||||
|
notice to the other party, and the Subscription and licenses granted hereunder
|
||||||
|
automatically terminate upon the termination of this Agreement. This Agreement
|
||||||
|
will terminate immediately without notice from StrongLoop if Customer fails to
|
||||||
|
comply with or otherwise breaches any provision of this Agreement.
|
||||||
|
7.2 All Sections other than Section 1.1 (Subscriptions) and 1.2 (Licenses) shall
|
||||||
|
survive the expiration or termination of this Agreement.
|
||||||
|
8. Subscription Fees and Payments. StrongLoop, Customer agrees to pay
|
||||||
|
StrongLoop the Subscription Fees as described on the StrongLoop Site for the
|
||||||
|
Subscription purchased unless a different amount has been agreed to in a
|
||||||
|
separate agreement between Customer and StrongLoop. In addition, Customer shall
|
||||||
|
pay all sales, use, value added, withholding, excise taxes and other tax, duty,
|
||||||
|
custom and similar fees levied upon the delivery or use of the Software and the
|
||||||
|
Subscriptions described in this Agreement. Fees shall be invoiced in full upon
|
||||||
|
StrongLoop's acceptance of Customer's purchase order for the Subscription. All
|
||||||
|
invoices shall be paid in US dollars and are due upon receipt and shall be paid
|
||||||
|
within thirty (30) days. Payments shall be made without right of set-off or
|
||||||
|
chargeback. If Customer does not pay the invoices when due, StrongLoop may
|
||||||
|
charge interest at one percent (1%) per month or the highest rate permitted by
|
||||||
|
law, whichever is lower, on the unpaid balance from the original due date. If
|
||||||
|
Customer fails to pay fees in accordance with this Section, StrongLoop may
|
||||||
|
suspend fulfilling its obligations under this Agreement (including but not
|
||||||
|
limited to suspending the services under the Subscription) until payment is
|
||||||
|
received by StrongLoop. If any applicable law requires Customer to withhold
|
||||||
|
amounts from any payments to StrongLoop under this Agreement, (a) Customer shall
|
||||||
|
effect such withholding, remit such amounts to the appropriate taxing
|
||||||
|
authorities and promptly furnish StrongLoop with tax receipts evidencing the
|
||||||
|
payments of such amounts and (b) the sum payable by Customer upon which the
|
||||||
|
deduction or withholding is based shall be increased to the extent necessary to
|
||||||
|
ensure that, after such deduction or withholding, StrongLoop receives and
|
||||||
|
retains, free from liability for such deduction or withholding, a net amount
|
||||||
|
equal to the amount StrongLoop would have received and retained absent the
|
||||||
|
required deduction or withholding.
|
||||||
|
9. General.
|
||||||
|
9.1 Compliance with Laws. Customer shall abide by all local, state, federal and
|
||||||
|
international laws, rules, regulations and orders applying to Customer's use of
|
||||||
|
the Software, including, without limitation, the laws and regulations of the
|
||||||
|
United States that may restrict the export and re-export of certain commodities
|
||||||
|
and technical data of United States origin, including the Software. Customer
|
||||||
|
agrees that it will not export or re-export the Software without the appropriate
|
||||||
|
United States or foreign government licenses.
|
||||||
|
9.2 Entire Agreement. This Agreement constitutes the entire agreement between
|
||||||
|
the parties concerning the subject matter hereof. This Agreement supersedes all
|
||||||
|
prior or contemporaneous discussions, proposals and agreements between the
|
||||||
|
parties relating to the subject matter hereof. No amendment, modification or
|
||||||
|
waiver of any provision of this Agreement shall be effective unless in writing
|
||||||
|
and signed by both parties. Any additional or different terms on any purchase
|
||||||
|
orders issued by Customer to StrongLoop shall not be binding on either party,
|
||||||
|
are hereby rejected by StrongLoop and void.
|
||||||
|
9.3 Severability. If any provision of this Agreement is held to be invalid or
|
||||||
|
unenforceable, the remaining portions shall remain in full force and effect and
|
||||||
|
such provision shall be enforced to the maximum extent possible so as to effect
|
||||||
|
the intent of the parties and shall be reformed to the extent necessary to make
|
||||||
|
such provision valid and enforceable.
|
||||||
|
9.4 Waiver. No waiver of rights by either party may be implied from any actions
|
||||||
|
or failures to enforce rights under this Agreement.
|
||||||
|
9.5 Force Majeure. Neither party shall be liable to the other for any delay or
|
||||||
|
failure to perform due to causes beyond its reasonable control (excluding
|
||||||
|
payment of monies due).
|
||||||
|
9.6 No Third Party Beneficiaries. Unless otherwise specifically stated, the
|
||||||
|
terms of this Agreement are intended to be and are solely for the benefit of
|
||||||
|
StrongLoop and Customer and do not create any right in favor of any third party.
|
||||||
|
9.7 Governing Law and Jurisdiction. This Agreement shall be governed by the
|
||||||
|
laws of the State of California, without reference to the principles of
|
||||||
|
conflicts of law. The provisions of the Uniform Computerized Information
|
||||||
|
Transaction Act and United Nations Convention on Contracts for the International
|
||||||
|
Sale of Goods shall not apply to this Agreement. The parties shall attempt to
|
||||||
|
resolve any dispute related to this Agreement informally, initially through
|
||||||
|
their respective management, and then by non-binding mediation in San Francisco
|
||||||
|
County, California. Any litigation related to this Agreement shall be brought
|
||||||
|
in the state or federal courts located in San Francisco County, California, and
|
||||||
|
only in those courts and each party irrevocably waives any objections to such
|
||||||
|
venue.
|
||||||
|
9.8 Notices. All notices must be in writing and shall be effective three (3)
|
||||||
|
days after the date sent to the other party's headquarters, Attention Chief
|
||||||
|
Financial Officer.
|
28
node_modules/strong-cluster-connect-store/README.md
generated
vendored
Normal file
28
node_modules/strong-cluster-connect-store/README.md
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Connect Session Store for Cluster
|
||||||
|
|
||||||
|
[](https://travis-ci.org/strongloop/strong-cluster-connect-store)
|
||||||
|
[](http://badge.fury.io/js/strong-cluster-connect-store)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Strong-cluster-connect-store is an implementation of connect session store
|
||||||
|
using node's native cluster messaging. It provides an easy way for using
|
||||||
|
sessions in connect/express based applications running in a node cluster.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
- Supports both connect and express.
|
||||||
|
- No dependencies on external services.
|
||||||
|
- Module is shipped without connect, it will use *your* version of connect
|
||||||
|
or express.
|
||||||
|
- Covered by unit-tests.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
For complete documentation, see [StrongLoop Documentation | Strong Cluster Connect Store](http://docs.strongloop.com/display/DOC/Strong+Cluster+Connect+Store).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install strong-cluster-connect-store
|
||||||
|
```
|
7
node_modules/strong-cluster-connect-store/docs.json
generated
vendored
Normal file
7
node_modules/strong-cluster-connect-store/docs.json
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{"title": "Strong Cluster Connect Store API", "depth": 2},
|
||||||
|
"lib/cluster-store.js"
|
||||||
|
],
|
||||||
|
"codeSectionDepth": 3
|
||||||
|
}
|
1
node_modules/strong-cluster-connect-store/index.js
generated
vendored
Normal file
1
node_modules/strong-cluster-connect-store/index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./lib/cluster-store.js');
|
115
node_modules/strong-cluster-connect-store/lib/cluster-store.js
generated
vendored
Normal file
115
node_modules/strong-cluster-connect-store/lib/cluster-store.js
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
var inherits = require('util').inherits;
|
||||||
|
var cluster = require('cluster');
|
||||||
|
var NativeStore = require('strong-store-cluster');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Documentation marker for explicit setup of the shared-state server
|
||||||
|
* in the master process. The initialization happens when this module
|
||||||
|
* is required, thus calling this function is entirely optional.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function setup() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the `ClusterStore` constructor that can be called to create
|
||||||
|
* a session Store to use with
|
||||||
|
* the [express-session](https://www.npmjs.org/package/express-session)
|
||||||
|
* middleware.
|
||||||
|
*
|
||||||
|
* #### Example
|
||||||
|
* ```
|
||||||
|
// express v3.x
|
||||||
|
var session = express.session;
|
||||||
|
var SessionStore = require('strong-cluster-connect-store')(session);
|
||||||
|
|
||||||
|
// express v4.x
|
||||||
|
var session = require('express-session');
|
||||||
|
var SessionStore = require('strong-cluster-connect-store')(session);
|
||||||
|
|
||||||
|
// express v3.x (backwards compatibility)
|
||||||
|
var SessionStore = require('strong-cluster-connect-store')(express);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {Object} connectOrSession express session or connect/express itself
|
||||||
|
* @return {function} The ClusterStore constructor.
|
||||||
|
*/
|
||||||
|
module.exports = function(connectOrSession) {
|
||||||
|
|
||||||
|
var session = connectOrSession.session || connectOrSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect's Store.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var Store = session.Store;
|
||||||
|
|
||||||
|
var COLLECTION_NAME = 'strong-cluster-connect-session-store';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a ClusterStore object with the given `options`.
|
||||||
|
* This is an internal constructor called by express-session middleware,
|
||||||
|
* you should not need to call it directly.
|
||||||
|
* @param {Object} options Options for the ClusterStore object.
|
||||||
|
* @constructor
|
||||||
|
* @extends {session.Store}
|
||||||
|
*/
|
||||||
|
function ClusterStore(options) {
|
||||||
|
Store.call(this, options);
|
||||||
|
this._collection = NativeStore.collection(COLLECTION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(ClusterStore, Store);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a session by an id and receive the session in the callback.
|
||||||
|
* @param {String} sid A string id for the session.
|
||||||
|
* @end
|
||||||
|
* @callback {Function} fn
|
||||||
|
* @param {Error} err if present, indicates an error condition.
|
||||||
|
* @param value The data stored in the collection, could be any type.
|
||||||
|
* @end
|
||||||
|
*/
|
||||||
|
ClusterStore.prototype.get = function(sid, fn) {
|
||||||
|
this._collection.get(sid, fn);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit the given `session` object associated with the given `sid` to the
|
||||||
|
* session store.
|
||||||
|
* @param {String} sid A string id identifying the session.
|
||||||
|
* @param {Object} session The session object.
|
||||||
|
* @end
|
||||||
|
* @callback {Function} fn
|
||||||
|
* @param {Error} err If defined, indicates an error occured.
|
||||||
|
* @end
|
||||||
|
*/
|
||||||
|
ClusterStore.prototype.set = function(sid, session, fn) {
|
||||||
|
this._collection.set(sid, session, fn);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the session associated with the given `sid`.
|
||||||
|
* @param {String} sid A String with the id of the session.
|
||||||
|
* @end
|
||||||
|
* @callback {Function} fn
|
||||||
|
* @param {Error} err If defined, indicates an error occured.
|
||||||
|
* @end
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ClusterStore.prototype.destroy = function(sid, fn){
|
||||||
|
this._collection.del(sid, fn);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `setup()` (see above).
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ClusterStore.setup = setup;
|
||||||
|
|
||||||
|
return ClusterStore;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.setup = setup;
|
55
node_modules/strong-cluster-connect-store/package.json
generated
vendored
Normal file
55
node_modules/strong-cluster-connect-store/package.json
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"name": "strong-cluster-connect-store",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Implementation of connect session store using node's native cluster messaging",
|
||||||
|
"license": {
|
||||||
|
"name": "Dual MIT/StrongLoop",
|
||||||
|
"url": "https://github.com/strongloop/strong-cluster-connect-store/blob/master/LICENSE"
|
||||||
|
},
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha --reporter spec",
|
||||||
|
"lint": "./node_modules/.bin/jshint *.js test lib"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/strongloop/strong-cluster-connect-store.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"connect",
|
||||||
|
"express",
|
||||||
|
"cluster",
|
||||||
|
"session",
|
||||||
|
"store"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "Miroslav Bajtos",
|
||||||
|
"email": "miroslav@strongloop.com"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"strong-store-cluster": "~0.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha": "~1.9.0",
|
||||||
|
"jshint": "~2.0.1",
|
||||||
|
"chai": "~1.7.2",
|
||||||
|
"cookie-parser": "^1.0.1",
|
||||||
|
"strong-store-cluster": "latest",
|
||||||
|
"request": "~2.22.0",
|
||||||
|
"async": "~0.2.9",
|
||||||
|
"express-session": "^1.0.2",
|
||||||
|
"express": "^4.1.1",
|
||||||
|
"body-parser": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
},
|
||||||
|
"readme": "# Connect Session Store for Cluster\n\n[](https://travis-ci.org/strongloop/strong-cluster-connect-store)\n[](http://badge.fury.io/js/strong-cluster-connect-store)\n\n## Overview\n\nStrong-cluster-connect-store is an implementation of connect session store\nusing node's native cluster messaging. It provides an easy way for using\nsessions in connect/express based applications running in a node cluster.\n\nFeatures:\n\n- Supports both connect and express.\n- No dependencies on external services.\n- Module is shipped without connect, it will use *your* version of connect\n or express.\n- Covered by unit-tests.\n \n## Documentation\n\nFor complete documentation, see [StrongLoop Documentation | Strong Cluster Connect Store](http://docs.strongloop.com/display/DOC/Strong+Cluster+Connect+Store).\n\n## Installation\n\n```sh\n$ npm install strong-cluster-connect-store\n```\n",
|
||||||
|
"readmeFilename": "README.md",
|
||||||
|
"_id": "strong-cluster-connect-store@1.0.0",
|
||||||
|
"dist": {
|
||||||
|
"shasum": "c1ee462f23b1dee4d6381fe986d83a227c32c62e"
|
||||||
|
},
|
||||||
|
"_from": "strong-cluster-connect-store@",
|
||||||
|
"_resolved": "https://registry.npmjs.org/strong-cluster-connect-store/-/strong-cluster-connect-store-1.0.0.tgz"
|
||||||
|
}
|
155
node_modules/strong-cluster-connect-store/test/cluster-store.js
generated
vendored
Normal file
155
node_modules/strong-cluster-connect-store/test/cluster-store.js
generated
vendored
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
var cluster = require('cluster');
|
||||||
|
var http = require('http');
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var express = require('express');
|
||||||
|
var bodyParser = require('body-parser');
|
||||||
|
var cookieParser = require('cookie-parser');
|
||||||
|
var session = require('express-session');
|
||||||
|
var request = require('request');
|
||||||
|
var async = require('async');
|
||||||
|
var ClusterStore = require('..')(session);
|
||||||
|
|
||||||
|
var workerUrl;
|
||||||
|
|
||||||
|
// verify we can call setup without connect in master and workers
|
||||||
|
require('..').setup();
|
||||||
|
|
||||||
|
if (cluster.isWorker) {
|
||||||
|
startConnectServer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('clustered connect server', function() {
|
||||||
|
before(setupWorkers);
|
||||||
|
after(stopWorkers);
|
||||||
|
|
||||||
|
var KEY = 'a-key';
|
||||||
|
var PAYLOAD = 'a-value';
|
||||||
|
|
||||||
|
// NOTE We assume that the cluster does a perfect round-robin
|
||||||
|
// distribution of requests among the workers
|
||||||
|
|
||||||
|
it('shares sessions between workers', function(done) {
|
||||||
|
async.series(
|
||||||
|
[
|
||||||
|
save,
|
||||||
|
load
|
||||||
|
],
|
||||||
|
function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
expect(results.pop().value).to.equal(PAYLOAD);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('destroys a session shared between workers', function(done) {
|
||||||
|
async.series(
|
||||||
|
[
|
||||||
|
save,
|
||||||
|
destroy,
|
||||||
|
load
|
||||||
|
],
|
||||||
|
function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
expect(results.pop().value).to.equal(undefined);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function save(next) {
|
||||||
|
sendCommand({ cmd: 'set', key: KEY, value: PAYLOAD }, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy(next) {
|
||||||
|
sendCommand({ cmd: 'del', key: KEY }, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
function load(next) {
|
||||||
|
sendCommand({ cmd: 'get', key: KEY }, next);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function sendCommand(command, cb) {
|
||||||
|
request(
|
||||||
|
{
|
||||||
|
url: workerUrl,
|
||||||
|
method: 'POST',
|
||||||
|
json: command
|
||||||
|
},
|
||||||
|
function(err, res, body) {
|
||||||
|
if (err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
cb(null, body);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var WORKER_COUNT = 2;
|
||||||
|
|
||||||
|
function getNumberOfWorkers() {
|
||||||
|
return Object.keys(cluster.workers).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupWorkers(done) {
|
||||||
|
if (getNumberOfWorkers() > 0) {
|
||||||
|
var msg = 'Cannot setup workers: there are already other workers running.';
|
||||||
|
return done(new Error(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster.setupMaster({ exec: __filename });
|
||||||
|
ClusterStore.setup();
|
||||||
|
|
||||||
|
var workersListening = 0;
|
||||||
|
cluster.on('listening', function(w, addr) {
|
||||||
|
if (!workerUrl) workerUrl = 'http://localhost:' + addr.port;
|
||||||
|
|
||||||
|
workersListening++;
|
||||||
|
if (workersListening == WORKER_COUNT) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i = 0; i < WORKER_COUNT; i++) {
|
||||||
|
cluster.fork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopWorkers(done) {
|
||||||
|
cluster.disconnect(done);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startConnectServer() {
|
||||||
|
var PORT = 0; // Let the OS pick any available port
|
||||||
|
var app = express()
|
||||||
|
.use(cookieParser())
|
||||||
|
.use(session({ store: new ClusterStore(), secret: 'a-secret', key: 'sid' }))
|
||||||
|
.use(bodyParser.json())
|
||||||
|
.use(requestHandler);
|
||||||
|
|
||||||
|
var server = http.createServer(app).listen(PORT);
|
||||||
|
|
||||||
|
function requestHandler(req, res) {
|
||||||
|
var result = {};
|
||||||
|
switch (req.body.cmd) {
|
||||||
|
case 'set':
|
||||||
|
req.session[req.body.key] = req.body.value;
|
||||||
|
break;
|
||||||
|
case 'get':
|
||||||
|
result.value = req.session[req.body.key];
|
||||||
|
break;
|
||||||
|
case 'del':
|
||||||
|
req.session.destroy();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setHeader('Content-Type', 'text/json');
|
||||||
|
res.end(JSON.stringify(result));
|
||||||
|
}
|
||||||
|
}
|
2
node_modules/strong-store-cluster/BUG.txt
generated
vendored
Normal file
2
node_modules/strong-store-cluster/BUG.txt
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
A new Client() is created for each 'online' worker... but clients are never
|
||||||
|
released.
|
19
node_modules/strong-store-cluster/LICENSE
generated
vendored
Normal file
19
node_modules/strong-store-cluster/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2013 Strongloop, Inc.
|
||||||
|
|
||||||
|
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.
|
19
node_modules/strong-store-cluster/Makefile
generated
vendored
Normal file
19
node_modules/strong-store-cluster/Makefile
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Makefile
|
||||||
|
|
||||||
|
-include local.mk
|
||||||
|
|
||||||
|
.PHONY: test default
|
||||||
|
|
||||||
|
default: test
|
||||||
|
|
||||||
|
test:
|
||||||
|
@npm test
|
||||||
|
|
||||||
|
jenkins-build: jenkins-install jenkins-test
|
||||||
|
|
||||||
|
jenkins-install:
|
||||||
|
npm install
|
||||||
|
|
||||||
|
jenkins-test:
|
||||||
|
./node_modules/.bin/mocha --timeout 5000 --slow 1000 --ui tdd --reporter xunit > xunit.xml
|
||||||
|
|
189
node_modules/strong-store-cluster/README.md
generated
vendored
Normal file
189
node_modules/strong-store-cluster/README.md
generated
vendored
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
# Strong Store Cluster
|
||||||
|
|
||||||
|
Strong Store for Cluster provides a key/value collection that can be accesses by
|
||||||
|
all processes in a node cluster.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// get the collection and give it a name
|
||||||
|
var collection = require('strong-store-cluster').collection('test');
|
||||||
|
|
||||||
|
// don't let keys expire, ever - the number represents seconds
|
||||||
|
collection.configure({ expireKeys: 0 });
|
||||||
|
|
||||||
|
collection.set('ThisIsMyKey', { a: 0, b: 'Hiya', c: { d: 99}}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error('There was an error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.get('ThisIsMyKey', function(err, obj) {
|
||||||
|
if (err) {
|
||||||
|
console.error('There was an error in collection.get.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('The object: ',obj);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## API documentation
|
||||||
|
|
||||||
|
### store.collection(name)
|
||||||
|
|
||||||
|
Returns a Collection object which lets you share data between node processes.
|
||||||
|
|
||||||
|
### Class: Collection
|
||||||
|
|
||||||
|
A `Collection` instance provides access to a shared key-value store
|
||||||
|
shared by multiple node instances.
|
||||||
|
|
||||||
|
How collections are named and stored is determined by the storage backend. The
|
||||||
|
`strong-store-cluster` implementation stores collections in the master process
|
||||||
|
(if you're using cluster), and accepts any arbitrary string as a collection
|
||||||
|
name.
|
||||||
|
|
||||||
|
A `Collection` object is also an `EventEmitter`.
|
||||||
|
|
||||||
|
|
||||||
|
#### collection.configure([options])
|
||||||
|
|
||||||
|
* `options` (`Object`) contains configurations options to be changed
|
||||||
|
* `expireKeys` (`Number`) seconds after which keys in this
|
||||||
|
collection are to be expired.
|
||||||
|
|
||||||
|
Set configuration options for the collection.
|
||||||
|
|
||||||
|
Currently only one configurable option is supported: `expireKeys`. When set
|
||||||
|
to a nonzero value, keys will automatically expire after they've not been
|
||||||
|
read or updated for some time. The timeout is specified in seconds. There's no
|
||||||
|
guarantee that the key will be discared after exactly that number of seconds
|
||||||
|
has passed. However keys will never be automatically deleted _sooner_ than what
|
||||||
|
the `expireKeys` setting allows.
|
||||||
|
|
||||||
|
It is perfectly legal to call the `configure` method from multiple node
|
||||||
|
processes (e.g. both in a worker and in the master process). However you
|
||||||
|
should be careful to set the _same_ option values every time, otherwise the
|
||||||
|
effect is undefined.
|
||||||
|
|
||||||
|
|
||||||
|
#### collection.get(key, callback)
|
||||||
|
|
||||||
|
* `key` (`String`) key to retrieve
|
||||||
|
* `callback` (`Function`) called when the value has been retrieved
|
||||||
|
|
||||||
|
Read the value associated with a particular key. The callback is called with
|
||||||
|
two arguments, `(err, value)`. When the key wasn't found in the collection, it
|
||||||
|
is automatically created and it's `value` is set to `undefined`.
|
||||||
|
|
||||||
|
|
||||||
|
#### collection.set(key, [value], [callback])
|
||||||
|
|
||||||
|
* `key` (`String`) key to set or update
|
||||||
|
* `value` (`object`) value to associate with the key
|
||||||
|
* `callback` (`Function`) called when the value has been retrieved
|
||||||
|
|
||||||
|
Set the value associated with `key`. The `value` must be either undefined or
|
||||||
|
a value that can be serialized with JSON.stringify.
|
||||||
|
|
||||||
|
When the `value` parameter is omitted or set to `undefined`, the key is
|
||||||
|
deleted, so effectively it's the same as calling `collection.del(key)`.
|
||||||
|
|
||||||
|
The `callback` function receives only one argument, `err`. When the
|
||||||
|
callback is omitted, the master process does not send a confirmation
|
||||||
|
after updating the key, and any errors are silently ignored.
|
||||||
|
|
||||||
|
|
||||||
|
#### collection.del(key, [callback])
|
||||||
|
|
||||||
|
* `key` (`String`) key to delete
|
||||||
|
* `callback` (`Function`) called when the value has been retrieved
|
||||||
|
|
||||||
|
Delete a key from the collection.
|
||||||
|
|
||||||
|
This operation is the equivalent of setting the key to `undefined`.
|
||||||
|
|
||||||
|
The `callback` function receives only one argument, `err`. When the
|
||||||
|
callback is omitted, the master process does not send a confirmation
|
||||||
|
after deleting the key, and any errors are silently ignored.
|
||||||
|
|
||||||
|
|
||||||
|
#### collection.acquire(key, callback)
|
||||||
|
|
||||||
|
* `key` (`String`) key to delete
|
||||||
|
* `callback` (`Function`) called when the key has been locked
|
||||||
|
|
||||||
|
Lock a key for exclusive read and write access.
|
||||||
|
|
||||||
|
The `acquire` methods waits until it can grab an exclusive lock on the
|
||||||
|
specified key. When the lock is acquired, no other process can read, write or
|
||||||
|
delete this particular key. When the lock is no longer needed, it should be
|
||||||
|
relinquished with `keylock.release()`.
|
||||||
|
|
||||||
|
Three parameters are passed to the `callback` function:
|
||||||
|
`(err, keylock, value)`. The `keylock` argument receives a `KeyLock` class
|
||||||
|
instance, which lets you read and manipulate the key's value as well as
|
||||||
|
eventually release the lock. The `value` argument is set to the initial value
|
||||||
|
associated with the key.
|
||||||
|
|
||||||
|
|
||||||
|
#### Event: 'error'
|
||||||
|
|
||||||
|
* `err` (`Error`)
|
||||||
|
|
||||||
|
The error event is emitted whenever an unrecoverable error is encountered.
|
||||||
|
|
||||||
|
### Class: KeyLock
|
||||||
|
|
||||||
|
A `KeyLock` instance represents a key that has been locked. The `KeyLock`
|
||||||
|
class implements methods that lets you manipulate the key and release
|
||||||
|
the lock.
|
||||||
|
|
||||||
|
|
||||||
|
#### keylock.get()
|
||||||
|
|
||||||
|
* Returns: (`Object`) value that's currently associated with the key
|
||||||
|
|
||||||
|
This function returns the value that's currently associated with the locked
|
||||||
|
key.
|
||||||
|
|
||||||
|
Initially this is the same as the `value` argument that was passed to the
|
||||||
|
`collection.acquire()` callback, but it does immediately reflect changes that
|
||||||
|
are made with `keylock.set()` and `keylock.del()`.
|
||||||
|
|
||||||
|
|
||||||
|
#### keylock.set([value])
|
||||||
|
|
||||||
|
Updates the value associated with a locked key.
|
||||||
|
|
||||||
|
The change isn't pushed back to the master process immediately; the change
|
||||||
|
is committed when the lock is released again. The change however is reflected
|
||||||
|
immediately in the return value from `keylock.get()`.
|
||||||
|
|
||||||
|
After the lock has been released, the key can no longer be updated through the
|
||||||
|
`KeyLock` instance. Any attempt to do so will make it throw.
|
||||||
|
|
||||||
|
Setting the value to `undefined` marks the key for deletion, e.g. it's
|
||||||
|
equivalent to `keylock.del()`.
|
||||||
|
|
||||||
|
|
||||||
|
#### keylock.del()
|
||||||
|
|
||||||
|
Mark a locked key for deletion. See `keylock.set()`.
|
||||||
|
|
||||||
|
|
||||||
|
#### keylock.release([callback])
|
||||||
|
|
||||||
|
Release the lock that protects a key. If the key was updated with
|
||||||
|
`keylock.set()` or `keylock.del()`, these changes are committed.
|
||||||
|
|
||||||
|
When a lock has been released, it is no longer possible to manipulate the
|
||||||
|
key using `KeyLock` methods. Releasing the lock twice isn't allowed either.
|
||||||
|
The `get()` method will still work but it won't reflect any value changes
|
||||||
|
that were made after releasing.
|
||||||
|
|
||||||
|
The `callback` function receives only one argument, `err`. When the
|
||||||
|
callback is omitted, the master process does not send a confirmation
|
||||||
|
after releasing the key, and any errors are silently ignored.
|
6
node_modules/strong-store-cluster/docs.json
generated
vendored
Normal file
6
node_modules/strong-store-cluster/docs.json
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"title": "Strong Store for Cluster",
|
||||||
|
"content": [
|
||||||
|
"README.md"
|
||||||
|
]
|
||||||
|
}
|
18
node_modules/strong-store-cluster/index.js
generated
vendored
Normal file
18
node_modules/strong-store-cluster/index.js
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
var assert = require('assert');
|
||||||
|
var cluster = require('cluster');
|
||||||
|
var VERSION = require('./package.json').version;
|
||||||
|
|
||||||
|
if(cluster._strongStoreCluster) {
|
||||||
|
assert(
|
||||||
|
cluster._strongStoreCluster.VERSION === VERSION,
|
||||||
|
'Multiple versions of strong-strore-cluster are being initialized.\n' +
|
||||||
|
'This version ' + VERSION + ' is incompatible with already initialized\n' +
|
||||||
|
'version ' + cluster._strongStoreCluster.VERSION + '.\n'
|
||||||
|
);
|
||||||
|
module.exports = cluster._strongStoreCluster;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = require('./lib/lib.js');
|
||||||
|
module.exports.VERSION = VERSION;
|
||||||
|
cluster._strongStoreCluster = module.exports;
|
22
node_modules/strong-store-cluster/lib/collection.js
generated
vendored
Normal file
22
node_modules/strong-store-cluster/lib/collection.js
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
module.exports = collection;
|
||||||
|
|
||||||
|
|
||||||
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||||
|
|
||||||
|
var cluster = require('cluster');
|
||||||
|
|
||||||
|
if (cluster.isMaster)
|
||||||
|
var Collection = require('./master/Collection.js');
|
||||||
|
else
|
||||||
|
var Collection = require('./worker/Collection.js');
|
||||||
|
|
||||||
|
|
||||||
|
var collections = {};
|
||||||
|
|
||||||
|
function collection(name) {
|
||||||
|
if (!hasOwnProperty.call(collections, name))
|
||||||
|
return collections[name] = new Collection(name);
|
||||||
|
else
|
||||||
|
return collections[name];
|
||||||
|
}
|
8
node_modules/strong-store-cluster/lib/lib.js
generated
vendored
Normal file
8
node_modules/strong-store-cluster/lib/lib.js
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
var cluster = require('cluster'),
|
||||||
|
collection = require('./collection.js');
|
||||||
|
|
||||||
|
exports.collection = collection;
|
||||||
|
|
||||||
|
if (cluster.isMaster)
|
||||||
|
require('./master/setup.js');
|
107
node_modules/strong-store-cluster/lib/master/Client.js
generated
vendored
Normal file
107
node_modules/strong-store-cluster/lib/master/Client.js
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
|
||||||
|
module.exports = Client;
|
||||||
|
|
||||||
|
|
||||||
|
var collection = require('../collection.js');
|
||||||
|
|
||||||
|
|
||||||
|
function Client(worker) {
|
||||||
|
this._worker = worker;
|
||||||
|
this._id = worker.id;
|
||||||
|
this._locks = {};
|
||||||
|
|
||||||
|
this._onMessage = this.onMessage.bind(this);
|
||||||
|
|
||||||
|
worker.on('message', this._onMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
Client.prototype.onMessage = function(msg) {
|
||||||
|
if (msg.type === 'DSM_REQUEST')
|
||||||
|
this[msg.method](msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
Client.prototype.get = function(msg) {
|
||||||
|
var self = this,
|
||||||
|
entry = collection(msg.collection)._entry(msg.key);
|
||||||
|
|
||||||
|
entry.get(this._id, function(err, json) {
|
||||||
|
if (err) self._sendError(msg, err);
|
||||||
|
else self._sendReply(msg, { json: json });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Client.prototype.set = function(msg) {
|
||||||
|
var self = this,
|
||||||
|
entry = collection(msg.collection)._entry(msg.key);
|
||||||
|
|
||||||
|
entry.set(msg.json, this._id, function(err) {
|
||||||
|
if (err) self._sendError(msg, err);
|
||||||
|
else self._sendReply(msg);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Client.prototype.acquire = function(msg) {
|
||||||
|
var self = this,
|
||||||
|
entry = collection(msg.collection)._entry(msg.key);
|
||||||
|
|
||||||
|
entry.acquire(this._id, function(err, json) {
|
||||||
|
if (err) self._sendError(msg, err);
|
||||||
|
else self._sendReply(msg, { json: json });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Client.prototype.release = function(msg) {
|
||||||
|
var self = this,
|
||||||
|
entry = collection(msg.collection)._entry(msg.key);
|
||||||
|
|
||||||
|
entry.release(this._id, function(err, json) {
|
||||||
|
if (err) self._sendError(msg, err);
|
||||||
|
else self._sendReply(msg);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Client.prototype.setRelease = function(msg) {
|
||||||
|
var self = this,
|
||||||
|
entry = collection(msg.collection)._entry(msg.key);
|
||||||
|
|
||||||
|
entry.setRelease(msg.json, this._id, function(err) {
|
||||||
|
if (err) self._sendError(msg, err);
|
||||||
|
else self._sendReply(msg);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Client.prototype.configure = function(msg) {
|
||||||
|
var coll = collection(msg.collection),
|
||||||
|
err = undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
coll._applyConfig(msg.config);
|
||||||
|
this._sendReply(msg);
|
||||||
|
} catch (err) {
|
||||||
|
this._sendError(msg, err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This function clobbers the data argument if specified!
|
||||||
|
Client.prototype._sendReply = function(msg, data) {
|
||||||
|
if (!msg.requestId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data = data || {};
|
||||||
|
data.type = 'DSM_REPLY';
|
||||||
|
data.requestId = msg.requestId;
|
||||||
|
data.err = undefined;
|
||||||
|
this._worker.send(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
Client.prototype._sendError = function(msg, err) {
|
||||||
|
if (!msg.requestId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var data = {};
|
||||||
|
data.type = 'DSM_REPLY';
|
||||||
|
data.requestId = msg.requestId;
|
||||||
|
data.err = err;
|
||||||
|
this._worker.send(data);
|
||||||
|
};
|
153
node_modules/strong-store-cluster/lib/master/Collection.js
generated
vendored
Normal file
153
node_modules/strong-store-cluster/lib/master/Collection.js
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
|
||||||
|
module.exports = Collection;
|
||||||
|
|
||||||
|
|
||||||
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||||
|
|
||||||
|
var assert = require('assert'),
|
||||||
|
inherits = require('util').inherits,
|
||||||
|
EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
var Entry = require('./Entry.js'),
|
||||||
|
KeyLock = require('./KeyLock.js');
|
||||||
|
|
||||||
|
|
||||||
|
function Collection(name) {
|
||||||
|
this._name = name;
|
||||||
|
this._entries = {};
|
||||||
|
this._count = 0;
|
||||||
|
this._expireKeys = null;
|
||||||
|
this._expireKeysTimer = null;
|
||||||
|
|
||||||
|
this._sweep = this._sweep.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(Collection, EventEmitter);
|
||||||
|
|
||||||
|
Collection.prototype._entry = function(key) {
|
||||||
|
if (!hasOwnProperty.call(this._entries, key)) {
|
||||||
|
if (!this._count++ && this._expireKeys)
|
||||||
|
this._startExpireKeysTimer();
|
||||||
|
|
||||||
|
return this._entries[key] = new Entry(this, key);
|
||||||
|
} else {
|
||||||
|
return this._entries[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype._remove = function(key) {
|
||||||
|
assert(hasOwnProperty.call(this._entries, key));
|
||||||
|
delete this._entries[key];
|
||||||
|
|
||||||
|
if (!--this._count && this.expireKeys)
|
||||||
|
this._stopExpireKeysTimer();
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.get = function(key, cb) {
|
||||||
|
this._entry(key).get(-1, function(err, json) {
|
||||||
|
if (err)
|
||||||
|
cb(err);
|
||||||
|
else if (!json)
|
||||||
|
cb(null, undefined);
|
||||||
|
else
|
||||||
|
cb(null, JSON.parse(json));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.set = function(key, value, cb) {
|
||||||
|
cb = cb || noop;
|
||||||
|
this._entry(key).set(JSON.stringify(value), -1, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.del = function(key, cb) {
|
||||||
|
cb = cb || noop;
|
||||||
|
this._entry(key).set(undefined, -1, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.acquire = function(key, cb) {
|
||||||
|
var self = this,
|
||||||
|
entry = this._entry(key);
|
||||||
|
|
||||||
|
entry.acquire(-1, function(err, json) {
|
||||||
|
var lock = new KeyLock(entry, json);
|
||||||
|
return cb(null, lock, lock.get());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype._applyConfig = function(config) {
|
||||||
|
config = config || {};
|
||||||
|
|
||||||
|
for (var key in config) {
|
||||||
|
if (!hasOwnProperty.call(config, key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'expireKeys':
|
||||||
|
if (config.expireKeys === this._expireKeys)
|
||||||
|
break;
|
||||||
|
|
||||||
|
this._stopExpireKeysTimer();
|
||||||
|
this._expireKeys = config.expireKeys;
|
||||||
|
this._startExpireKeysTimer();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error('Unspported configuration option: ' + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype._startExpireKeysTimer = function() {
|
||||||
|
assert(!this._expireKeysTimer);
|
||||||
|
|
||||||
|
if (!this._expireKeys || !this._count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var interval = Math.ceil(this._expireKeys * 1000 / 2);
|
||||||
|
|
||||||
|
this._expireKeysTimer = setInterval(this._sweep, interval);
|
||||||
|
this._expireKeysTimer.unref();
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype._stopExpireKeysTimer = function() {
|
||||||
|
if (!this._expireKeysTimer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearInterval(this._expireKeysTimer);
|
||||||
|
this._expireKeysTimer = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype._sweep = function() {
|
||||||
|
var entries = this._entries,
|
||||||
|
key;
|
||||||
|
|
||||||
|
for (key in entries) {
|
||||||
|
if (!hasOwnProperty.call(entries, key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (entries[key].age(1) > 2)
|
||||||
|
this._remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._count)
|
||||||
|
this._stopExpireKeysTimer();
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.configure = function(config) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._applyConfig(config);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
process.nextTick(function() {
|
||||||
|
self.emit('error', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function noop() {
|
||||||
|
}
|
103
node_modules/strong-store-cluster/lib/master/Entry.js
generated
vendored
Normal file
103
node_modules/strong-store-cluster/lib/master/Entry.js
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
module.exports = Entry;
|
||||||
|
|
||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
|
||||||
|
function Entry(collection, key) {
|
||||||
|
this._collection = collection;
|
||||||
|
this._key = key;
|
||||||
|
this._value = undefined;
|
||||||
|
this._queue = [];
|
||||||
|
this._age = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry.prototype.get = function(requestor, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (!this._queue.length) {
|
||||||
|
var value = self._value;
|
||||||
|
self._age = 0;
|
||||||
|
|
||||||
|
process.nextTick(function() {
|
||||||
|
cb(null, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.acquire(requestor, function(err) {
|
||||||
|
self.release(requestor, noop);
|
||||||
|
cb(null, self._value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry.prototype.set = function(newValue, requestor, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (!this._queue.length) {
|
||||||
|
this._value = newValue;
|
||||||
|
this._age = 0;
|
||||||
|
|
||||||
|
if (newValue === undefined)
|
||||||
|
this._collection._remove(this._key);
|
||||||
|
|
||||||
|
process.nextTick(cb);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.acquire(requestor, function() {
|
||||||
|
self._value = newValue;
|
||||||
|
|
||||||
|
if (newValue !== undefined)
|
||||||
|
self.release(requestor, cb);
|
||||||
|
else {
|
||||||
|
self._collection._remove(self._key);
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry.prototype.acquire = function(requestor, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this._queue.push([cb, requestor]);
|
||||||
|
|
||||||
|
if (this._queue.length === 1) {
|
||||||
|
process.nextTick(function() {
|
||||||
|
cb(null, self._value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry.prototype.release = function(requestor, cb) {
|
||||||
|
var self = this,
|
||||||
|
queue = this._queue;
|
||||||
|
|
||||||
|
setImmediate(function() {
|
||||||
|
assert.strictEqual(requestor, queue.shift()[1]);
|
||||||
|
|
||||||
|
self._age = 0;
|
||||||
|
cb();
|
||||||
|
|
||||||
|
if (queue.length)
|
||||||
|
queue[0][0](null, self._value);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry.prototype.setRelease = function(newValue, requestor, cb) {
|
||||||
|
this._value = newValue;
|
||||||
|
this.release(requestor, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Entry.prototype.age = function(d) {
|
||||||
|
if (this._queue.length)
|
||||||
|
return this._age = 0;
|
||||||
|
else
|
||||||
|
return this._age += (d || 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function noop() {
|
||||||
|
}
|
51
node_modules/strong-store-cluster/lib/master/KeyLock.js
generated
vendored
Normal file
51
node_modules/strong-store-cluster/lib/master/KeyLock.js
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
|
||||||
|
module.exports = KeyLock;
|
||||||
|
|
||||||
|
|
||||||
|
function KeyLock(entry, json) {
|
||||||
|
this._entry = entry;
|
||||||
|
this._json = json;
|
||||||
|
this._updated = false;
|
||||||
|
this._released = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyLock.prototype.get = function() {
|
||||||
|
if (!this._json)
|
||||||
|
return undefined;
|
||||||
|
else
|
||||||
|
return JSON.parse(this._json);
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyLock.prototype.set = function(newValue) {
|
||||||
|
if (this._released)
|
||||||
|
throw new Error("Can't set after releasing a lock.");
|
||||||
|
|
||||||
|
this._json = JSON.stringify(newValue);
|
||||||
|
this._updated = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyLock.prototype.del = function() {
|
||||||
|
if (this._released)
|
||||||
|
throw new Error("Can't delete after releasing a lock.");
|
||||||
|
|
||||||
|
this._json = undefined;
|
||||||
|
this._updated = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyLock.prototype.release = function(cb) {
|
||||||
|
if (this._released)
|
||||||
|
throw new Error('KeyLock has already been released.');
|
||||||
|
|
||||||
|
cb = cb || noop;
|
||||||
|
this._released = true;
|
||||||
|
|
||||||
|
if (!this._updated)
|
||||||
|
this._entry.release(-1, cb);
|
||||||
|
else
|
||||||
|
this._entry.setRelease(this._json, -1, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function noop() {
|
||||||
|
}
|
10
node_modules/strong-store-cluster/lib/master/setup.js
generated
vendored
Normal file
10
node_modules/strong-store-cluster/lib/master/setup.js
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
var cluster = require('cluster'),
|
||||||
|
Client = require('./Client.js');
|
||||||
|
|
||||||
|
for (var i = 0; i < cluster.workers.length; i++)
|
||||||
|
new Client(cluster.workers[i]);
|
||||||
|
|
||||||
|
cluster.on('online', function(worker) {
|
||||||
|
new Client(worker);
|
||||||
|
});
|
68
node_modules/strong-store-cluster/lib/worker/Collection.js
generated
vendored
Normal file
68
node_modules/strong-store-cluster/lib/worker/Collection.js
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
module.exports = Collection;
|
||||||
|
|
||||||
|
|
||||||
|
var inherits = require('util').inherits,
|
||||||
|
EventEmitter = require('events').EventEmitter,
|
||||||
|
KeyLock = require('./KeyLock.js'),
|
||||||
|
request = require('./request.js');
|
||||||
|
|
||||||
|
|
||||||
|
function Collection(name) {
|
||||||
|
this._name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(Collection, EventEmitter);
|
||||||
|
|
||||||
|
Collection.prototype.get = function(key, cb) {
|
||||||
|
this._request('get', key, null, function(err, msg) {
|
||||||
|
if (err)
|
||||||
|
return cb(err);
|
||||||
|
else if (!msg.json)
|
||||||
|
return cb(null, undefined);
|
||||||
|
else
|
||||||
|
return cb(null, JSON.parse(msg.json));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.set = function(key, value, cb) {
|
||||||
|
var data = { json: JSON.stringify(value) };
|
||||||
|
this._request('set', key, data, cb && function(err, msg) {
|
||||||
|
return cb(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.del = function(key, cb) {
|
||||||
|
return this._request('set', key, null, cb && function(err, msg) {
|
||||||
|
return cb(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.acquire = function(key, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this._request('acquire', key, null, function(err, msg) {
|
||||||
|
if (err)
|
||||||
|
return cb(err);
|
||||||
|
|
||||||
|
var json = msg.json;
|
||||||
|
var lock = new KeyLock(self, key, json);
|
||||||
|
cb(null, lock, lock.get());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Collection.prototype.configure = function(config) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this._request('configure', null, { config: config }, function(err, msg) {
|
||||||
|
if (err)
|
||||||
|
self.emit('error', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This function clobbers `data` if specified
|
||||||
|
Collection.prototype._request = function(method, key, data, cb) {
|
||||||
|
request(method, this._name, key, data, cb);
|
||||||
|
};
|
56
node_modules/strong-store-cluster/lib/worker/KeyLock.js
generated
vendored
Normal file
56
node_modules/strong-store-cluster/lib/worker/KeyLock.js
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
module.exports = KeyLock;
|
||||||
|
|
||||||
|
|
||||||
|
var request = require('./request.js');
|
||||||
|
|
||||||
|
|
||||||
|
function KeyLock(collection, key, json) {
|
||||||
|
this._collection = collection;
|
||||||
|
this._key = key;
|
||||||
|
this._json = json;
|
||||||
|
this._updated = false;
|
||||||
|
this._released = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyLock.prototype.get = function() {
|
||||||
|
if (!this._json)
|
||||||
|
return undefined;
|
||||||
|
else
|
||||||
|
return JSON.parse(this._json);
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyLock.prototype.set = function(newValue) {
|
||||||
|
if (this._released)
|
||||||
|
throw new Error("Can't set after releasing a lock.");
|
||||||
|
|
||||||
|
this._json = JSON.stringify(newValue);
|
||||||
|
this._updated = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyLock.prototype.del = function() {
|
||||||
|
if (this._released)
|
||||||
|
throw new Error("Can't delete after releasing a lock.");
|
||||||
|
|
||||||
|
this._json = undefined;
|
||||||
|
this._updated = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyLock.prototype.release = function(cb) {
|
||||||
|
if (this._released)
|
||||||
|
throw new Error('KeyLock has already been released.');
|
||||||
|
|
||||||
|
this._released = true;
|
||||||
|
|
||||||
|
if (!this._updated)
|
||||||
|
this._collection._request('release', this._key, null, cb && afterRelease);
|
||||||
|
else
|
||||||
|
this._collection._request('setRelease',
|
||||||
|
this._key,
|
||||||
|
{ json: this._json },
|
||||||
|
cb && afterRelease);
|
||||||
|
|
||||||
|
function afterRelease(err, msg) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
};
|
51
node_modules/strong-store-cluster/lib/worker/request.js
generated
vendored
Normal file
51
node_modules/strong-store-cluster/lib/worker/request.js
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
|
||||||
|
module.exports = request;
|
||||||
|
process.on('message', onMessage);
|
||||||
|
|
||||||
|
|
||||||
|
var requestIdCounter = 0;
|
||||||
|
var requestCallbacks = {};
|
||||||
|
|
||||||
|
|
||||||
|
// This function clobbers `data` if specified
|
||||||
|
function request(method, collection, key, data, cb) {
|
||||||
|
data = data || {};
|
||||||
|
|
||||||
|
data.type = 'DSM_REQUEST';
|
||||||
|
data.method = method;
|
||||||
|
data.collection = collection;
|
||||||
|
data.key = key;
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
var requestId = getRequestId();
|
||||||
|
requestCallbacks[requestId] = cb;
|
||||||
|
data.requestId = requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onMessage(msg) {
|
||||||
|
if (msg.type !== 'DSM_REPLY')
|
||||||
|
return;
|
||||||
|
|
||||||
|
var requestId = msg.requestId;
|
||||||
|
var cb = requestCallbacks[requestId];
|
||||||
|
delete requestCallbacks[requestId];
|
||||||
|
|
||||||
|
if (msg.err) {
|
||||||
|
var err = new Error('Master error: ' + msg.err);
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(null, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getRequestId() {
|
||||||
|
return ++requestIdCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
44
node_modules/strong-store-cluster/package.json
generated
vendored
Normal file
44
node_modules/strong-store-cluster/package.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
17
node_modules/strong-store-cluster/test/concurrent-inc.js
generated
vendored
Normal file
17
node_modules/strong-store-cluster/test/concurrent-inc.js
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
var helper = require('./helper/cluster-helper');
|
||||||
|
|
||||||
|
suite('concurrent increment', function() {
|
||||||
|
test('master only', function(cb) {
|
||||||
|
helper.run('do-concurrent-inc', true, 0, 4, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('four workers', function(cb) {
|
||||||
|
helper.run('do-concurrent-inc', false, 4, 4, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('master and four workers', function(cb) {
|
||||||
|
helper.run('do-concurrent-inc', true, 4, 4, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
12
node_modules/strong-store-cluster/test/get-set-del.js
generated
vendored
Normal file
12
node_modules/strong-store-cluster/test/get-set-del.js
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
var helper = require('./helper/cluster-helper');
|
||||||
|
|
||||||
|
suite('get-set-del', function() {
|
||||||
|
test('master', function(cb) {
|
||||||
|
helper.run('do-get-set-del', true, 0, 1, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('worker', function(cb) {
|
||||||
|
helper.run('do-get-set-del', false, 1, 1, cb);
|
||||||
|
});
|
||||||
|
});
|
83
node_modules/strong-store-cluster/test/helper/cluster-helper.js
generated
vendored
Normal file
83
node_modules/strong-store-cluster/test/helper/cluster-helper.js
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
|
||||||
|
|
||||||
|
var assert = require('assert'),
|
||||||
|
cluster = require('cluster');
|
||||||
|
|
||||||
|
|
||||||
|
if (!process.env.CLUSTER_TEST) {
|
||||||
|
// We're require()'d by the test harness. Export a function that start
|
||||||
|
// the test.
|
||||||
|
|
||||||
|
exports.run = function(filename, inMaster, workers, concurrency, cb) {
|
||||||
|
assert(filename);
|
||||||
|
assert(inMaster || workers);
|
||||||
|
assert(concurrency > 0);
|
||||||
|
|
||||||
|
var env = {};
|
||||||
|
for (var key in process.env)
|
||||||
|
env[key] = process.env[key];
|
||||||
|
|
||||||
|
env.CLUSTER_TEST = require.resolve('./' + filename);
|
||||||
|
env.CLUSTER_TEST_IN_MASTER = inMaster;
|
||||||
|
env.CLUSTER_TEST_WORKERS = workers;
|
||||||
|
env.CLUSTER_TEST_CONCURRENCY = concurrency;
|
||||||
|
|
||||||
|
var cp = require('child_process').fork(module.filename,
|
||||||
|
{env: env, stdio: 'inherit'});
|
||||||
|
|
||||||
|
cp.on('exit', function(exitCode, termSig) {
|
||||||
|
assert(exitCode === 0);
|
||||||
|
assert(!termSig);
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// We're being spawned as a standalone process. Execute the test and/or spawn
|
||||||
|
// cluster workers that do.
|
||||||
|
|
||||||
|
var filename = process.env.CLUSTER_TEST,
|
||||||
|
inMaster = !!+process.env.CLUSTER_TEST_IN_MASTER,
|
||||||
|
workers = ~~ + process.env.CLUSTER_TEST_WORKERS,
|
||||||
|
concurrency = ~~ + process.env.CLUSTER_TEST_CONCURRENCY;
|
||||||
|
|
||||||
|
var test = require(filename);
|
||||||
|
|
||||||
|
// Both the master and the worker have .setup() always called once.
|
||||||
|
test.setup && test.setup();
|
||||||
|
|
||||||
|
var waiting = 0;
|
||||||
|
|
||||||
|
// If we're the master process, spawn a number of workers.
|
||||||
|
if (cluster.isMaster && workers) {
|
||||||
|
for (var i = 0; i < workers; i++)
|
||||||
|
var worker = cluster.fork();
|
||||||
|
|
||||||
|
waiting += workers;
|
||||||
|
|
||||||
|
cluster.on('exit', function(worker, exitCode, termSig) {
|
||||||
|
assert(exitCode === 0);
|
||||||
|
assert(!termSig);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're either a worker, or the master is supposed to run the tests,
|
||||||
|
// run the test cases.
|
||||||
|
if (cluster.isWorker || inMaster) {
|
||||||
|
waiting += concurrency;
|
||||||
|
|
||||||
|
for (var i = 0; i < concurrency; i++)
|
||||||
|
test.run(done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function done() {
|
||||||
|
assert(--waiting >= 0);
|
||||||
|
if (waiting === 0)
|
||||||
|
return test.teardown && test.teardown();
|
||||||
|
}
|
||||||
|
|
51
node_modules/strong-store-cluster/test/helper/do-concurrent-inc.js
generated
vendored
Normal file
51
node_modules/strong-store-cluster/test/helper/do-concurrent-inc.js
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
exports.run = run;
|
||||||
|
exports.teardown = teardown;
|
||||||
|
|
||||||
|
|
||||||
|
var ROUNDS = 100;
|
||||||
|
assert = require('assert'),
|
||||||
|
cluster = require('cluster'),
|
||||||
|
store = require('../..');
|
||||||
|
|
||||||
|
|
||||||
|
function run(cb) {
|
||||||
|
var left = ROUNDS,
|
||||||
|
coll = store.collection('counter');
|
||||||
|
|
||||||
|
increment();
|
||||||
|
|
||||||
|
function increment() {
|
||||||
|
coll.acquire('counter', function(err, lock, val) {
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
val = 1;
|
||||||
|
else
|
||||||
|
val++;
|
||||||
|
|
||||||
|
lock.set(val);
|
||||||
|
lock.release();
|
||||||
|
|
||||||
|
if (--left > 0)
|
||||||
|
increment();
|
||||||
|
else
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function teardown() {
|
||||||
|
if (cluster.isWorker)
|
||||||
|
process._channel.unref();
|
||||||
|
|
||||||
|
if (cluster.isMaster) {
|
||||||
|
store.collection('counter').get('counter', function(err, value) {
|
||||||
|
assert(value % ROUNDS === 0);
|
||||||
|
assert(value >= ROUNDS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
60
node_modules/strong-store-cluster/test/helper/do-get-set-del.js
generated
vendored
Normal file
60
node_modules/strong-store-cluster/test/helper/do-get-set-del.js
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
exports.run = run;
|
||||||
|
exports.teardown = teardown;
|
||||||
|
|
||||||
|
|
||||||
|
var assert = require('assert'),
|
||||||
|
cluster = require('cluster'),
|
||||||
|
store = require('../..');
|
||||||
|
|
||||||
|
|
||||||
|
function run(cb) {
|
||||||
|
var testsRun = 0;
|
||||||
|
|
||||||
|
testWith('test1', 'key1', 'zulis', onDone);
|
||||||
|
testWith('test2', 'quux', 'stoll', onDone);
|
||||||
|
testWith('test2', 'key1', 'urals', onDone);
|
||||||
|
testWith('test2', 'key2', 'quipp', onDone);
|
||||||
|
|
||||||
|
function onDone() {
|
||||||
|
if (++testsRun === 4)
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testWith(collectionName, key, testValue, cb) {
|
||||||
|
var coll = store.collection(collectionName);
|
||||||
|
|
||||||
|
coll.get(key, function(err, value) {
|
||||||
|
assert(!err);
|
||||||
|
assert(value === undefined);
|
||||||
|
|
||||||
|
coll.set(key, testValue, function(err) {
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
coll.get(key, function(err, value) {
|
||||||
|
assert(!err);
|
||||||
|
assert(value === testValue);
|
||||||
|
|
||||||
|
coll.del(key, function(err) {
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
coll.get(key, function(err, value) {
|
||||||
|
assert(!err);
|
||||||
|
assert(value === undefined);
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function teardown() {
|
||||||
|
if (cluster.isWorker)
|
||||||
|
process._channel.unref();
|
||||||
|
}
|
80
node_modules/strong-store-cluster/test/helper/do-lock-get-set-del.js
generated
vendored
Normal file
80
node_modules/strong-store-cluster/test/helper/do-lock-get-set-del.js
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
exports.run = run;
|
||||||
|
exports.teardown = teardown;
|
||||||
|
|
||||||
|
|
||||||
|
var assert = require('assert'),
|
||||||
|
cluster = require('cluster'),
|
||||||
|
store = require('../..');
|
||||||
|
|
||||||
|
|
||||||
|
function run(cb) {
|
||||||
|
var testsRun = 0;
|
||||||
|
|
||||||
|
testWith('test1', 'key1', {foo: 'zulis'}, onDone);
|
||||||
|
testWith('test2', 'quux', ['stoll'], onDone);
|
||||||
|
testWith('test2', 'key1', 'urals', onDone);
|
||||||
|
testWith('test2', 'key2', 42, onDone);
|
||||||
|
|
||||||
|
function onDone() {
|
||||||
|
if (++testsRun === 4)
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function testWith(collectionName, key, testValue, cb) {
|
||||||
|
var coll = store.collection(collectionName);
|
||||||
|
|
||||||
|
coll.set(key, testValue, function(err, value) {
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
coll.acquire(key, function(err, lock, value) {
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
assert.deepEqual(testValue, value);
|
||||||
|
assert.deepEqual(testValue, lock.get());
|
||||||
|
|
||||||
|
// Non-primitive values should be deep-cloned.
|
||||||
|
if (typeof testValue === 'object') {
|
||||||
|
assert(testValue !== value);
|
||||||
|
assert(testValue !== lock.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.set('other');
|
||||||
|
assert('other' === lock.get());
|
||||||
|
|
||||||
|
lock.release(function(err) {
|
||||||
|
assert(!err);
|
||||||
|
});
|
||||||
|
|
||||||
|
coll.acquire(key, function(err, lock, value) {
|
||||||
|
assert(!err);
|
||||||
|
|
||||||
|
assert('other' === value);
|
||||||
|
assert('other' === lock.get());
|
||||||
|
|
||||||
|
lock.del();
|
||||||
|
assert(undefined === lock.get());
|
||||||
|
|
||||||
|
lock.release(function(err) {
|
||||||
|
assert(!err);
|
||||||
|
});
|
||||||
|
|
||||||
|
coll.get(key, function(err, value) {
|
||||||
|
assert(!err);
|
||||||
|
assert(undefined === value);
|
||||||
|
|
||||||
|
// That was it!
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function teardown() {
|
||||||
|
if (cluster.isWorker)
|
||||||
|
process._channel.unref();
|
||||||
|
}
|
12
node_modules/strong-store-cluster/test/lock-get-set-del.js
generated
vendored
Normal file
12
node_modules/strong-store-cluster/test/lock-get-set-del.js
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
var helper = require('./helper/cluster-helper');
|
||||||
|
|
||||||
|
suite('lock-get-set-del', function() {
|
||||||
|
test('master', function(cb) {
|
||||||
|
helper.run('do-lock-get-set-del', true, 0, 1, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('worker', function(cb) {
|
||||||
|
helper.run('do-lock-get-set-del', false, 1, 1, cb);
|
||||||
|
});
|
||||||
|
});
|
@ -20,8 +20,10 @@
|
|||||||
"moment": "",
|
"moment": "",
|
||||||
"async": "",
|
"async": "",
|
||||||
"passport-oauth": "",
|
"passport-oauth": "",
|
||||||
|
"markdown": "",
|
||||||
"node-uuid": "~1.4.1",
|
"node-uuid": "~1.4.1",
|
||||||
"MD5": "~1.2.1"
|
"MD5": "~1.2.1",
|
||||||
|
"pushover-notifications": "~0.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"supervisor": ""
|
"supervisor": ""
|
||||||
|
@ -46,6 +46,10 @@
|
|||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.nav > li {
|
.nav > li {
|
||||||
border-right: 1px solid #41bedd;
|
border-right: 1px solid #41bedd;
|
||||||
}
|
}
|
||||||
@ -76,3 +80,13 @@
|
|||||||
background-color: @navbarSecondaryLinkBackgroundActive;
|
background-color: @navbarSecondaryLinkBackgroundActive;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.day-of-year {
|
||||||
|
float: right !important;
|
||||||
|
position: relative;
|
||||||
|
color: white;
|
||||||
|
font-size: 18px;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
@ -288,6 +288,10 @@ header {
|
|||||||
width: 140px;
|
width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tech-current {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.enteries {
|
.enteries {
|
||||||
margin-left: 150px;
|
margin-left: 150px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -719,3 +723,33 @@ header {
|
|||||||
background-position: -7px -400px;
|
background-position: -7px -400px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
th.sort-true::after {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 8px solid transparent;
|
||||||
|
border-right: 8px solid transparent;
|
||||||
|
|
||||||
|
border-top: 8px solid #000;
|
||||||
|
content: "";
|
||||||
|
top: 12px;
|
||||||
|
left: 10px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.sort-false::after {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 8px solid transparent;
|
||||||
|
border-right: 8px solid transparent;
|
||||||
|
|
||||||
|
border-bottom: 8px solid #000;
|
||||||
|
content: "";
|
||||||
|
bottom: 11px;
|
||||||
|
left: 10px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ angular.module('biomed', ['biomed.filters', 'biomed.services', 'biomed.directive
|
|||||||
sales: 'Sales',
|
sales: 'Sales',
|
||||||
other: 'Others'
|
other: 'Others'
|
||||||
};
|
};
|
||||||
|
$rootScope.dayOfYear = moment().dayOfYear();
|
||||||
})
|
})
|
||||||
.config(function($routeProvider, $locationProvider, $httpProvider) {
|
.config(function($routeProvider, $locationProvider, $httpProvider) {
|
||||||
|
|
||||||
|
@ -18,9 +18,10 @@ biomed.TechScheduleCtrl = function($scope, $routeParams, $location, Schedule, Us
|
|||||||
function updateDate() {
|
function updateDate() {
|
||||||
Schedule.index({
|
Schedule.index({
|
||||||
tech: $routeParams.id,
|
tech: $routeParams.id,
|
||||||
start: $scope.date.toJSON(),
|
start: moment($scope.date).subtract('days', 10).toDate().toJSON(),
|
||||||
end: moment($scope.date).add('days', 7).toDate().toJSON()
|
end: moment($scope.date).add('days', 21).toDate().toJSON()
|
||||||
}, function(result) {
|
}, function(result) {
|
||||||
|
console.log(result);
|
||||||
$scope.schedule = result;
|
$scope.schedule = result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -85,6 +86,25 @@ biomed.SchedulePmsCtrl = function($scope, Clients) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.sort = {
|
||||||
|
column: 'client.name',
|
||||||
|
descending: false
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.selectedCls = function(column) {
|
||||||
|
return column == $scope.sort.column && 'sort-' + $scope.sort.descending;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.changeSorting = function(column) {
|
||||||
|
var sort = $scope.sort;
|
||||||
|
if (sort.column == column) {
|
||||||
|
sort.descending = !sort.descending;
|
||||||
|
} else {
|
||||||
|
sort.column = column;
|
||||||
|
sort.descending = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$scope.$watch('month', filter);
|
$scope.$watch('month', filter);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,17 +201,60 @@ biomed.UserClockCtrl = function($scope, $routeParams, Users) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
biomed.PostIndexCtrl = function($scope, $routeParams, Posts, LocationBinder) {
|
biomed.PostIndexCtrl = function($scope, $routeParams, Posts, LocationBinder) {
|
||||||
$scope.loading = true;
|
var updatePosts = function() {
|
||||||
|
$scope.loading = true;
|
||||||
|
|
||||||
$scope.posts = Posts.index(function() {
|
$scope.posts = Posts.index(
|
||||||
$scope.loading = false;
|
{page: $scope.page},
|
||||||
});
|
function() {
|
||||||
|
$scope.loading = false;
|
||||||
|
|
||||||
|
$scope.posted = 0;
|
||||||
|
|
||||||
|
angular.forEach($scope.posts, function(value) {
|
||||||
|
if (value.status === "posted") {
|
||||||
|
$scope.posted += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.selectPage = function(page) {
|
||||||
|
$scope.page = page;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$watch('page', updatePosts);
|
||||||
};
|
};
|
||||||
|
|
||||||
biomed.PostAddCtrl = function($scope, Posts, $location) {
|
biomed.PostAddCtrl = function($scope, Posts, $location) {
|
||||||
|
|
||||||
|
$scope.tagOptions = {
|
||||||
|
'multiple': true,
|
||||||
|
'simple_tags': true,
|
||||||
|
'tags': [],
|
||||||
|
'formatNoMatches': function() { return 'Type a tag and press return to add it.'; }
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.pages = [
|
||||||
|
{ value: 'front', label: 'Front Page' },
|
||||||
|
{ value: 'about-us', label: 'About Us' },
|
||||||
|
{ value: 'sales', label: 'Sales' },
|
||||||
|
{ value: 'service', label: 'Service' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$scope.togglePage = function(page) {
|
||||||
|
var idx = $scope.model.pages.indexOf(page.value);
|
||||||
|
if (idx > -1) {
|
||||||
|
$scope.model.pages.splice(idx, 1);
|
||||||
|
} else {
|
||||||
|
$scope.model.pages.push(page.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$scope.model = {
|
$scope.model = {
|
||||||
gallery: []
|
gallery: [],
|
||||||
|
pages: [],
|
||||||
|
postedOn: new Date()
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.titleImageOptions = {
|
$scope.titleImageOptions = {
|
||||||
@ -255,10 +318,6 @@ biomed.PostAddCtrl = function($scope, Posts, $location) {
|
|||||||
$scope.model.status = status;
|
$scope.model.status = status;
|
||||||
$scope.model.createdOn = new Date();
|
$scope.model.createdOn = new Date();
|
||||||
|
|
||||||
if (status === 'posted') {
|
|
||||||
$scope.model.postedOn = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
Posts.create($scope.model, function(result) {
|
Posts.create($scope.model, function(result) {
|
||||||
$location.path("/posts/" + result._id);
|
$location.path("/posts/" + result._id);
|
||||||
});
|
});
|
||||||
@ -276,9 +335,34 @@ biomed.PostAddCtrl = function($scope, Posts, $location) {
|
|||||||
biomed.PostEditCtrl = function($scope, Posts, $routeParams, $location) {
|
biomed.PostEditCtrl = function($scope, Posts, $routeParams, $location) {
|
||||||
var galleryImages = {};
|
var galleryImages = {};
|
||||||
|
|
||||||
|
$scope.tagOptions = {
|
||||||
|
'multiple': true,
|
||||||
|
'simple_tags': true,
|
||||||
|
'tags': [],
|
||||||
|
'formatNoMatches': function() { return 'Type a tag and press return to add it.'; }
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.pages = [
|
||||||
|
{ value: 'front', label: 'Front Page' },
|
||||||
|
{ value: 'about-us', label: 'About Us' },
|
||||||
|
{ value: 'sales', label: 'Sales' },
|
||||||
|
{ value: 'service', label: 'Service' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$scope.togglePage = function(page) {
|
||||||
|
var idx = $scope.model.pages.indexOf(page.value);
|
||||||
|
if (idx > -1) {
|
||||||
|
$scope.model.pages.splice(idx, 1);
|
||||||
|
} else {
|
||||||
|
$scope.model.pages.push(page.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$scope.model = Posts.get($routeParams, function() {
|
$scope.model = Posts.get($routeParams, function() {
|
||||||
$scope.loading = false;
|
$scope.loading = false;
|
||||||
|
|
||||||
|
console.log($scope.model);
|
||||||
|
|
||||||
if ($scope.model.image) {
|
if ($scope.model.image) {
|
||||||
$scope.existingTitleImages = [$scope.model.image];
|
$scope.existingTitleImages = [$scope.model.image];
|
||||||
}
|
}
|
||||||
@ -287,6 +371,10 @@ biomed.PostEditCtrl = function($scope, Posts, $routeParams, $location) {
|
|||||||
for (var i = 0; i < $scope.model.gallery.length; i++) {
|
for (var i = 0; i < $scope.model.gallery.length; i++) {
|
||||||
galleryImages[$scope.model.gallery[i]] = 1;
|
galleryImages[$scope.model.gallery[i]] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$scope.model.postedOn) {
|
||||||
|
$scope.model.postedOn = new Date();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.titleImageOptions = {
|
$scope.titleImageOptions = {
|
||||||
@ -349,11 +437,7 @@ biomed.PostEditCtrl = function($scope, Posts, $routeParams, $location) {
|
|||||||
$scope.model.gallery = Object.keys(galleryImages);
|
$scope.model.gallery = Object.keys(galleryImages);
|
||||||
$scope.model.status = status;
|
$scope.model.status = status;
|
||||||
|
|
||||||
if (status === 'posted') {
|
console.log($scope.model);
|
||||||
$scope.model.postedOn = new Date();
|
|
||||||
} else {
|
|
||||||
$scope.model.postedOn = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Posts.update({id: $scope.model._id}, $scope.model, function(result) {
|
Posts.update({id: $scope.model._id}, $scope.model, function(result) {
|
||||||
$location.path("/posts/");
|
$location.path("/posts/");
|
||||||
@ -396,7 +480,7 @@ biomed.ClientIndexCtrl = function($scope, $filter, $routeParams, Clients, Locati
|
|||||||
LocationBinder($scope, ['query']);
|
LocationBinder($scope, ['query']);
|
||||||
|
|
||||||
$scope.filter = function() {
|
$scope.filter = function() {
|
||||||
filteredData = $filter('filter')(allData, $scope.query);
|
filteredData = $filter('orderBy')($filter('filter')(allData, $scope.query), $scope.sort.column, $scope.sort.descending);
|
||||||
index = initialPageSize;
|
index = initialPageSize;
|
||||||
$scope.canLoad = true;
|
$scope.canLoad = true;
|
||||||
$scope.clients = filteredData.slice(0, initialPageSize);
|
$scope.clients = filteredData.slice(0, initialPageSize);
|
||||||
@ -407,6 +491,27 @@ biomed.ClientIndexCtrl = function($scope, $filter, $routeParams, Clients, Locati
|
|||||||
index += pageSize;
|
index += pageSize;
|
||||||
$scope.canLoad = index < filteredData.length;
|
$scope.canLoad = index < filteredData.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.sort = {
|
||||||
|
column: 'name',
|
||||||
|
descending: false
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.selectedCls = function(column) {
|
||||||
|
return column == $scope.sort.column && 'sort-' + $scope.sort.descending;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.changeSorting = function(column) {
|
||||||
|
var sort = $scope.sort;
|
||||||
|
if (sort.column == column) {
|
||||||
|
sort.descending = !sort.descending;
|
||||||
|
} else {
|
||||||
|
sort.column = column;
|
||||||
|
sort.descending = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.filter();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
biomed.ClientAddCtrl = function($scope, Clients, $location) {
|
biomed.ClientAddCtrl = function($scope, Clients, $location) {
|
||||||
@ -578,6 +683,10 @@ biomed.WorkorderIndexCtrl = function($scope, $filter, $routeParams, Workorders,
|
|||||||
|
|
||||||
$scope.$watch('end', fetchData);
|
$scope.$watch('end', fetchData);
|
||||||
|
|
||||||
|
$scope.sort = {
|
||||||
|
column: 'scheduling.start',
|
||||||
|
descending: true
|
||||||
|
};
|
||||||
|
|
||||||
$scope.addItems = function() {
|
$scope.addItems = function() {
|
||||||
$scope.workorders = $scope.workorders.concat(filteredData.slice(index, index + pageSize));
|
$scope.workorders = $scope.workorders.concat(filteredData.slice(index, index + pageSize));
|
||||||
@ -592,6 +701,20 @@ biomed.WorkorderIndexCtrl = function($scope, $filter, $routeParams, Workorders,
|
|||||||
$scope.workorders = filteredData.slice(0, initialPageSize);
|
$scope.workorders = filteredData.slice(0, initialPageSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.selectedCls = function(column) {
|
||||||
|
return column == $scope.sort.column && 'sort-' + $scope.sort.descending;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.changeSorting = function(column) {
|
||||||
|
var sort = $scope.sort;
|
||||||
|
if (sort.column == column) {
|
||||||
|
sort.descending = !sort.descending;
|
||||||
|
} else {
|
||||||
|
sort.column = column;
|
||||||
|
sort.descending = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function fetchData() {
|
function fetchData() {
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
|
|
||||||
@ -657,6 +780,10 @@ biomed.WorkorderAddCtrl = function($scope, $location, Workorders, Schedule, Clie
|
|||||||
|
|
||||||
$scope.$watch('group', updateUsers);
|
$scope.$watch('group', updateUsers);
|
||||||
|
|
||||||
|
$scope.$watch('model.client', function() {
|
||||||
|
$scope.currentClient = Clients.get({ id: $scope.model.client });
|
||||||
|
});
|
||||||
|
|
||||||
Clients.index(function(result) {
|
Clients.index(function(result) {
|
||||||
$scope.clients = result;
|
$scope.clients = result;
|
||||||
});
|
});
|
||||||
|
@ -89,10 +89,17 @@ angular.module('biomed.directives', [])
|
|||||||
|
|
||||||
attr.$observe('value', update)();
|
attr.$observe('value', update)();
|
||||||
attr.$observe('title', function(){ update(); a.text(tab.title); })();
|
attr.$observe('title', function(){ update(); a.text(tab.title); })();
|
||||||
|
attr.$observe('visible', function(){
|
||||||
|
update();
|
||||||
|
tab.tabElement[0].style.display = (tab.visible === "false") ? 'none' : 'block';
|
||||||
|
})();
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
|
console.log(attr.visible);
|
||||||
tab.title = attr.title;
|
tab.title = attr.title;
|
||||||
tab.value = attr.value || attr.title;
|
tab.value = attr.value || attr.title;
|
||||||
|
tab.visible = attr.visible;
|
||||||
|
|
||||||
if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
|
if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
|
||||||
// we are not part of angular
|
// we are not part of angular
|
||||||
ngModel.$viewValue = tab.value;
|
ngModel.$viewValue = tab.value;
|
||||||
@ -235,17 +242,17 @@ angular.module('biomed.directives', [])
|
|||||||
function setupScale() {
|
function setupScale() {
|
||||||
x = d3.scale.linear()
|
x = d3.scale.linear()
|
||||||
.range([0, 100])
|
.range([0, 100])
|
||||||
.domain([420, 1320])
|
.domain([420, 1140])
|
||||||
.clamp(true);
|
.clamp(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupScale();
|
setupScale();
|
||||||
|
|
||||||
var color = d3.scale.category20();
|
var color = d3.scale.category20();
|
||||||
var hourWidth = 100 / 15;
|
var hourWidth = 100 / 12;
|
||||||
|
|
||||||
$scope.hourMarkers = [];
|
$scope.hourMarkers = [];
|
||||||
for (var i = 7; i < 22; i++) {
|
for (var i = 7; i < 19; i++) {
|
||||||
$scope.hourMarkers.push({
|
$scope.hourMarkers.push({
|
||||||
date: moment({ hour: i }).toDate(),
|
date: moment({ hour: i }).toDate(),
|
||||||
style: {
|
style: {
|
||||||
@ -266,13 +273,16 @@ angular.module('biomed.directives', [])
|
|||||||
function generateDate() {
|
function generateDate() {
|
||||||
var range = moment($scope.date);
|
var range = moment($scope.date);
|
||||||
var data = {};
|
var data = {};
|
||||||
|
var current = range.format('ddd MMM Do YYYY');
|
||||||
|
|
||||||
for (var i = 0; i < 7; i++) {
|
for (var i = -7; i < 22; i++) {
|
||||||
var day = range.clone().add(i, 'days');
|
var day = range.clone().add(i, 'days');
|
||||||
var key = day.format('MM-DD-YYYY');
|
var key = day.format('MM-DD-YYYY');
|
||||||
var label = day.format('ddd MMM Do YYYY');
|
var label = day.format('ddd MMM Do YYYY');
|
||||||
|
|
||||||
data[key] = {
|
data[key] = {
|
||||||
|
order: i,
|
||||||
|
current: current == label,
|
||||||
label: label,
|
label: label,
|
||||||
values: []
|
values: []
|
||||||
};
|
};
|
||||||
@ -345,7 +355,12 @@ angular.module('biomed.directives', [])
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.data = data;
|
var dataArray = [];
|
||||||
|
for (var o in data) {
|
||||||
|
dataArray.push(data[o]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.data = dataArray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -374,7 +389,7 @@ angular.module('biomed.directives', [])
|
|||||||
rangeDate = moment($scope.date).startOf('day');
|
rangeDate = moment($scope.date).startOf('day');
|
||||||
|
|
||||||
rangeStart = moment(rangeDate).add('hours', 7);
|
rangeStart = moment(rangeDate).add('hours', 7);
|
||||||
rangeEnd = moment(rangeDate).add('hours', 22);
|
rangeEnd = moment(rangeDate).add('hours', 19);
|
||||||
|
|
||||||
x = d3.time.scale()
|
x = d3.time.scale()
|
||||||
.range([0, 100])
|
.range([0, 100])
|
||||||
|
@ -257,7 +257,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" title="Frequency">
|
<div class="tab-pane" title="Frequency" visible="{{accountHasPermission('client.frequency')}}">
|
||||||
<table class="table frequency">
|
<table class="table frequency">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
|
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 20%"></th>
|
<th style="width: 20%" ng-class="selectedCls('identifier')" ng-click="changeSorting('identifier')">ID</th>
|
||||||
<th style="width: 48%">Client Name</th>
|
<th style="width: 48%" ng-class="selectedCls('name')" ng-click="changeSorting('name')">Client Name</th>
|
||||||
<th style="width: 20%">Contact</th>
|
<th style="width: 20%" ng-class="selectedCls('contacts[0].name')" ng-click="changeSorting('contacts[0].name')">Contact</th>
|
||||||
<th style="width: 12%">Phone</th>
|
<th style="width: 12%" ng-class="selectedCls('contacts[0].phone')" ng-click="changeSorting('contacts[0].phone')">Phone</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -29,6 +29,32 @@
|
|||||||
<textarea ng-model="model.details" class="input-xlarge"></textarea>
|
<textarea ng-model="model.details" class="input-xlarge"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Posted On</label>
|
||||||
|
<div class="controls">
|
||||||
|
<span><input ng-model="model.postedOn" datepicker type="text" class="input-small"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Pages</label>
|
||||||
|
<div class="controls">
|
||||||
|
<label ng-repeat="page in pages">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="model.pages[]"
|
||||||
|
value="page.value"
|
||||||
|
ng-checked="model.pages.indexOf(page.value) > -1"
|
||||||
|
ng-click="togglePage(page)"
|
||||||
|
>{{page.label}}</input>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Tags</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" ui-select2="tagOptions" ng-model="model.tags" class="input-xxlarge" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -42,7 +68,7 @@
|
|||||||
<div class="dropzone" dropzone="titleImageOptions"></div>
|
<div class="dropzone" dropzone="titleImageOptions"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group">
|
<div class="control-group" ng-show="model.image">
|
||||||
<label class="control-label">Gallery</label>
|
<label class="control-label">Gallery</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div class="dropzone" dropzone="galleryImageOptions"></div>
|
<div class="dropzone" dropzone="galleryImageOptions"></div>
|
||||||
|
@ -29,6 +29,32 @@
|
|||||||
<textarea ng-model="model.details" class="input-xlarge"></textarea>
|
<textarea ng-model="model.details" class="input-xlarge"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Posted On</label>
|
||||||
|
<div class="controls">
|
||||||
|
<span><input ng-model="model.postedOn" datepicker type="text" class="input-small"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Pages</label>
|
||||||
|
<div class="controls">
|
||||||
|
<label ng-repeat="page in pages">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
name="model.pages[]"
|
||||||
|
value="page.value"
|
||||||
|
ng-checked="model.pages.indexOf(page.value) > -1"
|
||||||
|
ng-click="togglePage(page)"
|
||||||
|
>{{page.label}}</input>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label class="control-label">Tags</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" ui-select2="tagOptions" ng-model="model.tags" class="input-xxlarge" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -42,7 +68,7 @@
|
|||||||
<div class="dropzone" dropzone="titleImageOptions" existing="existingTitleImages"></div>
|
<div class="dropzone" dropzone="titleImageOptions" existing="existingTitleImages"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group">
|
<div class="control-group" ng-show="model.image">
|
||||||
<label class="control-label">Gallery</label>
|
<label class="control-label">Gallery</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div class="dropzone" dropzone="galleryImageOptions" existing="existingGalleryImages"></div>
|
<div class="dropzone" dropzone="galleryImageOptions" existing="existingGalleryImages"></div>
|
||||||
|
@ -9,20 +9,28 @@
|
|||||||
<div class="span12">
|
<div class="span12">
|
||||||
<div class="toolbelt">
|
<div class="toolbelt">
|
||||||
<a href="/posts/add" class="btn btn-primary">Create new Post</a>
|
<a href="/posts/add" class="btn btn-primary">Create new Post</a>
|
||||||
|
<a ng-click="selectPage('')" class="btn">All</a>
|
||||||
|
<a ng-click="selectPage('front')" class="btn">Front Page</a>
|
||||||
|
<a ng-click="selectPage('about-us')" class="btn">About Us</a>
|
||||||
|
<a ng-click="selectPage('sales')" class="btn">Sales</a>
|
||||||
|
<a ng-click="selectPage('service')" class="btn">Service</a>
|
||||||
|
<div class="pull-right">
|
||||||
|
<span class="toolbelt-text">Total Published: {{posted}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
|
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 5%">Title</th>
|
<th style="width: 45%">Title</th>
|
||||||
<th style="width: 5%">Author</th>
|
<th style="width: 15%">Author</th>
|
||||||
<th style="width: 5%">Created on</th>
|
<th style="width: 15%">Created on</th>
|
||||||
<th style="width: 5%">Posted on</th>
|
<th style="width: 15%">Posted on</th>
|
||||||
<th style="width: 5%">Status</th>
|
<th style="width: 10%">Status</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-show="loading"><td colspan="4" class="table-loading"><i class="loader"></i></td></tr>
|
<tr ng-show="loading"><td colspan="5" class="table-loading"><i class="loader"></i></td></tr>
|
||||||
<tr ng-hide="loading || posts.length"><td colspan="4" class="table-message">There is no information to display.</td></tr>
|
<tr ng-hide="loading || posts.length"><td colspan="5" class="table-message">There is no information to display.</td></tr>
|
||||||
<tr ng-hide="loading" ng-repeat="post in posts">
|
<tr ng-hide="loading" ng-repeat="post in posts">
|
||||||
<td>
|
<td>
|
||||||
<a href="/posts/{{post._id}}">
|
<a href="/posts/{{post._id}}">
|
||||||
|
@ -33,20 +33,20 @@
|
|||||||
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
|
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 48%">Client Name</th>
|
<th style="width: 48%" ng-class="selectedCls('client.name')" ng-click="changeSorting('client.name')">Client Name</th>
|
||||||
<th style="width: 20%">Reason</th>
|
<th style="width: 20%" ng-class="selectedCls('reason')" ng-click="changeSorting('reason')">Reason</th>
|
||||||
<th style="width: 20%">Contact</th>
|
<th style="width: 20%" ng-class="selectedCls('client.contacts[0].name')" ng-click="changeSorting('client.contacts[0].name')">Contact</th>
|
||||||
<th style="width: 12%">Phone</th>
|
<th style="width: 12%" ng-class="selectedCls('client.contacts[0].phone')" ng-click="changeSorting('client.contacts[0].phone')">Phone</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-show="loading"><td colspan="4" class="table-loading"><i class="loader"></i></td></tr>
|
<tr ng-show="loading"><td colspan="4" class="table-loading"><i class="loader"></i></td></tr>
|
||||||
<tr ng-hide="loading || pms.length"><td colspan="4" class="table-message">There is no information to display.</td></tr>
|
<tr ng-hide="loading || pms.length"><td colspan="4" class="table-message">There is no information to display.</td></tr>
|
||||||
<tr ng-hide="loading" ng-repeat="pm in pms">
|
<tr ng-hide="loading" ng-repeat="pm in pms | orderBy : sort.column : sort.descending">
|
||||||
<td><a ng-href="/workorders/add?workorderType=pm&clientId={{pm.client._id}}&type={{pm.reason}}">{{pm.client.name}} ({{pm.client.identifier | uppercase}})</a><br>
|
<td><a ng-href="/workorders/add?workorderType=pm&clientId={{pm.client._id}}&type={{pm.reason}}">{{pm.client.name}} ({{pm.client.identifier | uppercase}})</a><br>
|
||||||
<td>{{pm.reason}}</td>
|
<td>{{pm.reason}}</td>
|
||||||
<td>{{pm.client.contacts[0].name}}</td>
|
<td>{{pm.client.contacts[0].name}}</td>
|
||||||
<td>{{pm.lient.contacts[0].phone}}</td>
|
<td>{{pm.client.contacts[0].phone}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user