summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.sample-env (renamed from .env)2
-rw-r--r--bucky/app/bucky.js6
-rw-r--r--bucky/app/index.js6
-rw-r--r--bucky/app/router.js14
-rw-r--r--bucky/db/index.js42
-rw-r--r--lib/search/index.js110
-rw-r--r--lib/search/snippet.js103
-rw-r--r--package-lock.json2462
-rw-r--r--package.json1
-rw-r--r--public/assets/css/bucky.css112
-rw-r--r--public/assets/js/lib/views/details/commentform.js33
-rw-r--r--public/assets/js/lib/views/details/index.js16
-rw-r--r--public/assets/js/lib/views/index/hootbox.js24
-rw-r--r--public/assets/js/lib/views/index/index.js2
-rw-r--r--public/assets/js/lib/views/index/threadbox.js27
-rw-r--r--public/assets/js/util/format.js9
-rw-r--r--public/assets/js/vendor/view/formview.js24
-rw-r--r--public/assets/js/vendor/view/view.js1
-rwxr-xr-xsearch/bin/build-autocomplete53
-rwxr-xr-xsearch/bin/build-index112
-rwxr-xr-xsearch/bin/build-splashes112
-rw-r--r--search/bin/fix-files41
-rw-r--r--search/bin/gross.dbbin0 -> 3158016 bytes
-rwxr-xr-xsearch/bin/listener.pl65
-rwxr-xr-xsearch/bin/poetaster33
-rwxr-xr-xsearch/bin/watch-index.pl8
-rw-r--r--search/lib/Bucky.pm159
-rw-r--r--search/lib/Bucky/DB.pm175
-rw-r--r--search/lib/Bucky/Keyword.pm26
-rw-r--r--search/lib/Bucky/SVN.pm103
-rw-r--r--search/lib/Bucky/Search.pm413
-rw-r--r--search/lib/Bucky/Session.pm19
-rw-r--r--search/lib/Bucky/Thread.pm30
-rw-r--r--search/lib/Common.pm46
-rw-r--r--search/lib/Time/Stopwatch.pm13
-rw-r--r--search/lib/localbucky.pm12
-rw-r--r--views/pages/details.ejs9
-rw-r--r--views/pages/message.ejs2
-rw-r--r--views/partials/comments.ejs16
-rw-r--r--views/partials/files.ejs2
-rw-r--r--views/partials/gallery.ejs2
-rw-r--r--views/partials/header.ejs2
-rw-r--r--views/partials/hootbox.ejs9
-rw-r--r--views/partials/scripts.ejs1
-rw-r--r--views/partials/threads.ejs21
46 files changed, 4384 insertions, 97 deletions
diff --git a/.gitignore b/.gitignore
index 589c52d..dc9b0e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,5 @@ v1
node_modules/
dist
*.sql
-
+.env
+public/data
diff --git a/.env b/.sample-env
index 7c447f4..9a57f81 100644
--- a/.env
+++ b/.sample-env
@@ -1,5 +1,5 @@
DB_HOST=localhost
-DB_NAME=bucky
+DB_NAME=bucky3
DB_USER=carbon
DB_PASS=argon
HOST_NAME=5.k
diff --git a/bucky/app/bucky.js b/bucky/app/bucky.js
index 008427d..757592a 100644
--- a/bucky/app/bucky.js
+++ b/bucky/app/bucky.js
@@ -21,7 +21,9 @@ var bucky = module.exports = {
lookup[c.thread] = c
})
res.threads.forEach(function(thread){
- thread.set("comment_count", lookup[thread.id].count)
+ if (lookup[thread.id]) {
+ thread.set("comment_count", lookup[thread.id].count)
+ }
})
next()
})
@@ -58,7 +60,7 @@ var bucky = module.exports = {
})
},
ensureHootbox: function (req, res, next){
- db.getCommentsForThread(1, 9, 0, "desc").then(function(hootbox){
+ db.getCommentsForThread(1, 15, 0, "desc").then(function(hootbox){
res.hootbox = hootbox
next()
})
diff --git a/bucky/app/index.js b/bucky/app/index.js
index 2260cfe..03c5593 100644
--- a/bucky/app/index.js
+++ b/bucky/app/index.js
@@ -40,9 +40,9 @@ site.init = function(){
type: 'mongodb',
host: 'localhost',
port: 27017,
- dbName: 'sessionDb',
+ dbName: 'buckySessionDb',
collectionName: 'sessions',
- timeout: 10000
+ timeout: 10000,
}),
resave: true,
saveUninitialized: false,
@@ -53,7 +53,7 @@ site.init = function(){
app.use(passport.initialize())
app.use(passport.session())
- server = http.createServer(app).listen(5000, function () {
+ server = http.createServer(app).listen(process.env.PORT || 5000, function () {
console.log('Bucky listening at http://5.k:%s', server.address().port)
})
diff --git a/bucky/app/router.js b/bucky/app/router.js
index fe7d336..c3af565 100644
--- a/bucky/app/router.js
+++ b/bucky/app/router.js
@@ -1,8 +1,9 @@
-var auth = require('../util/auth')
-var middleware = require('../util/middleware')
-var fortune = require('../db/fortune')
-var bucky = require('../app/bucky')
-var util = require('../util/util')
+var auth = require('./auth')
+var middleware = require('./middleware')
+var fortune = require('./fortune')
+var bucky = require('./bucky')
+var db = require('./db')
+var util = require('./util')
module.exports = function(app){
app.all('*', middleware.ensureLocals)
@@ -29,13 +30,13 @@ module.exports = function(app){
app.post("/api/login", auth.loggedInLocal)
app.get("/api/index",
+ bucky.ensureLastlog,
middleware.ensureAuthenticated,
bucky.ensureLatestThreads,
bucky.ensureCommentCountsForThreads,
bucky.ensureFileCountsForThreads,
bucky.ensureKeywordsForThreads,
bucky.ensureHootbox,
- bucky.ensureLastlog,
function(req, res){
res.json({
threads: res.threads,
@@ -69,7 +70,6 @@ module.exports = function(app){
bucky.ensureThread,
// ensure thread privacy
bucky.createComment,
- // add comments and files
function(req, res){
res.json({
comment: res.comment
diff --git a/bucky/db/index.js b/bucky/db/index.js
index 77e94fa..f376308 100644
--- a/bucky/db/index.js
+++ b/bucky/db/index.js
@@ -58,12 +58,11 @@ db.getLastlog = function(limit){
return knex.column('username').column('lastseen').select().from('users').orderBy('lastseen', 'desc').limit(limit || 10)
}
-
/* THREADS */
db.getLatestThreads = function () {
return Thread.query(function(qb){
- qb.orderBy("id", "desc").limit(50)
+ qb.orderBy("lastmodified", "desc").limit(50)
}).fetchAll()
}
db.getThreadsForKeyword = function (keyword) {
@@ -74,7 +73,13 @@ db.getThreadsForKeyword = function (keyword) {
db.getThread = function (id) {
return Thread.query("where", "id", "=", id).fetch()
}
-
+db.createThread = function(data){
+ return new db.Thread(data).save()
+}
+db.updateThread = function(data){
+}
+db.removeThread = function(id){
+}
/* FILES */
@@ -87,7 +92,11 @@ db.getFileCounts = function(ids){
db.getFileSizes = function(ids){
return knex.column('thread').sum('size as size').select().from('files').where('thread', 'in', ids).groupBy('thread')
}
-
+db.createFile = function(data){
+ return new db.File(data).save()
+}
+db.removeFile = function(id){
+}
/* COMMENTS */
@@ -111,8 +120,12 @@ db.getCommentsForThread = function (id, limit, offset, order){
db.getCommentCounts = function(ids){
return knex.column('thread').count('* as count').select().from('comments').where('thread', 'in', ids).groupBy('thread')
}
-db.createComment = function(comment){
- return new Comment(comment).save()
+db.createComment = function(data){
+ return new db.Comment(data).save()
+}
+db.updateComment = function(data){
+}
+db.removeComment = function(id){
}
@@ -124,6 +137,13 @@ db.getKeywords = function (keywords){
db.getKeyword = function (keyword) {
return Keyword.query("where", "keyword", "=", keyword).fetch()
}
+db.createKeyword = function(data){
+ return new db.Keyword(data).save()
+}
+db.updateKeyword = function(data){
+}
+db.removeKeyword = function(id){
+}
/* MAILBOXES */
@@ -134,7 +154,8 @@ db.getMailboxes = function(username){
db.getMailboxCounts = function(boxes){
return knex.column('mbox').count('* as count').select().from('messages').where('mbox', 'in', boxes).groupBy('mbox')
}
-
+db.createMailbox = function(data){
+}
/* MESSAGES */
@@ -157,3 +178,10 @@ db.getMessage = function (id){
return message
})
}
+db.createMessage = function(data){
+ return new db.Message(data).save()
+}
+db.updateMessage = function(data){
+}
+db.removeMessage = function(id){
+}
diff --git a/lib/search/index.js b/lib/search/index.js
new file mode 100644
index 0000000..27f436f
--- /dev/null
+++ b/lib/search/index.js
@@ -0,0 +1,110 @@
+var db = require('../db')
+var bdb_lib = require('berkeleydb')
+var bdb = new bdb_lib.Db()
+bdb.open('search.db')
+
+var wordRegexp = new RegExp("(\W+)");
+var wordBoundaryRegexp = new RegExp("\W");
+function parse_terms (s) {
+ return s.toLowerCase().split(wordRegexp).filter((term) => {
+ if (! term.match(wordBoundaryRegexp)) {
+ return true
+ }
+ return false
+ })
+}
+function cmp (a,b){ return (a<b)?a:(a===b)?0:1 }
+
+var STOPWORDS = new Set(
+ "a about above across adj after again against all almost alone along also " +
+ "although always am among an and another any anybody anyone anything anywhere " +
+ "apart are around as aside at away be because been before behind being below " +
+ "besides between beyond both but by can cannot could did do does doing done " +
+ "down downwards during each either else enough etc even ever every everybody " +
+ "everyone except far few for forth from get gets got had hardly has have having " +
+ "her here herself him himself his how however i if in indeed instead into inward " +
+ "is it its itself just kept many maybe might mine more most mostly much must " +
+ "myself near neither next no nobody none nor not nothing nowhere of off often on " +
+ "only onto or other others ought our ours out outside over own p per please plus " +
+ "pp quite rather really said seem self selves several shall she should since so " +
+ "some somebody somewhat still such than that the their theirs them themselves " +
+ "then there therefore these they this thorough thoroughly those through thus to " +
+ "together too toward towards under until up upon v very was well were what " +
+ "whatever when whenever where whether which while who whom whose will with" +
+ "within without would yet young your yourself s".split(" ")
+);
+
+function find_term(term) {
+ var matches = bdb.get(term).split(",").map((s) => {
+ var partz = s.split(" ")
+ var match = {
+ thread: s[0],
+ comment: s[1],
+ file: s[2],
+ strength: s[3],
+ }
+ })
+ return matches
+}
+
+function search (query, start, limit) {
+ if (!query) return
+ start = start || 0;
+ limit = limit || 10;
+ var scores = {};
+ var terms = parse_terms($query);
+ var i = 0
+ var total
+ var to_display = limit
+ var threads = {}
+ var comment_ids = []
+ var file_ids = []
+ var results = []
+
+ terms.forEach((term) => {
+ if (STOPWORDS.has(term)) return;
+ var results = find_term(term);
+ if (!results) return;
+ results.forEach((result) => {
+ var score = scores[result.thread] = scores[result.thread] || { count: 0, strength: 0 }
+ score.thread = score.thread || result.thread
+ score.comment = score.comment || result.comment
+ score.file = score.file || result.file
+ score.strength += result.strength
+ score.count += 1
+ })
+ })
+ total = Object.keys(scores).length
+ Object.values(scores).sort((a,b) => {
+ if (b.count !== a.count) {
+ return cmp(b.count, a.count)
+ }
+ return cmp(b.strength * b.count, a.strength * a.count)
+ }).some((match) => {
+ if (i++ < start) return false
+ if (to_display-- === 0) return true
+ results.push(match)
+ thread_ids.push(match.thread)
+ if (match.comment) comment_ids.push(match.comment)
+ if (match.file) file_ids.push(match.file)
+ return false
+ })
+
+ db.storeQuery(query, total)
+
+ my $files = $self->files_by_id($files_to_get);
+ my $comments = $self->comments_by_id($comments_to_get);
+ $self->log_query($query, $total);
+ return {
+ start => $start + $limit,
+ limit => $limit,
+ total => $total,
+ results => $results,
+ threads => $threads,
+ comments => $comments,
+ files => $files,
+ terms => $terms,
+ };
+}
+
+module.exports = { search: search }
diff --git a/lib/search/snippet.js b/lib/search/snippet.js
new file mode 100644
index 0000000..de71911
--- /dev/null
+++ b/lib/search/snippet.js
@@ -0,0 +1,103 @@
+var util = require('../util/util')
+
+function bold_terms (s, terms) {
+
+}
+sub bold_terms
+ {
+ my ($self, $string, $terms) = @_;
+ $string = $self->strip_html($string);
+ foreach my $term (@$terms)
+ {
+ $string =~ s/\b($term)\b/<b>$1<\/b>/gi;
+ }
+ return $string;
+ }
+sub bold_snippet
+ {
+ my ($self, $string, $terms) = @_;
+ my $snippet = $self->snippet($string, $terms);
+ return $self->bold_terms($snippet, $terms);
+ }
+sub snippet
+ {
+ my ($self, $string, $terms) = @_;
+
+ # clean up the string we got
+ $string = $self->strip_html($string);
+
+ # create a regex out of the search terms
+ my $term_re = join "|", @$terms;
+
+ # take the string to be snippetized and split it into words
+ my @words = split /\s+/, $string;
+
+ # deduper for matching @words indexes, so we don't add a word twice
+ my $index_matches = {};
+
+ # words in the eventual snippet
+ my @words_matched;
+
+ # the snippet itself
+ my $snippet = '';
+
+ # counter for aggregating context after a match
+ my $aggr = 0;
+
+ # amount of context to show, in number of words surrounding a match
+ my $pad = 4;
+
+ # loop over each of the words in the string
+ for (my $i = 0; $i < scalar @words; $i++)
+ {
+ # does this word contain a match?
+ if ($words[$i] =~ /\b($term_re)\b/i && ! $self->is_stopword($1))
+ {
+ # if we aren't already aggregating, add an ellipsis
+ if (! $aggr)
+ {
+ push @words_matched, "...";
+ }
+ # look backward $pad words
+ for (my $j = -$pad; $j < 1; $j++)
+ {
+ # create a new index from the offset
+ my $idx = $i + $j;
+
+ # is this a valid index? has it already been encountered?
+ next if $idx < 0;
+ next if $idx > scalar @words;
+ next if exists $index_matches->{$i+$j};
+
+ # checks out, save this word
+ push @words_matched, $words[$i+$j];
+
+ # note the matching index in our deduper
+ $index_matches->{$i+$j} ++;
+ }
+ # enter aggregate mode -- add the next $pad words
+ $aggr = $pad;
+ }
+ # have we been told to aggregate?
+ elsif ($aggr)
+ {
+ # save this word
+ push @words_matched, $words[$i];
+
+ # add index to the deduper
+ $index_matches->{$i} ++;
+
+ # one less word to aggregate
+ $aggr--;
+ }
+ # keep snippets to a modest length
+ last if scalar @words_matched > 30;
+ }
+ # add a trailing ellipsis
+ push @words_matched, "...";
+
+ # create the snippet from the saved context words
+ $snippet = join " ", @words_matched;
+
+ return $snippet;
+ } \ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..f0a494e
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,2462 @@
+{
+ "name": "bucky",
+ "version": "3.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "berkeleydb": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/berkeleydb/-/berkeleydb-0.2.1.tgz",
+ "integrity": "sha1-pY5bGTSakJFPqpxKhLOJ4ar7gWs=",
+ "requires": {
+ "bindings": "1.3.0",
+ "nan": "2.8.0"
+ }
+ },
+ "bindings": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz",
+ "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw=="
+ },
+ "body-parser": {
+ "version": "1.13.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz",
+ "integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=",
+ "requires": {
+ "bytes": "2.1.0",
+ "content-type": "1.0.1",
+ "debug": "2.2.0",
+ "depd": "1.0.1",
+ "http-errors": "1.3.1",
+ "iconv-lite": "0.4.11",
+ "on-finished": "2.3.0",
+ "qs": "4.0.0",
+ "raw-body": "2.1.2",
+ "type-is": "1.6.8"
+ },
+ "dependencies": {
+ "bytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz",
+ "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q="
+ },
+ "content-type": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.1.tgz",
+ "integrity": "sha1-oZ0iRzJ9wDgFDOYit6FU7FnF5gA="
+ },
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
+ "depd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz",
+ "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo="
+ },
+ "http-errors": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
+ "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=",
+ "requires": {
+ "inherits": "2.0.1",
+ "statuses": "1.2.1"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "statuses": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz",
+ "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg="
+ }
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.11",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz",
+ "integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ },
+ "dependencies": {
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ }
+ }
+ },
+ "qs": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz",
+ "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc="
+ },
+ "raw-body": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.2.tgz",
+ "integrity": "sha1-Y0gagFujDtfVmtRDOyDrhQ+V6Ic=",
+ "requires": {
+ "bytes": "2.1.0",
+ "iconv-lite": "0.4.11",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ }
+ }
+ },
+ "type-is": {
+ "version": "1.6.8",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.8.tgz",
+ "integrity": "sha1-O6yMDIUnVMhVFD4gbUoW6Qi/AxU=",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "2.1.6"
+ },
+ "dependencies": {
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "mime-types": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.6.tgz",
+ "integrity": "sha1-lJ+HiEEYZN3HCUig8hxD8p0lZnw=",
+ "requires": {
+ "mime-db": "1.18.0"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.18.0.tgz",
+ "integrity": "sha1-UxfigiTAivHUhPYJc904a6jzieA="
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "bookshelf": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/bookshelf/-/bookshelf-0.8.2.tgz",
+ "integrity": "sha1-k8e7felW+Yfvjqhm7869i8CDazw=",
+ "requires": {
+ "bluebird": "2.9.34",
+ "chalk": "1.1.1",
+ "create-error": "0.3.1",
+ "inflection": "1.7.1",
+ "inherits": "2.0.1",
+ "lodash": "3.10.1",
+ "semver": "4.3.6"
+ },
+ "dependencies": {
+ "bluebird": {
+ "version": "2.9.34",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz",
+ "integrity": "sha1-L3tOyAIWMoqf3evfacjUlC/v99g="
+ },
+ "chalk": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz",
+ "integrity": "sha1-UJr7ZwZudJn36zU1x3RFdyri0Bk=",
+ "requires": {
+ "ansi-styles": "2.1.0",
+ "escape-string-regexp": "1.0.3",
+ "has-ansi": "2.0.0",
+ "strip-ansi": "3.0.0",
+ "supports-color": "2.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz",
+ "integrity": "sha1-mQ90cUaSe1Wakyv5KVkWPWDA0OI="
+ },
+ "escape-string-regexp": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz",
+ "integrity": "sha1-ni2LJbwlVcMzZyN1DgPwmcJzW7U="
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "requires": {
+ "ansi-regex": "2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz",
+ "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc="
+ }
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz",
+ "integrity": "sha1-dRC2ZVZ8qRTMtdfgcnY6yWi+NyQ=",
+ "requires": {
+ "ansi-regex": "2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz",
+ "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc="
+ }
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+ }
+ }
+ },
+ "create-error": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/create-error/-/create-error-0.3.1.tgz",
+ "integrity": "sha1-aYECRaYp5lRDK/BDdzYAA6U1GiM="
+ },
+ "inflection": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.7.1.tgz",
+ "integrity": "sha1-HPFgzUIJVtZ0/RWvbZQpEnHTi3g="
+ },
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "semver": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
+ "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto="
+ }
+ }
+ },
+ "cookie-parser": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz",
+ "integrity": "sha1-nXVVcPtdF4kHcSJ6AjFNm+fPg1Y=",
+ "requires": {
+ "cookie": "0.1.3",
+ "cookie-signature": "1.0.6"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz",
+ "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ }
+ }
+ },
+ "csurf": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.8.3.tgz",
+ "integrity": "sha1-I/KhO/HY/OHQyZZYg5RELLqGpWo=",
+ "requires": {
+ "cookie": "0.1.3",
+ "cookie-signature": "1.0.6",
+ "csrf": "3.0.0",
+ "http-errors": "1.3.1"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz",
+ "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "csrf": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.0.0.tgz",
+ "integrity": "sha1-Sk0008H4vvnZtMWWon79YNky2Do=",
+ "requires": {
+ "base64-url": "1.2.1",
+ "rndm": "1.1.0",
+ "scmp": "1.0.0",
+ "uid-safe": "2.0.0"
+ },
+ "dependencies": {
+ "base64-url": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz",
+ "integrity": "sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg="
+ },
+ "rndm": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.1.0.tgz",
+ "integrity": "sha1-AdGo8fubRxGBkltie5BJvzMHRXQ="
+ },
+ "scmp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/scmp/-/scmp-1.0.0.tgz",
+ "integrity": "sha1-oLJyw/xykvdxFWRvAGGLAmJRTgQ="
+ },
+ "uid-safe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.0.0.tgz",
+ "integrity": "sha1-p/PGymSh9qXQTsDvPkw9U2cxcTc=",
+ "requires": {
+ "base64-url": "1.2.1"
+ }
+ }
+ }
+ },
+ "http-errors": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
+ "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=",
+ "requires": {
+ "inherits": "2.0.1",
+ "statuses": "1.2.1"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "statuses": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz",
+ "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg="
+ }
+ }
+ }
+ }
+ },
+ "dotenv": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-1.2.0.tgz",
+ "integrity": "sha1-fNc+FuB/BXyAchR6W8OoZ38KtcY="
+ },
+ "ejs": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.3.3.tgz",
+ "integrity": "sha1-prq7Z4FdcZBpSvS6gv4GXlbV8Oc="
+ },
+ "express": {
+ "version": "4.13.3",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.13.3.tgz",
+ "integrity": "sha1-3bLx+0UCvzNZjSsDKwN5YMpsgKM=",
+ "requires": {
+ "accepts": "1.2.12",
+ "array-flatten": "1.1.1",
+ "content-disposition": "0.5.0",
+ "content-type": "1.0.1",
+ "cookie": "0.1.3",
+ "cookie-signature": "1.0.6",
+ "debug": "2.2.0",
+ "depd": "1.0.1",
+ "escape-html": "1.0.2",
+ "etag": "1.7.0",
+ "finalhandler": "0.4.0",
+ "fresh": "0.3.0",
+ "merge-descriptors": "1.0.0",
+ "methods": "1.1.1",
+ "on-finished": "2.3.0",
+ "parseurl": "1.3.0",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "1.0.8",
+ "qs": "4.0.0",
+ "range-parser": "1.0.2",
+ "send": "0.13.0",
+ "serve-static": "1.10.0",
+ "type-is": "1.6.8",
+ "utils-merge": "1.0.0",
+ "vary": "1.0.1"
+ },
+ "dependencies": {
+ "accepts": {
+ "version": "1.2.12",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.12.tgz",
+ "integrity": "sha1-fm2ID0c7XEjUbj419x6nw7aFFMM=",
+ "requires": {
+ "mime-types": "2.1.6",
+ "negotiator": "0.5.3"
+ },
+ "dependencies": {
+ "mime-types": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.6.tgz",
+ "integrity": "sha1-lJ+HiEEYZN3HCUig8hxD8p0lZnw=",
+ "requires": {
+ "mime-db": "1.18.0"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.18.0.tgz",
+ "integrity": "sha1-UxfigiTAivHUhPYJc904a6jzieA="
+ }
+ }
+ },
+ "negotiator": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz",
+ "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g="
+ }
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "content-disposition": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz",
+ "integrity": "sha1-QoT+auBjCHRjnkToCkGMKTQTXp4="
+ },
+ "content-type": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.1.tgz",
+ "integrity": "sha1-oZ0iRzJ9wDgFDOYit6FU7FnF5gA="
+ },
+ "cookie": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz",
+ "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
+ "depd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz",
+ "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo="
+ },
+ "escape-html": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz",
+ "integrity": "sha1-130y+pjjjC9BroXpJ44ODmuhAiw="
+ },
+ "etag": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz",
+ "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg="
+ },
+ "finalhandler": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz",
+ "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=",
+ "requires": {
+ "debug": "2.2.0",
+ "escape-html": "1.0.2",
+ "on-finished": "2.3.0",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ }
+ }
+ },
+ "fresh": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz",
+ "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8="
+ },
+ "merge-descriptors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz",
+ "integrity": "sha1-IWnPdTjhsMyH+4jhUC2EdLv3mGQ="
+ },
+ "methods": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.1.tgz",
+ "integrity": "sha1-F+pjZgZtAMWON1uOx9/QRTyJgio="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ },
+ "dependencies": {
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ }
+ }
+ },
+ "parseurl": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.0.tgz",
+ "integrity": "sha1-tYBG20Ij4UWvp2AJ5hush8wigbM="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "proxy-addr": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.8.tgz",
+ "integrity": "sha1-21Tsh4vMEFPVdkZgkhmzcVZ4uv4=",
+ "requires": {
+ "forwarded": "0.1.0",
+ "ipaddr.js": "1.0.1"
+ },
+ "dependencies": {
+ "forwarded": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz",
+ "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M="
+ },
+ "ipaddr.js": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.1.tgz",
+ "integrity": "sha1-XziAHcc+BAD8cHY4b27VIV+9j5U="
+ }
+ }
+ },
+ "qs": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz",
+ "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc="
+ },
+ "range-parser": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.2.tgz",
+ "integrity": "sha1-BqEqQuUTG6jkV82JIESGfyNE5Uk="
+ },
+ "send": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.13.0.tgz",
+ "integrity": "sha1-UY+SGusFYK7H3KspkLFM9vPM5d4=",
+ "requires": {
+ "debug": "2.2.0",
+ "depd": "1.0.1",
+ "destroy": "1.0.3",
+ "escape-html": "1.0.2",
+ "etag": "1.7.0",
+ "fresh": "0.3.0",
+ "http-errors": "1.3.1",
+ "mime": "1.3.4",
+ "ms": "0.7.1",
+ "on-finished": "2.3.0",
+ "range-parser": "1.0.2",
+ "statuses": "1.2.1"
+ },
+ "dependencies": {
+ "destroy": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz",
+ "integrity": "sha1-tDO0ck5x/YVR2YhRdIUcX8N34sk="
+ },
+ "http-errors": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
+ "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=",
+ "requires": {
+ "inherits": "2.0.1",
+ "statuses": "1.2.1"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ }
+ }
+ },
+ "mime": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
+ "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ },
+ "statuses": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz",
+ "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.0.tgz",
+ "integrity": "sha1-vmMvqmhYIOSkPtPfE3kTXMTzcNc=",
+ "requires": {
+ "escape-html": "1.0.2",
+ "parseurl": "1.3.0",
+ "send": "0.13.0"
+ }
+ },
+ "type-is": {
+ "version": "1.6.8",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.8.tgz",
+ "integrity": "sha1-O6yMDIUnVMhVFD4gbUoW6Qi/AxU=",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "2.1.6"
+ },
+ "dependencies": {
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "mime-types": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.6.tgz",
+ "integrity": "sha1-lJ+HiEEYZN3HCUig8hxD8p0lZnw=",
+ "requires": {
+ "mime-db": "1.18.0"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.18.0.tgz",
+ "integrity": "sha1-UxfigiTAivHUhPYJc904a6jzieA="
+ }
+ }
+ }
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
+ "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
+ },
+ "vary": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz",
+ "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA="
+ }
+ }
+ },
+ "express-json": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/express-json/-/express-json-1.0.0.tgz",
+ "integrity": "sha1-n91TI5rQpvPgdvVFhdiiJDB1+zY="
+ },
+ "express-session": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.11.3.tgz",
+ "integrity": "sha1-XMmPP1/4Ttg1+Ry/CqvQxxB0AK8=",
+ "requires": {
+ "cookie": "0.1.3",
+ "cookie-signature": "1.0.6",
+ "crc": "3.3.0",
+ "debug": "2.2.0",
+ "depd": "1.0.1",
+ "on-headers": "1.0.0",
+ "parseurl": "1.3.0",
+ "uid-safe": "2.0.0",
+ "utils-merge": "1.0.0"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz",
+ "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "crc": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/crc/-/crc-3.3.0.tgz",
+ "integrity": "sha1-+mIuG8OIvyVzCQgta2UgDOZwkLo="
+ },
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
+ "depd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz",
+ "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo="
+ },
+ "on-headers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.0.tgz",
+ "integrity": "sha1-LHW12kN1UT0BYcYFLn/L5JU/yl0="
+ },
+ "parseurl": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.0.tgz",
+ "integrity": "sha1-tYBG20Ij4UWvp2AJ5hush8wigbM="
+ },
+ "uid-safe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.0.0.tgz",
+ "integrity": "sha1-p/PGymSh9qXQTsDvPkw9U2cxcTc=",
+ "requires": {
+ "base64-url": "1.2.1"
+ },
+ "dependencies": {
+ "base64-url": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz",
+ "integrity": "sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg="
+ }
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
+ "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
+ }
+ }
+ },
+ "knex": {
+ "version": "0.8.6",
+ "resolved": "https://registry.npmjs.org/knex/-/knex-0.8.6.tgz",
+ "integrity": "sha1-IPL0ps+Y+nVbXO6aqfq65TGvBWo=",
+ "requires": {
+ "bluebird": "2.9.34",
+ "chalk": "1.1.1",
+ "commander": "2.8.1",
+ "debug": "2.2.0",
+ "inherits": "2.0.1",
+ "interpret": "0.5.2",
+ "liftoff": "2.0.3",
+ "lodash": "3.10.1",
+ "minimist": "1.1.3",
+ "mkdirp": "0.5.1",
+ "pool2": "1.2.0",
+ "readable-stream": "1.1.13",
+ "tildify": "1.0.0",
+ "v8flags": "2.0.10"
+ },
+ "dependencies": {
+ "bluebird": {
+ "version": "2.9.34",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz",
+ "integrity": "sha1-L3tOyAIWMoqf3evfacjUlC/v99g="
+ },
+ "chalk": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz",
+ "integrity": "sha1-UJr7ZwZudJn36zU1x3RFdyri0Bk=",
+ "requires": {
+ "ansi-styles": "2.1.0",
+ "escape-string-regexp": "1.0.3",
+ "has-ansi": "2.0.0",
+ "strip-ansi": "3.0.0",
+ "supports-color": "2.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz",
+ "integrity": "sha1-mQ90cUaSe1Wakyv5KVkWPWDA0OI="
+ },
+ "escape-string-regexp": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz",
+ "integrity": "sha1-ni2LJbwlVcMzZyN1DgPwmcJzW7U="
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "requires": {
+ "ansi-regex": "2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz",
+ "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc="
+ }
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz",
+ "integrity": "sha1-dRC2ZVZ8qRTMtdfgcnY6yWi+NyQ=",
+ "requires": {
+ "ansi-regex": "2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz",
+ "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc="
+ }
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+ }
+ }
+ },
+ "commander": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+ "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
+ "requires": {
+ "graceful-readlink": "1.0.1"
+ },
+ "dependencies": {
+ "graceful-readlink": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
+ }
+ }
+ },
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "interpret": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-0.5.2.tgz",
+ "integrity": "sha1-N3gzsEteppP/DVMzgOPdoMA4G+A="
+ },
+ "liftoff": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.0.3.tgz",
+ "integrity": "sha1-+6slNipQasKKPbDFXN6VYvvXBFY=",
+ "requires": {
+ "extend": "2.0.1",
+ "findup-sync": "0.2.1",
+ "flagged-respawn": "0.3.1",
+ "minimist": "1.1.3",
+ "resolve": "1.1.6"
+ },
+ "dependencies": {
+ "extend": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-2.0.1.tgz",
+ "integrity": "sha1-HugBBonnOV/5RIJByYZSvHWagmA="
+ },
+ "findup-sync": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.2.1.tgz",
+ "integrity": "sha1-4KkKRQB1xJRm7lE3MgV1FLgeh4w=",
+ "requires": {
+ "glob": "4.3.5"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-4.3.5.tgz",
+ "integrity": "sha1-gPuwjKVA8jiszl0R0em8QedRc9M=",
+ "requires": {
+ "inflight": "1.0.4",
+ "inherits": "2.0.1",
+ "minimatch": "2.0.10",
+ "once": "1.3.2"
+ },
+ "dependencies": {
+ "inflight": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
+ "integrity": "sha1-bLtFIevVHODsCpNr/XZX736bFyo=",
+ "requires": {
+ "once": "1.3.2",
+ "wrappy": "1.0.1"
+ },
+ "dependencies": {
+ "wrappy": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz",
+ "integrity": "sha1-HmWWmWXMvC20VIxrhKbyxa7dRzk="
+ }
+ }
+ },
+ "minimatch": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
+ "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=",
+ "requires": {
+ "brace-expansion": "1.1.0"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz",
+ "integrity": "sha1-ybfQPAPze8cEvhAOUitA249s/Nk=",
+ "requires": {
+ "balanced-match": "0.2.0",
+ "concat-map": "0.0.1"
+ },
+ "dependencies": {
+ "balanced-match": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz",
+ "integrity": "sha1-OPZzDAOqttXtu1K9k0iF51bXFnQ="
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ }
+ }
+ }
+ }
+ },
+ "once": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
+ "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=",
+ "requires": {
+ "wrappy": "1.0.1"
+ },
+ "dependencies": {
+ "wrappy": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz",
+ "integrity": "sha1-HmWWmWXMvC20VIxrhKbyxa7dRzk="
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "flagged-respawn": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-0.3.1.tgz",
+ "integrity": "sha1-OXcAkl324SRSICpx6J2JVF+7vp0="
+ },
+ "resolve": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz",
+ "integrity": "sha1-00kq0FTKgA9b76YS5hvqwe7Jj48="
+ }
+ }
+ },
+ "minimist": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz",
+ "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag="
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ }
+ }
+ },
+ "pool2": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pool2/-/pool2-1.2.0.tgz",
+ "integrity": "sha1-yrd+d9O47JTC2MWbMdFc+5MhNzI=",
+ "requires": {
+ "debug": "2.2.0",
+ "double-ended-queue": "2.1.0-0",
+ "hashmap": "2.0.3",
+ "simple-backoff": "1.0.0"
+ },
+ "dependencies": {
+ "double-ended-queue": {
+ "version": "2.1.0-0",
+ "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
+ "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw="
+ },
+ "hashmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/hashmap/-/hashmap-2.0.3.tgz",
+ "integrity": "sha1-+IlUXTb+aKtW5MUiNQCd1mEIsVM="
+ },
+ "simple-backoff": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/simple-backoff/-/simple-backoff-1.0.0.tgz",
+ "integrity": "sha1-pPopDsAZacB8oTb+i7+0Dg7zWsI="
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
+ "integrity": "sha1-9u73ZPUUyJ4rniMUanW6EGdW0j4=",
+ "requires": {
+ "core-util-is": "1.0.1",
+ "inherits": "2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ },
+ "dependencies": {
+ "core-util-is": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
+ "integrity": "sha1-awcIWu+aPMrG7lO/nT3wwVIaVTg="
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
+ },
+ "tildify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.0.0.tgz",
+ "integrity": "sha1-KgIdtej73gqPi03zetqo+x05190=",
+ "requires": {
+ "user-home": "1.1.1"
+ },
+ "dependencies": {
+ "user-home": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
+ "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA="
+ }
+ }
+ },
+ "v8flags": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.0.10.tgz",
+ "integrity": "sha1-ZKFhN06XSRAJx43vL5ZJAOltnO8=",
+ "requires": {
+ "user-home": "1.1.1"
+ },
+ "dependencies": {
+ "user-home": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
+ "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA="
+ }
+ }
+ }
+ }
+ },
+ "lodash": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
+ },
+ "mongodb": {
+ "version": "2.0.42",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.0.42.tgz",
+ "integrity": "sha1-G614E9ByXOLjvVQYDzH67dJNnlM=",
+ "requires": {
+ "es6-promise": "2.1.1",
+ "mongodb-core": "1.2.10",
+ "readable-stream": "1.0.31"
+ },
+ "dependencies": {
+ "es6-promise": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.1.1.tgz",
+ "integrity": "sha1-A+jzxyl5KOVHjWqx0GQyUVB73t0="
+ },
+ "mongodb-core": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-1.2.10.tgz",
+ "integrity": "sha1-7OFyAb05WmR/uY9Ivo+64Vvgr9k=",
+ "requires": {
+ "bson": "0.4.11",
+ "kerberos": "0.0.12"
+ },
+ "dependencies": {
+ "bson": {
+ "version": "0.4.11",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-0.4.11.tgz",
+ "integrity": "sha1-BFJVznmNLUAAH/d14N2Rdu+vJbQ="
+ },
+ "kerberos": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/kerberos/-/kerberos-0.0.12.tgz",
+ "integrity": "sha1-fSXMq3SiMlwYaxpWdhBDpHiciXI=",
+ "optional": true,
+ "requires": {
+ "nan": "1.8.4"
+ },
+ "dependencies": {
+ "nan": {
+ "version": "1.8.4",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-1.8.4.tgz",
+ "integrity": "sha1-PHa1OC6rM+RLdY0oE8qdkuk0LzQ=",
+ "optional": true
+ }
+ }
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "1.0.31",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.31.tgz",
+ "integrity": "sha1-jyUC4LyeOw2huUUgqrtOJgPsr64=",
+ "requires": {
+ "core-util-is": "1.0.1",
+ "inherits": "2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ },
+ "dependencies": {
+ "core-util-is": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
+ "integrity": "sha1-awcIWu+aPMrG7lO/nT3wwVIaVTg="
+ },
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
+ }
+ }
+ },
+ "multer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/multer/-/multer-1.0.3.tgz",
+ "integrity": "sha1-cR/vX5Tx8vDL/gAiTFhJic13ZGg=",
+ "requires": {
+ "append-field": "0.1.0",
+ "busboy": "0.2.11",
+ "concat-stream": "1.5.0",
+ "mkdirp": "0.5.1",
+ "object-assign": "3.0.0",
+ "type-is": "1.6.8",
+ "xtend": "4.0.0"
+ },
+ "dependencies": {
+ "append-field": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz",
+ "integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo="
+ },
+ "busboy": {
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.11.tgz",
+ "integrity": "sha1-GRNH/pNeWvumZVAakRwvcj07YfI=",
+ "requires": {
+ "dicer": "0.2.3",
+ "readable-stream": "1.1.13"
+ },
+ "dependencies": {
+ "dicer": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.3.tgz",
+ "integrity": "sha1-8AKBGJpVwjUe+ASQpP6fssWcSTk=",
+ "requires": {
+ "readable-stream": "1.1.13",
+ "streamsearch": "0.1.2"
+ },
+ "dependencies": {
+ "streamsearch": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
+ "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
+ "integrity": "sha1-9u73ZPUUyJ4rniMUanW6EGdW0j4=",
+ "requires": {
+ "core-util-is": "1.0.1",
+ "inherits": "2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ },
+ "dependencies": {
+ "core-util-is": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
+ "integrity": "sha1-awcIWu+aPMrG7lO/nT3wwVIaVTg="
+ },
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
+ }
+ }
+ },
+ "concat-stream": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
+ "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=",
+ "requires": {
+ "inherits": "2.0.1",
+ "readable-stream": "2.0.2",
+ "typedarray": "0.0.6"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "readable-stream": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
+ "integrity": "sha1-vsgb6ujPRVFovC5bKzH1vPrtmxs=",
+ "requires": {
+ "core-util-is": "1.0.1",
+ "inherits": "2.0.1",
+ "isarray": "0.0.1",
+ "process-nextick-args": "1.0.2",
+ "string_decoder": "0.10.31",
+ "util-deprecate": "1.0.1"
+ },
+ "dependencies": {
+ "core-util-is": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
+ "integrity": "sha1-awcIWu+aPMrG7lO/nT3wwVIaVTg="
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "process-nextick-args": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.2.tgz",
+ "integrity": "sha1-i00/xYZmi9W2Vz5zLt8rccHB2Ko="
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ },
+ "util-deprecate": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz",
+ "integrity": "sha1-NVaj0TxMaqeYPX4kJUeBlxmbeIE="
+ }
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ }
+ }
+ },
+ "object-assign": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
+ "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
+ },
+ "type-is": {
+ "version": "1.6.8",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.8.tgz",
+ "integrity": "sha1-O6yMDIUnVMhVFD4gbUoW6Qi/AxU=",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "2.1.6"
+ },
+ "dependencies": {
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "mime-types": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.6.tgz",
+ "integrity": "sha1-lJ+HiEEYZN3HCUig8hxD8p0lZnw=",
+ "requires": {
+ "mime-db": "1.18.0"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.18.0.tgz",
+ "integrity": "sha1-UxfigiTAivHUhPYJc904a6jzieA="
+ }
+ }
+ }
+ }
+ },
+ "xtend": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
+ "integrity": "sha1-i8Nv+Hrtvnzp6vC8o2sjVKdDhA8="
+ }
+ }
+ },
+ "multiparty": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-4.1.2.tgz",
+ "integrity": "sha1-VPjslxIFL6Hf2OyXUFbIIw1vI3A=",
+ "requires": {
+ "fd-slicer": "1.0.1"
+ },
+ "dependencies": {
+ "fd-slicer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
+ "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
+ "requires": {
+ "pend": "1.2.0"
+ },
+ "dependencies": {
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
+ }
+ }
+ }
+ }
+ },
+ "mysql2": {
+ "version": "0.15.8",
+ "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-0.15.8.tgz",
+ "integrity": "sha1-8WZQtvfFu1aLNFEeIbr+NtWonvE=",
+ "requires": {
+ "bn.js": "2.0.0",
+ "cardinal": "0.4.4",
+ "double-ended-queue": "2.0.0-0",
+ "named-placeholders": "0.1.3",
+ "readable-stream": "1.0.33"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-2.0.0.tgz",
+ "integrity": "sha1-glxBB/f6eJN47hsNhr4FA9esdDs="
+ },
+ "cardinal": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-0.4.4.tgz",
+ "integrity": "sha1-ylu2iltRG5D+k7ms6km97lwyv+I=",
+ "requires": {
+ "ansicolors": "0.2.1",
+ "redeyed": "0.4.4"
+ },
+ "dependencies": {
+ "ansicolors": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz",
+ "integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8="
+ },
+ "redeyed": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-0.4.4.tgz",
+ "integrity": "sha1-N+mQpvKyGyoRwuakj9QTVpjLqX8=",
+ "requires": {
+ "esprima": "1.0.4"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
+ "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0="
+ }
+ }
+ }
+ }
+ },
+ "double-ended-queue": {
+ "version": "2.0.0-0",
+ "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.0.0-0.tgz",
+ "integrity": "sha1-eEf9ocAPtyIkWv+DZDpIh2cO/Sw="
+ },
+ "named-placeholders": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-0.1.3.tgz",
+ "integrity": "sha1-NTd27iWa0QUifhOFLu9CFaxjHoQ=",
+ "requires": {
+ "lru-cache": "2.5.0"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz",
+ "integrity": "sha1-2COIrpyWC+y+oMc7uet5tsbOmus="
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "1.0.33",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+ "integrity": "sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw=",
+ "requires": {
+ "core-util-is": "1.0.1",
+ "inherits": "2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ },
+ "dependencies": {
+ "core-util-is": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
+ "integrity": "sha1-awcIWu+aPMrG7lO/nT3wwVIaVTg="
+ },
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
+ }
+ }
+ },
+ "nan": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz",
+ "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo="
+ },
+ "passport": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/passport/-/passport-0.3.0.tgz",
+ "integrity": "sha1-FMFRsOtnlaqTNSOYJ/VI1flMcEY=",
+ "requires": {
+ "passport-strategy": "1.0.0",
+ "pause": "0.0.1"
+ },
+ "dependencies": {
+ "passport-strategy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
+ "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
+ },
+ "pause": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
+ "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
+ }
+ }
+ },
+ "passport-local": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
+ "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
+ "requires": {
+ "passport-strategy": "1.0.0"
+ },
+ "dependencies": {
+ "passport-strategy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
+ "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
+ }
+ }
+ },
+ "sessionstore": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/sessionstore/-/sessionstore-1.2.5.tgz",
+ "integrity": "sha1-mH3ixYSvXKnyQNELqAeJXDVHT7c=",
+ "requires": {
+ "async": "1.4.0",
+ "jsondate": "0.0.1",
+ "lodash": "3.10.0",
+ "parent-require": "1.0.0",
+ "tolerance": "1.0.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.4.0.tgz",
+ "integrity": "sha1-Nfhvg8WeBCHQmc2akdgnj7V4wA0="
+ },
+ "jsondate": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/jsondate/-/jsondate-0.0.1.tgz",
+ "integrity": "sha1-RXqa4Bgm0Z+vfofJviY9TzqiN/w="
+ },
+ "lodash": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.0.tgz",
+ "integrity": "sha1-k9UcZygopEFqEq9XIguoqHN+L7s="
+ },
+ "parent-require": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz",
+ "integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc="
+ },
+ "tolerance": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/tolerance/-/tolerance-1.0.0.tgz",
+ "integrity": "sha1-mFFo5d0TwJ3tQUrHOGb4R7QI2mw=",
+ "requires": {
+ "retry": "0.7.0"
+ },
+ "dependencies": {
+ "retry": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.7.0.tgz",
+ "integrity": "sha1-3IbuuWCvmstmKJaRi+QlTBrPY3k="
+ }
+ }
+ }
+ }
+ },
+ "skipper": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/skipper/-/skipper-0.5.5.tgz",
+ "integrity": "sha1-ZXTSdd4tdxC8tNq1aRt4CdUQurc=",
+ "requires": {
+ "async": "0.2.10",
+ "colors": "0.6.2",
+ "connect": "2.25.10",
+ "debug": "2.2.0",
+ "dot-access": "0.0.3",
+ "lodash": "2.4.2",
+ "multiparty": "3.2.10",
+ "node-uuid": "1.4.3",
+ "semver": "2.2.1",
+ "skipper-disk": "0.5.4",
+ "string_decoder": "0.10.31"
+ },
+ "dependencies": {
+ "async": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+ "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E="
+ },
+ "colors": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
+ "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w="
+ },
+ "connect": {
+ "version": "2.25.10",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-2.25.10.tgz",
+ "integrity": "sha1-GDs7VQaax81LWf/dh8xMxff/qKc=",
+ "requires": {
+ "basic-auth-connect": "1.0.0",
+ "body-parser": "1.6.7",
+ "bytes": "1.0.0",
+ "compression": "1.0.11",
+ "connect-timeout": "1.2.2",
+ "cookie": "0.1.2",
+ "cookie-parser": "1.3.2",
+ "cookie-signature": "1.0.4",
+ "csurf": "1.4.1",
+ "debug": "1.0.4",
+ "depd": "0.4.4",
+ "errorhandler": "1.1.1",
+ "express-session": "1.7.6",
+ "finalhandler": "0.1.0",
+ "fresh": "0.2.2",
+ "media-typer": "0.2.0",
+ "method-override": "2.1.3",
+ "morgan": "1.2.3",
+ "multiparty": "3.3.2",
+ "on-headers": "1.0.0",
+ "parseurl": "1.3.0",
+ "pause": "0.0.1",
+ "qs": "2.2.2",
+ "response-time": "2.0.1",
+ "serve-favicon": "2.0.1",
+ "serve-index": "1.1.6",
+ "serve-static": "1.5.4",
+ "type-is": "1.3.2",
+ "vhost": "2.0.0"
+ },
+ "dependencies": {
+ "basic-auth-connect": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz",
+ "integrity": "sha1-/bC0OWLKe0BFanwrtI/hc9otISI="
+ },
+ "body-parser": {
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.6.7.tgz",
+ "integrity": "sha1-gjBr7K30RUPoJrOQfq6T8CN8Tlw=",
+ "requires": {
+ "bytes": "1.0.0",
+ "depd": "0.4.4",
+ "iconv-lite": "0.4.4",
+ "media-typer": "0.2.0",
+ "on-finished": "2.1.0",
+ "qs": "2.2.2",
+ "raw-body": "1.3.0",
+ "type-is": "1.3.2"
+ },
+ "dependencies": {
+ "iconv-lite": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.4.tgz",
+ "integrity": "sha1-6V8uQdsHNfwhZS94J6XuMuY8g6g="
+ },
+ "on-finished": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.1.0.tgz",
+ "integrity": "sha1-DFOfCSkej/rd4MiiWFD7LO3HAi0=",
+ "requires": {
+ "ee-first": "1.0.5"
+ },
+ "dependencies": {
+ "ee-first": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.0.5.tgz",
+ "integrity": "sha1-jJshKJjYzZ8alDZlDOe+ICyen/A="
+ }
+ }
+ },
+ "raw-body": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.3.0.tgz",
+ "integrity": "sha1-l4IwoValVI9C7vFN4i0PT2EAg9E=",
+ "requires": {
+ "bytes": "1.0.0",
+ "iconv-lite": "0.4.4"
+ }
+ }
+ }
+ },
+ "bytes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz",
+ "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g="
+ },
+ "compression": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.0.11.tgz",
+ "integrity": "sha1-aXAM8e6JY0VDVqwZKm5ekeIyv/s=",
+ "requires": {
+ "accepts": "1.0.7",
+ "bytes": "1.0.0",
+ "compressible": "1.1.1",
+ "debug": "1.0.4",
+ "on-headers": "1.0.0",
+ "vary": "1.0.1"
+ },
+ "dependencies": {
+ "accepts": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.0.7.tgz",
+ "integrity": "sha1-W1AftPBwQwmWTM2wSBclQSCNqxo=",
+ "requires": {
+ "mime-types": "1.0.2",
+ "negotiator": "0.4.7"
+ },
+ "dependencies": {
+ "mime-types": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz",
+ "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4="
+ },
+ "negotiator": {
+ "version": "0.4.7",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.7.tgz",
+ "integrity": "sha1-pBYPcXfsgGc4Yx0NMFIyXaQqvcg="
+ }
+ }
+ },
+ "compressible": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/compressible/-/compressible-1.1.1.tgz",
+ "integrity": "sha1-I7ceqQ6mxqZiiXAakYGCwk0HKe8="
+ },
+ "vary": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz",
+ "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA="
+ }
+ }
+ },
+ "connect-timeout": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/connect-timeout/-/connect-timeout-1.2.2.tgz",
+ "integrity": "sha1-WVNgK7Zqv9X6Ia6RGnIhxeglocA=",
+ "requires": {
+ "debug": "1.0.4",
+ "ms": "0.6.2",
+ "on-headers": "1.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
+ "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw="
+ }
+ }
+ },
+ "cookie": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.2.tgz",
+ "integrity": "sha1-cv7D0k5Io0Mgc9kMEmQgBQYQBLE="
+ },
+ "cookie-parser": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.2.tgz",
+ "integrity": "sha1-UiEcyCyVXXn/DAiJVEB3JOGc9WI=",
+ "requires": {
+ "cookie": "0.1.2",
+ "cookie-signature": "1.0.4"
+ }
+ },
+ "cookie-signature": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.4.tgz",
+ "integrity": "sha1-Dt0iKG46ERuaKnDbNj6SXoZ/aso="
+ },
+ "csurf": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.4.1.tgz",
+ "integrity": "sha1-DMrwJpkrLSGHcdYXT1xsQCpiif0=",
+ "requires": {
+ "cookie": "0.1.2",
+ "cookie-signature": "1.0.4",
+ "csrf": "2.0.7"
+ },
+ "dependencies": {
+ "csrf": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/csrf/-/csrf-2.0.7.tgz",
+ "integrity": "sha1-0E9S4Paiin4s/h4B3V68JRs9QgE=",
+ "requires": {
+ "base64-url": "1.2.1",
+ "rndm": "1.1.0",
+ "scmp": "1.0.0",
+ "uid-safe": "1.1.0"
+ },
+ "dependencies": {
+ "base64-url": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz",
+ "integrity": "sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg="
+ },
+ "rndm": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.1.0.tgz",
+ "integrity": "sha1-AdGo8fubRxGBkltie5BJvzMHRXQ="
+ },
+ "scmp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/scmp/-/scmp-1.0.0.tgz",
+ "integrity": "sha1-oLJyw/xykvdxFWRvAGGLAmJRTgQ="
+ },
+ "uid-safe": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-1.1.0.tgz",
+ "integrity": "sha1-WNbF2r+N+9jVKDSDmAbAP9YUMjI=",
+ "requires": {
+ "base64-url": "1.2.1",
+ "native-or-bluebird": "1.1.2"
+ },
+ "dependencies": {
+ "native-or-bluebird": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/native-or-bluebird/-/native-or-bluebird-1.1.2.tgz",
+ "integrity": "sha1-OSHhECMtHreQ89rGG7NwUxx9NW4="
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "debug": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz",
+ "integrity": "sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=",
+ "requires": {
+ "ms": "0.6.2"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
+ "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw="
+ }
+ }
+ },
+ "depd": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-0.4.4.tgz",
+ "integrity": "sha1-BwkfrnX5eCjYm0oCotR3jw58BmI="
+ },
+ "errorhandler": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.1.1.tgz",
+ "integrity": "sha1-GN79Q22Mou/gotiGxcTW7m121pE=",
+ "requires": {
+ "accepts": "1.0.7",
+ "escape-html": "1.0.1"
+ },
+ "dependencies": {
+ "accepts": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.0.7.tgz",
+ "integrity": "sha1-W1AftPBwQwmWTM2wSBclQSCNqxo=",
+ "requires": {
+ "mime-types": "1.0.2",
+ "negotiator": "0.4.7"
+ },
+ "dependencies": {
+ "mime-types": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz",
+ "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4="
+ },
+ "negotiator": {
+ "version": "0.4.7",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.7.tgz",
+ "integrity": "sha1-pBYPcXfsgGc4Yx0NMFIyXaQqvcg="
+ }
+ }
+ },
+ "escape-html": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz",
+ "integrity": "sha1-GBoobq05ejmpKFfPsdQwUuNWv/A="
+ }
+ }
+ },
+ "express-session": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.7.6.tgz",
+ "integrity": "sha1-4cNpuiF296/beed9ZdzYx8RuSKU=",
+ "requires": {
+ "buffer-crc32": "0.2.3",
+ "cookie": "0.1.2",
+ "cookie-signature": "1.0.4",
+ "debug": "1.0.4",
+ "depd": "0.4.4",
+ "on-headers": "1.0.0",
+ "parseurl": "1.3.0",
+ "uid-safe": "1.0.1",
+ "utils-merge": "1.0.0"
+ },
+ "dependencies": {
+ "buffer-crc32": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.3.tgz",
+ "integrity": "sha1-u1RRnpXRB8vSQA520MqxRnM22SE="
+ },
+ "uid-safe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-1.0.1.tgz",
+ "integrity": "sha1-W9FIRgouhPVPGT/SA1LIw9feasg=",
+ "requires": {
+ "base64-url": "1.2.1",
+ "mz": "1.3.0"
+ },
+ "dependencies": {
+ "base64-url": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz",
+ "integrity": "sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg="
+ },
+ "mz": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-1.3.0.tgz",
+ "integrity": "sha1-BvCT/dmVagbTfhsegTROJ0eMQvA=",
+ "requires": {
+ "native-or-bluebird": "1.2.0",
+ "thenify": "3.1.0",
+ "thenify-all": "1.6.0"
+ },
+ "dependencies": {
+ "native-or-bluebird": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/native-or-bluebird/-/native-or-bluebird-1.2.0.tgz",
+ "integrity": "sha1-OcR7/Xgl0fuf+tMiEK4l2q3xAck="
+ },
+ "thenify": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.1.0.tgz",
+ "integrity": "sha1-wny7xit8KH7fGho9XMhCbYrtSfA=",
+ "requires": {
+ "native-or-bluebird": "1.2.0"
+ }
+ },
+ "thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
+ "requires": {
+ "thenify": "3.1.0"
+ }
+ }
+ }
+ }
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
+ "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
+ }
+ }
+ },
+ "finalhandler": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.1.0.tgz",
+ "integrity": "sha1-2gW7xPX0owyEzh2R88FUAHxOnao=",
+ "requires": {
+ "debug": "1.0.4",
+ "escape-html": "1.0.1"
+ },
+ "dependencies": {
+ "escape-html": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz",
+ "integrity": "sha1-GBoobq05ejmpKFfPsdQwUuNWv/A="
+ }
+ }
+ },
+ "fresh": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.2.tgz",
+ "integrity": "sha1-lzHc9WeMf660T7kDxPct9VGH+nc="
+ },
+ "media-typer": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.2.0.tgz",
+ "integrity": "sha1-2KBlITrf6qLnYyGitt2jb/YzWYQ="
+ },
+ "method-override": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/method-override/-/method-override-2.1.3.tgz",
+ "integrity": "sha1-UR9BxPsdzNtqsYRNpdxuqBt8ETU=",
+ "requires": {
+ "debug": "1.0.4",
+ "methods": "1.1.0",
+ "parseurl": "1.3.0",
+ "vary": "1.0.1"
+ },
+ "dependencies": {
+ "methods": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.0.tgz",
+ "integrity": "sha1-XcpO4S31L/OwVhRZhqjwHLyGQ28="
+ },
+ "vary": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz",
+ "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA="
+ }
+ }
+ },
+ "morgan": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.2.3.tgz",
+ "integrity": "sha1-Ow8XBN+QJVpUJZGrrNeXiRqMQKE=",
+ "requires": {
+ "basic-auth": "1.0.0",
+ "bytes": "1.0.0",
+ "depd": "0.4.4",
+ "on-finished": "2.1.0"
+ },
+ "dependencies": {
+ "basic-auth": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.0.tgz",
+ "integrity": "sha1-ERstn/jk5tE2uMhOpeCWy4c1Fjc="
+ },
+ "on-finished": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.1.0.tgz",
+ "integrity": "sha1-DFOfCSkej/rd4MiiWFD7LO3HAi0=",
+ "requires": {
+ "ee-first": "1.0.5"
+ },
+ "dependencies": {
+ "ee-first": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.0.5.tgz",
+ "integrity": "sha1-jJshKJjYzZ8alDZlDOe+ICyen/A="
+ }
+ }
+ }
+ }
+ },
+ "multiparty": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-3.3.2.tgz",
+ "integrity": "sha1-Nd5oBNwZZD5SSfPT473GyM4wHT8=",
+ "requires": {
+ "readable-stream": "1.1.13",
+ "stream-counter": "0.2.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
+ "integrity": "sha1-9u73ZPUUyJ4rniMUanW6EGdW0j4=",
+ "requires": {
+ "core-util-is": "1.0.1",
+ "inherits": "2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ },
+ "dependencies": {
+ "core-util-is": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
+ "integrity": "sha1-awcIWu+aPMrG7lO/nT3wwVIaVTg="
+ },
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ }
+ }
+ },
+ "stream-counter": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz",
+ "integrity": "sha1-3tJmVWMZyLDiIoErnPOyb6fZR94=",
+ "requires": {
+ "readable-stream": "1.1.13"
+ }
+ }
+ }
+ },
+ "on-headers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.0.tgz",
+ "integrity": "sha1-LHW12kN1UT0BYcYFLn/L5JU/yl0="
+ },
+ "parseurl": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.0.tgz",
+ "integrity": "sha1-tYBG20Ij4UWvp2AJ5hush8wigbM="
+ },
+ "pause": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
+ "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
+ },
+ "qs": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-2.2.2.tgz",
+ "integrity": "sha1-3+eD8YVLGsKzreknda0D4n4DIYw="
+ },
+ "response-time": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.0.1.tgz",
+ "integrity": "sha1-xtLLrerEyyUbIQFv4YJkDAKv80M=",
+ "requires": {
+ "on-headers": "1.0.0"
+ }
+ },
+ "serve-favicon": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.0.1.tgz",
+ "integrity": "sha1-SCaXXZ8XPKOkFY6WmBYfdd7Hr+w=",
+ "requires": {
+ "fresh": "0.2.2"
+ }
+ },
+ "serve-index": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.1.6.tgz",
+ "integrity": "sha1-t1gxj+eBYoOD9mrIDdRHcS6neB8=",
+ "requires": {
+ "accepts": "1.0.7",
+ "batch": "0.5.1",
+ "parseurl": "1.3.0"
+ },
+ "dependencies": {
+ "accepts": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.0.7.tgz",
+ "integrity": "sha1-W1AftPBwQwmWTM2wSBclQSCNqxo=",
+ "requires": {
+ "mime-types": "1.0.2",
+ "negotiator": "0.4.7"
+ },
+ "dependencies": {
+ "mime-types": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz",
+ "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4="
+ },
+ "negotiator": {
+ "version": "0.4.7",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.7.tgz",
+ "integrity": "sha1-pBYPcXfsgGc4Yx0NMFIyXaQqvcg="
+ }
+ }
+ },
+ "batch": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.1.tgz",
+ "integrity": "sha1-NqS6tZTAUP17UHvKDbMMLZKvT/I="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.5.4.tgz",
+ "integrity": "sha1-gZ+zeuRr0C3VILd/z3/Y9REvl4I=",
+ "requires": {
+ "escape-html": "1.0.1",
+ "parseurl": "1.3.0",
+ "send": "0.8.5",
+ "utils-merge": "1.0.0"
+ },
+ "dependencies": {
+ "escape-html": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz",
+ "integrity": "sha1-GBoobq05ejmpKFfPsdQwUuNWv/A="
+ },
+ "send": {
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.8.5.tgz",
+ "integrity": "sha1-N/cIIW5vUMF150xp/sU0hOL9gsc=",
+ "requires": {
+ "debug": "1.0.4",
+ "depd": "0.4.4",
+ "destroy": "1.0.3",
+ "escape-html": "1.0.1",
+ "fresh": "0.2.2",
+ "mime": "1.2.11",
+ "ms": "0.6.2",
+ "on-finished": "2.1.0",
+ "range-parser": "1.0.2"
+ },
+ "dependencies": {
+ "destroy": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz",
+ "integrity": "sha1-tDO0ck5x/YVR2YhRdIUcX8N34sk="
+ },
+ "mime": {
+ "version": "1.2.11",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
+ "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA="
+ },
+ "ms": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
+ "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw="
+ },
+ "on-finished": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.1.0.tgz",
+ "integrity": "sha1-DFOfCSkej/rd4MiiWFD7LO3HAi0=",
+ "requires": {
+ "ee-first": "1.0.5"
+ },
+ "dependencies": {
+ "ee-first": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.0.5.tgz",
+ "integrity": "sha1-jJshKJjYzZ8alDZlDOe+ICyen/A="
+ }
+ }
+ },
+ "range-parser": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.2.tgz",
+ "integrity": "sha1-BqEqQuUTG6jkV82JIESGfyNE5Uk="
+ }
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
+ "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
+ }
+ }
+ },
+ "type-is": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.3.2.tgz",
+ "integrity": "sha1-TypdxYd1yhYwJQr8cYb4s2MJ0bs=",
+ "requires": {
+ "media-typer": "0.2.0",
+ "mime-types": "1.0.2"
+ },
+ "dependencies": {
+ "mime-types": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz",
+ "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4="
+ }
+ }
+ },
+ "vhost": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/vhost/-/vhost-2.0.0.tgz",
+ "integrity": "sha1-HiZ3C9D86GxAlFWR5vKExokXkeI="
+ }
+ }
+ },
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
+ "dot-access": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/dot-access/-/dot-access-0.0.3.tgz",
+ "integrity": "sha1-Atsha7+VjQ+MUvoGXMfdiLXAajQ="
+ },
+ "lodash": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
+ "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4="
+ },
+ "multiparty": {
+ "version": "3.2.10",
+ "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-3.2.10.tgz",
+ "integrity": "sha1-+JghtveRKb8R/5v5NPSRHew9KcM=",
+ "requires": {
+ "readable-stream": "1.1.13",
+ "stream-counter": "0.2.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
+ "integrity": "sha1-9u73ZPUUyJ4rniMUanW6EGdW0j4=",
+ "requires": {
+ "core-util-is": "1.0.1",
+ "inherits": "2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ },
+ "dependencies": {
+ "core-util-is": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
+ "integrity": "sha1-awcIWu+aPMrG7lO/nT3wwVIaVTg="
+ },
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ }
+ }
+ },
+ "stream-counter": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz",
+ "integrity": "sha1-3tJmVWMZyLDiIoErnPOyb6fZR94=",
+ "requires": {
+ "readable-stream": "1.1.13"
+ }
+ }
+ }
+ },
+ "node-uuid": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz",
+ "integrity": "sha1-MZu3pW58tj8AtcDNeFHNS03fHfk="
+ },
+ "semver": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-2.2.1.tgz",
+ "integrity": "sha1-eUEYKz/8xYC/8cF5QqzfeVHA0hM="
+ },
+ "skipper-disk": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/skipper-disk/-/skipper-disk-0.5.4.tgz",
+ "integrity": "sha1-7UGstFNKPxuA602ZZfp2sDGou6c=",
+ "requires": {
+ "debug": "2.2.0",
+ "fs-extra": "0.8.1",
+ "lodash": "2.4.2",
+ "node-uuid": "1.4.3"
+ },
+ "dependencies": {
+ "fs-extra": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.8.1.tgz",
+ "integrity": "sha1-Dld5/7/t9RG8dVWVx/A8BtS0Po0=",
+ "requires": {
+ "jsonfile": "1.1.1",
+ "mkdirp": "0.3.5",
+ "ncp": "0.4.2",
+ "rimraf": "2.2.8"
+ },
+ "dependencies": {
+ "jsonfile": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.1.1.tgz",
+ "integrity": "sha1-2k/WrXfxolUgPqY8e8Mtwx72RDM="
+ },
+ "mkdirp": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
+ "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc="
+ },
+ "ncp": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz",
+ "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ="
+ },
+ "rimraf": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
+ "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI="
+ }
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index fa4f441..993f57e 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"author": "",
"license": "LNT",
"dependencies": {
+ "berkeleydb": "^0.2.1",
"body-parser": "^1.13.3",
"bookshelf": "^0.8.2",
"cookie-parser": "^1.3.5",
diff --git a/public/assets/css/bucky.css b/public/assets/css/bucky.css
index 9da79e5..c791ca1 100644
--- a/public/assets/css/bucky.css
+++ b/public/assets/css/bucky.css
@@ -17,7 +17,7 @@ label {
text-align: right;
padding-right: 5px;
}
-button {
+button, input[type=submit] {
font-size: 10px;
font-family: Trebuchet MS, Helvetica, Arial, sans-serif;
font-weight: bold;
@@ -28,7 +28,8 @@ button {
background-color: #c8d0dc;
text-transform: uppercase;
}
-.desktop button:hover {
+.desktop button:hover,
+.desktop input[type=submit] {
color: #040a0a;
background-color: #d8ece0;
}
@@ -134,28 +135,48 @@ table, tr {
#hoots tr:nth-child(odd) td:nth-child(2) { background-color: #f3f1f2; }
#hoots tr:nth-child(even) td:nth-child(2) { background-color: #e3e8e3; }
-#threads th {
+#threads .keyword td {
vertical-align: top;
font-weight: normal;
padding-right: 4px;
line-height: 15px;
+ padding-top: 10px;
}
-#threads th b {
+#threads .keyword:first-child td {
+ padding-top: 5px;
+}
+#threads .keyword td:first-child {
+ text-align: right;
+}
+#threads .keyword td b {
font-weight: bold;
font-size: 14px;
}
+#threads .keyword:first-child td:nth-child(2) {
+ border-top: 0;
+}
+#threads .keyword td:nth-child(2) {
+ border-top: 1px solid #b3b3b3;
+ border-bottom: 1px solid #b3b3b3;
+}
+#threads .row:last-child td:nth-child(2) {
+ border-bottom: 1px solid #b3b3b3;
+}
-.ledger td {
+.ledger {
+ width: 100%;
+}
+.ledger .row td {
text-align: right;
padding-left: 4px;
padding-right: 4px;
}
-.ledger td:nth-child(1) a {
+.ledger .row td:nth-child(1) a {
margin-left: 10px;
color: #444;
text-decoration: none;
}
-.ledger td:nth-child(2) {
+.ledger .row td:nth-child(2) {
text-align: left;
font-family: Georgia, serif;
font-size: 120%;
@@ -166,10 +187,10 @@ table, tr {
max-width: 30vw;
white-space: nowrap;
}
-.ledger tr:first-child td:nth-child(2) {
+.ledger tr.row:first-child td:nth-child(2) {
border-top: 1px solid #b6aeab;
}
-.ledger tr:last-child td:nth-child(2) {
+.ledger tr.row:last-child td:nth-child(2) {
border-bottom: 1px solid #b6aeab;
}
.ledger td:nth-child(2) a {
@@ -179,10 +200,10 @@ table, tr {
text-align: center;
}
-tr:nth-child(odd).row td { background-color: #e6f0f0; }
-tr:nth-child(odd).row:hover td { background-color: #d8e0ec; color: #000000; }
-tr:nth-child(even).row td { background-color: #e0e8e8; }
-tr:nth-child(even).row:hover td { background-color: #d8e0ec; color: #000000; }
+tr:nth-child(odd).file td { background-color: #e6f0f0; }
+tr:nth-child(odd).file:hover td { background-color: #d8e0ec; color: #000000; }
+tr:nth-child(even).file td { background-color: #e0e8e8; }
+tr:nth-child(even).file:hover td { background-color: #d8e0ec; color: #000000; }
tr:nth-child(odd) td.row { background-color: #e6f0f0; }
tr:nth-child(odd) td.row:hover { background-color: #d8e0ec; color: #000000; }
@@ -251,10 +272,6 @@ tr:nth-child(even) td.black:hover { background-color: #f8f8f8; color: #000000;
.older { color: #5D6464; }
.quiet { color: #787878; }
-#details .left {
- padding-right: 20px;
- vertical-align: top;
-}
#details_rapper {
width: 100%;
text-align: center;
@@ -262,6 +279,11 @@ tr:nth-child(even) td.black:hover { background-color: #f8f8f8; color: #000000;
#details {
display: inline-block;
text-align: left;
+ width: 100%;
+}
+#details .left {
+ vertical-align: top;
+ max-width: 50%;
}
#details .right {
max-width: 50vw;
@@ -273,6 +295,13 @@ tr:nth-child(even) td.black:hover { background-color: #f8f8f8; color: #000000;
border-bottom: 1px solid #ccc;
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
+ min-width: 450px;
+}
+#comments {
+ width: 600px;
+}
+#comments tr {
+ padding-right: 20px;
}
#comments tr .user {
margin: 0;
@@ -281,8 +310,14 @@ tr:nth-child(even) td.black:hover { background-color: #f8f8f8; color: #000000;
font-size: 11px;
vertical-align: top;
}
-#comments tr .user img {
+#comments tr .user .avatar {
border: 1px solid;
+ width: 40px;
+ height: 40px;
+ background-size: cover;
+ margin: 0 auto;
+ margin-bottom: 2px;
+ background-position: center center;
}
#comments tr:first-child .comment {
border-top: 1px solid #ccc;
@@ -300,6 +335,23 @@ tr:nth-child(even) td.black:hover { background-color: #f8f8f8; color: #000000;
tr:nth-child(even) td.comment { background-color: #f3f1f2; }
tr:nth-child(odd) td.comment { background-color: #fcf8f8; }
+#comment_form form {
+ width: 530px;
+ margin-top: 5px;
+ margin-left: 50px;
+ padding-right: 10px;
+}
+#comment_form textarea {
+ width: 100%;
+ height: 240px;
+ font-family: 'Trebuchet MS', sans-serif;
+ padding: 5px;
+ font-size: 15px;
+}
+#comment_form input[type=submit] {
+ float: right;
+}
+
#files, #files tr {
margin: 0; padding: 0;
border-spacing: 0;
@@ -338,10 +390,32 @@ tr:nth-child(odd) td.comment { background-color: #fcf8f8; }
text-align: center;
padding: 0 0 12px 0;
}
+#gallery .thumb {
+ max-width: 150px;
+}
#messages {
width: 100%;
}
+#messages tr td:nth-child(1) {
+ text-align: right;
+ padding-right: 3px;
+}
+#messages tr td:nth-child(2) {
+ padding: 5px;
+ border-left: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+}
+#messages tr td:nth-child(3) {
+ text-align: center;
+ padding-left: 3px;
+}
+#messages tr:first-child td:nth-child(2) {
+ border-top: 1px solid #ccc;
+}
+#messages tr:last-child td:nth-child(2) {
+ border-bottom: 1px solid #ccc;
+}
#boxes table {
width: 200px;
font-size: 13px;
@@ -377,7 +451,7 @@ tr:nth-child(odd) td.comment { background-color: #fcf8f8; }
line-height: 15px;
padding: 20px;
}
-@media (max-width: 1024px) {
+@media (max-width: 700px) {
#threads td:nth-child(3) small {
display: none;
}
diff --git a/public/assets/js/lib/views/details/commentform.js b/public/assets/js/lib/views/details/commentform.js
new file mode 100644
index 0000000..30671f2
--- /dev/null
+++ b/public/assets/js/lib/views/details/commentform.js
@@ -0,0 +1,33 @@
+var CommentForm = FormView.extend({
+
+ el: "#comment_form",
+
+ events: {
+ },
+
+ action: "/api/thread/1/comment",
+
+ initialize: function(){
+ this.__super__.initialize.call(this)
+ this.template = this.$(".template").html()
+ this.$comment = this.$("[name=comment]")
+ },
+
+ load: function(thread){
+ this.action = "/api/thread/" + thread.id + "/comment"
+ },
+
+ validate: function(){
+ var errors = []
+ var comment = $("[name=comment]").val()
+ if (! comment || ! comment.length) {
+ errors.push("Please enter a comment.")
+ }
+ return errors.length ? errors : null
+ },
+
+ success: function(comment){
+ this.prependComment(comment)
+ this.$("[name=comment]").val("")
+ }
+}) \ No newline at end of file
diff --git a/public/assets/js/lib/views/details/index.js b/public/assets/js/lib/views/details/index.js
index 554c475..cd8045a 100644
--- a/public/assets/js/lib/views/details/index.js
+++ b/public/assets/js/lib/views/details/index.js
@@ -6,11 +6,14 @@ var DetailsView = View.extend({
action: "/api/thread/",
keywordAction: "/api/keyword/",
+
initialize: function(opt){
this.comments = new CommentsView ({ parent: this })
this.files = new FilesView ({ parent: this })
this.gallery = new GalleryView ({ parent: this })
+ this.form = new CommentForm ({ parent: this })
this.threadbox = new ThreadBox ({ parent: this })
+ this.metadataTemplate = $(".metadata_template").html()
},
load: function(id){
@@ -19,7 +22,18 @@ var DetailsView = View.extend({
},
populate: function(data){
- $("h1").html(data.thread.title)
+ var thread = data.thread
+ $("h1").html(thread.title)
+ var datetime = verbose_date(thread.createdate, true)
+ var age = get_age(thread.lastmodified, true)
+ var t = this.metadataTemplate
+ .replace(/{{ username }}/g, thread.username)
+ .replace(/{{ date }}/g, datetime[0])
+ .replace(/{{ time }}/g, datetime[1])
+ .replace(/{{ active }}/g, age + " ago")
+ .replace(/{{ views }}/g, thread.viewed + " view" + courtesy_s(thread.viewed))
+ $(".metadata").html(t)
+ this.form.load(data.thread)
this.comments.load(data.comments)
this.files.load(data.files)
this.gallery.load(data.files)
diff --git a/public/assets/js/lib/views/index/hootbox.js b/public/assets/js/lib/views/index/hootbox.js
index 4a23d32..cdd3eb0 100644
--- a/public/assets/js/lib/views/index/hootbox.js
+++ b/public/assets/js/lib/views/index/hootbox.js
@@ -33,24 +33,18 @@ var HootBox = FormView.extend({
var $el = $( this.parse(comment) )
this.$hoots.append($el)
},
-
+
validate: function(){
var errors = []
- if (! this.$comment.val()) {
- errors.push("no comment")
- return errors
+ var comment = $("[name=comment]").val()
+ if (! comment || ! comment.length) {
+ errors.push("Please enter a comment.")
}
- return null
- },
-
- beforeSend: function(){
- this.$comment.val("")
+ return errors.length ? errors : null
},
-
- showErrors: function(){
- },
-
- success: function(data){
- this.prependComment(data.comment)
+
+ success: function(comment){
+ this.prependComment(comment)
+ this.$("[name=comment]").val("")
}
}) \ No newline at end of file
diff --git a/public/assets/js/lib/views/index/index.js b/public/assets/js/lib/views/index/index.js
index a1e8af5..d66ea1c 100644
--- a/public/assets/js/lib/views/index/index.js
+++ b/public/assets/js/lib/views/index/index.js
@@ -8,7 +8,7 @@ var IndexView = View.extend({
initialize: function(opt){
// opt.parent = parent
this.hootbox = new HootBox ({ parent: this })
- this.threadbox = new ThreadBox ({ parent: this })
+ this.threadbox = new ThreadBox ({ parent: this, latest: true })
this.lastlog = new LastLog ({ parent: this })
this.load()
},
diff --git a/public/assets/js/lib/views/index/threadbox.js b/public/assets/js/lib/views/index/threadbox.js
index 0475382..8d8cb02 100644
--- a/public/assets/js/lib/views/index/threadbox.js
+++ b/public/assets/js/lib/views/index/threadbox.js
@@ -12,13 +12,30 @@ var ThreadBox = View.extend({
load: function(data){
if (data.keyword) {
- var $row = this.parseKeyword(data.keyword)
- this.$el.append($row)
+ this.appendKeyword(data.keyword)
+ data.threads.forEach(this.appendThread.bind(this))
+ }
+ else if (this.options.latest) {
+ data.threads.sort( (a,b) => {
+ return b.lastmodified - a.lastmodified
+ }).slice(0, 50).forEach(this.appendThread.bind(this))
+ }
+ else {
+ var keywords = {}
+ data.threads.forEach((thread) => {
+ var keyword = thread.keyword || '__unsorted'
+ keywords[keyword] = keywords[keyword] || []
+ keywords[keyword].push(thread)
+ })
+ Object.keys(keywords).sort().forEach((keyword) => {
+ this.appendKeyword({ keyword })
+ keywords[keyword].forEach(this.appendThread.bind(this))
+ })
}
- data.threads.forEach(this.appendThread.bind(this))
},
parse: function(thread){
+ if (thread.comment_count === undefined) return ""
var views = hush_views(thread.viewed)
var size = hush_size(thread.size)
var comments = hush_null(thread.comment_count, "c")
@@ -65,4 +82,8 @@ var ThreadBox = View.extend({
this.$el.append($row)
},
+ appendKeyword: function(keyword){
+ var $row = $( this.parseKeyword(keyword) )
+ this.$el.append($row)
+ },
})
diff --git a/public/assets/js/util/format.js b/public/assets/js/util/format.js
index 501108a..889ab09 100644
--- a/public/assets/js/util/format.js
+++ b/public/assets/js/util/format.js
@@ -132,7 +132,7 @@ function hush_null (n, unit, no_bold) {
}
}
-function courtesy_s (n, s) { return v == 1 ? "" : (s || "s") }
+function courtesy_s (n, s) { return n == 1 ? "" : (s || "s") }
var revision_letters = "z a b c d f g h j k l m n p q r s t v w x y".split(" ")
function get_revision (thread) {
@@ -207,10 +207,11 @@ function make_link(file){
}
function make_thumb(file){
if (file.filename.indexOf("http") !== 0) {
- return "//carbonpictures.com/bucky/data/" + file.thread + "/.thumb/t." + file.filename.toLowerCase()
+ return "//carbonpictures.com/bucky/data/" + file.thread + "/" + file.filename
}
else {
- var partz = file.filename.toLowerCase().split("/")
- return partz.splice(partz.length-2, 0, ".thumb").join("/")
+ return "//carbonpictures.com/bucky/data/" + file.thread + "/" + file.filename
+ // var partz = file.filename.toLowerCase().split("/")
+ // return partz.splice(partz.length-2, 0, ".thumb").join("/")
}
} \ No newline at end of file
diff --git a/public/assets/js/vendor/view/formview.js b/public/assets/js/vendor/view/formview.js
index 7e77500..2c54d3e 100644
--- a/public/assets/js/vendor/view/formview.js
+++ b/public/assets/js/vendor/view/formview.js
@@ -53,10 +53,10 @@ var FormView = View.extend({
}
});
-// if (! hasCSRF) {
-// fd.append("_csrf", $("[name=_csrf]").attr("value"))
-// }
-//
+ if (! hasCSRF) {
+ fd.append("_csrf", $("[name=_csrf]").attr("value"))
+ }
+
return fd
},
@@ -64,7 +64,7 @@ var FormView = View.extend({
e && e.preventDefault()
this.$errors.hide().css("opacity", 0.0);
-
+
if (this.validate) {
var errors = this.validate()
if (errors && errors.length) {
@@ -103,13 +103,11 @@ var FormView = View.extend({
}
return
}
- else {
- if (successCallback) {
- successCallback(response)
- }
- if (this.success) {
- this.success(response)
- }
+ if (successCallback) {
+ successCallback(response)
+ }
+ if (this.success) {
+ this.success(response)
}
}.bind(this),
error: function(response){
@@ -141,4 +139,4 @@ var ModalFormView = ModalView.extend(FormView.prototype).extend({
})
-*/ \ No newline at end of file
+*/
diff --git a/public/assets/js/vendor/view/view.js b/public/assets/js/vendor/view/view.js
index 9a8ab5b..82e5117 100644
--- a/public/assets/js/vendor/view/view.js
+++ b/public/assets/js/vendor/view/view.js
@@ -4,6 +4,7 @@ var View = (function($, _){
this._id = _.uniqueId('view')
this.type = "view"
options || (options = {});
+ this.options = options
_.extend(this, _.pick(options, viewOptions))
this._ensureElement()
this.initialize.apply(this, arguments)
diff --git a/search/bin/build-autocomplete b/search/bin/build-autocomplete
new file mode 100755
index 0000000..d9a62fd
--- /dev/null
+++ b/search/bin/build-autocomplete
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+use lib "../lib";
+use Bucky;
+use Bucky::Search;
+use Data::Dumper;
+use DB_File;
+
+my $file = "auto.db";
+
+my $search = new Bucky::Search;
+
+my $index = $search->index;
+my $auto_index = $search->auto_index_write;
+
+my $partials = {};
+my $partials_with_media = {};
+foreach my $word (keys %$index)
+ {
+ # goatse operator
+ my $count =()= $index->{$word} =~ /,/g;
+
+ next unless $word;
+
+ my $par = '';
+ my @letters = split "", $word;
+ for (my $i = 0; $i < scalar @letters; $i++)
+ {
+ $par .= $letters[$i];
+ if (! exists $partials->{$par} || $partials->{$par}->[0] < $count)
+ {
+ $partials->{$par} = [$count,$word];
+ }
+ }
+ }
+# don't autocomplete if we match a word
+foreach my $word (keys %$index)
+ {
+ $partials->{$word}->[1] = $word
+ }
+
+foreach my $par (sort keys %$partials)
+ {
+ $auto_index->{$par} = $partials->{$par}->[1];
+ }
+$search->auto_index_close;
+
+print "NEW: " ; system("/bin/ls", "-l", "./$file");
+print "OLD: " ; system("/bin/ls", "-l", "../cgi-bin/$file");
+system("/bin/mv", "../cgi-bin/$file", "../cgi-bin/$file.1");
+system("/bin/mv", "./$file", "../cgi-bin/$file");
+
+exit;
+
diff --git a/search/bin/build-index b/search/bin/build-index
new file mode 100755
index 0000000..b838924
--- /dev/null
+++ b/search/bin/build-index
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+use strict;
+use lib "../lib";
+use Bucky;
+use DB_File;
+#require Time::Stopwatch;
+tie my $timer, 'Time::Stopwatch';
+
+print_timer($timer, "Initialized");
+
+my $bucky = new Bucky::Search;
+
+my $keywords = $bucky->db->select("keyword");
+my $threads = $bucky->db->select("thread", {"id > 1"});
+my $files = $bucky->db->select("file");
+my $comments = $bucky->db->select("comment", {"thread > 1"});
+
+print_timer($timer, "Loaded mysql");
+
+my $lexicon = {};
+my $total = 0;
+#foreach my $keyword (@$keywords)
+# {
+# my $id = $keyword->{$id};
+# $lexicon->{ $keyword->{'keyword'} }++;
+# $total++;
+# }
+foreach my $thread (@$threads)
+ {
+ $total += parse_terms({ string => $thread->{'title'}, thread => $thread->{'id'} });
+ }
+foreach my $comment (@$comments)
+ {
+ $total += parse_terms({ string => $comment->{'comment'}, thread => $comment->{'thread'}, comment => $comment->{'id'} });
+ }
+foreach my $file (@$files)
+ {
+ $total += parse_terms({ string => $file->{'filename'}, thread => $file->{'thread'}, file => $file->{'id'} });
+ }
+
+print_timer($timer, "Created index");
+
+my $unique = scalar keys %$lexicon;
+print "--- WORD COUNT: " . $total . "\n";
+print "--- UNIQUE WORDS: " . $unique . "\n";
+
+$bucky->lexicon_store($lexicon);
+
+my $file = $bucky->index_filename;
+
+print_timer($timer, "Dumped $file");
+
+print "NEW: " ; system("/bin/ls", "-l", "./$file");
+print "OLD: " ; system("/bin/ls", "-l", "../cgi-bin/$file");
+system("/bin/mv", "../cgi-bin/$file", "../cgi-bin/$file.1");
+system("/bin/cp", "./$file", "../cgi-bin/$file");
+system("/usr/bin/perl", "./build-autocomplete");
+exit;
+
+sub parse_terms
+ {
+ my ($args) = @_;
+ my $thread = $args->{'thread'} || return;
+ my $comment = $args->{'comment'} || '0';
+ my $file = $args->{'file'} || '0';
+ my $string = $args->{'string'};
+ $string =~ s/_/ /g;
+ my @terms = split /(\W+)/, $string;
+ my $count = 0;
+ foreach my $term (@terms)
+ {
+ if ( $term !~ /\W/ )
+ {
+ my $t = lc($term);
+ $lexicon->{$t} ||= {};
+ $lexicon->{$t}->{$thread} ||= {};
+ $lexicon->{$t}->{$thread}->{'thread'} ||= $thread;
+ $lexicon->{$t}->{$thread}->{'comment'} ||= $comment;
+ $lexicon->{$t}->{$thread}->{'file'} ||= $file;
+ # give terms in title an extra bump
+ if ($comment eq '0' && $file eq '0')
+ { $lexicon->{$t}->{$thread}->{'strength'} += 2; }
+ else
+ { $lexicon->{$t}->{$thread}->{'strength'} += 1; }
+ $count++;
+ }
+ }
+ return $count;
+ }
+
+sub print_timer
+ { print STDERR sprintf "%3.2f s %s\n", shift, shift; }
+
+################################################3
+
+package Time::Stopwatch;
+my $VERSION = '1.00';
+
+use strict;
+use constant HIRES => eval { local $SIG{__DIE__}; require Time::HiRes };
+
+sub TIESCALAR {
+ my $pkg = shift;
+ my $time = (HIRES ? Time::HiRes::time() : time()) - (@_ ? shift() : 0);
+ bless \$time, $pkg;
+}
+
+sub FETCH { (HIRES ? Time::HiRes::time() : time()) - ${$_[0]}; }
+sub STORE { ${$_[0]} = (HIRES ? Time::HiRes::time() : time()) - $_[1]; }
+
+1;
+
diff --git a/search/bin/build-splashes b/search/bin/build-splashes
new file mode 100755
index 0000000..d5fd5c1
--- /dev/null
+++ b/search/bin/build-splashes
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+
+my $TEMPLATE_DIR = "../template";
+my $BASE_DIR = "/var/www/vhosts/carbonpictures.com/httpdocs/splash";
+my $OUT_FILE = "/var/www/vhosts/carbonpictures.com/httpdocs/splash/index.html";
+my @ab = qw[b c d f g h j k l m n p q r s t v w x y z];
+unshift @ab, undef;
+
+# disabled for now
+# build_site(read_splashes());
+
+sub build_site
+ {
+ my ($years) = @_;
+ carp("Building site!");
+ my $t_page = slurp_template("splash_list_page");
+ my $t_year = slurp_template("splash_year");
+ my $t_month = slurp_template("splash_month");
+ my $t_day = slurp_template("splash_day");
+ my $yeas = "";
+ foreach my $year (sort keys %$years)
+ {
+ carp($year);
+ my $mons = "";
+ foreach my $month (sort keys %{ $years->{$year} })
+ {
+ my $days = "";
+ foreach my $day (sort {$a cmp $b} keys %{ $years->{$year}->{$month} })
+ {
+ my $d = $years->{$year}->{$month}->{$day};
+ $days .= templatize($t_day, $d);
+ }
+ $mons .= templatize($t_month, { month => $month, days => $days });
+ }
+ $yeas .= templatize($t_year, { year => "20".$year, months => $mons });
+ }
+ my $page = templatize($t_page, { years => $yeas } );
+ vomit($OUT_FILE, $page);
+ }
+sub templatize
+ {
+ my ($t, $o) = @_;
+ while ($t =~ /\%\%([^\%]+)\%\%/)
+ {
+ my $val = $o->{lc $1};
+ $t =~ s/\%\%$1\%\%/$val/g;
+ }
+ return $t;
+ }
+sub read_splashes
+ {
+ my $years = {};
+ foreach my $y (grep /^\d/, slurp_dir($BASE_DIR))
+ {
+ my $months = {};
+ $years->{$y} = $months;
+ foreach my $m (grep /^\d/, slurp_dir("$BASE_DIR/$y"))
+ {
+ my $days = {};
+ $months->{$m} = $days;
+ foreach my $d (grep /^\d/, slurp_dir("$BASE_DIR/$y/$m"))
+ {
+ my $abi = 0;
+ foreach my $f (sort grep /html$/, slurp_dir("$BASE_DIR/$y/$m/$d"))
+ {
+ my $is_index = $f eq "index.html";
+ if ($is_index)
+ { $k = $d; }
+ else
+ { $k = "$d".$ab[$abi++]; }
+ my $d =
+ {
+ key => $k,
+ url => "/splash/$y/$m/$d/" . ($is_index ? undef : $f),
+ };
+ $days->{$k} = $d;
+ }
+ }
+ }
+ }
+ return $years;
+ }
+
+sub slurp_dir
+ {
+ my ($d) = @_;
+ my @files;
+ opendir D, $d;
+ while (my $f = readdir(D))
+ { push(@files,$f) if $f !~ /^\./; }
+ closedir D;
+ return @files;
+ }
+sub slurp_template
+ { return slurp(join "/", $TEMPLATE_DIR, @_); }
+sub slurp
+ {
+ my ($f) = @_;
+ open F, $f; my @lines = <F>; close F;
+ return join "", @lines;
+ }
+sub vomit
+ {
+ my ($f, $t) = @_;
+ carp("Writing $f");
+ open F, ">", $f || die "couldn't open $f : $!"; print F $t; close F;
+ }
+sub carp
+ {
+ my ($m) = @_;
+ print STDERR $m . "\n";
+ }
diff --git a/search/bin/fix-files b/search/bin/fix-files
new file mode 100644
index 0000000..b56d377
--- /dev/null
+++ b/search/bin/fix-files
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+use strict;
+use lib "../lib";
+use Bucky;
+
+my $bucky = new Bucky;
+my $file_list = $bucky->db->select("file", {'thread = 2833'});
+my $file_map = {};
+foreach my $f (@$file_list) {
+ $file_map->{ $f->{'filename'} } = $f->{'id'};
+}
+
+my $base = "/var/www/vhosts/carbonpictures.com/bucky/data/";
+opendir(DIR, $base) or die $!;
+my @dirs = readdir(DIR);
+closedir(DIR);
+
+print scalar @dirs;
+
+foreach my $thread_id (@dirs) {
+ my $dir = $base . $thread_id;
+
+ next unless (-d $dir && $thread_id !~ /^\./);
+
+ opendir (THREAD, $dir);
+ my @local_files = readdir(THREAD);
+ closedir (THREAD);
+
+ foreach my $filename (@local_files) {
+ next unless exists($file_map->{$filename});
+
+ my $file_id = $file_map->{$filename};
+
+ $bucky->db->update_by_id('file', {
+ "id" => $file_id,
+ "record" => {
+ "thread" => $thread_id
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/search/bin/gross.db b/search/bin/gross.db
new file mode 100644
index 0000000..410d4e8
--- /dev/null
+++ b/search/bin/gross.db
Binary files differ
diff --git a/search/bin/listener.pl b/search/bin/listener.pl
new file mode 100755
index 0000000..0f0f2d9
--- /dev/null
+++ b/search/bin/listener.pl
@@ -0,0 +1,65 @@
+#!/usr/bin/perl
+ use IO::Socket;
+ use IO::Select;
+
+ # Create a socket to listen on.
+ #
+ my $listener =
+ IO::Socket::INET->new( LocalPort => 8008, Listen => 5, Reuse => 1 );
+
+ die "Can't create socket for listening: $!" unless $listener;
+ print "Listening for connections on port 8008\n";
+
+ my $readable = IO::Select->new; # Create a new IO::Select object
+ $readable->add($listener); # Add the listener to it
+
+ while(1) {
+
+ # Get a list of sockets that are ready to talk to us.
+ #
+ my ($ready) = IO::Select->select($readable, undef, undef, undef);
+ foreach my $s (@$ready) {
+
+ # Is it a new connection?
+ #
+ if($s == $listener) {
+
+ # Accept the connection and add it to our readable list.
+ #
+ my $new_sock = $listener->accept;
+ $readable->add($new_sock) if $new_sock;
+
+ print $new_sock "Welcome!\r\n";
+ print "connection :-o\n\n";
+
+ } else { # It's an established connection
+
+ my $buf = <$s>; # Try to read a line
+
+ # Was there anyone on the other end?
+ #
+ if( defined $buf ) {
+
+ # If they said goodbye, close the socket. If not,
+ # echo what they said to us.
+ #
+ if ($buf =~ /(good)?bye/i) {
+ print $s "See you later!\n";
+ $readable->remove($s);
+ $s->close;
+ } else {
+ print $s "You said: $buf\n";
+ print "$buf\n";
+ }
+
+ } else { # The client disconnected.
+
+ $readable->remove($s);
+ $s->close;
+ print STDERR "Client Connection closed\n";
+
+ }
+ }
+ }
+ }
+
diff --git a/search/bin/poetaster b/search/bin/poetaster
new file mode 100755
index 0000000..fe973a5
--- /dev/null
+++ b/search/bin/poetaster
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+use lib "../lib";
+use Rest;
+use CGI;
+use Poetaster;
+
+my $file = $ARGV[0] || "twain";
+my $data = load_data($file);
+$data =~ s/<[^>]+>//g;
+$data =~ s/\r\n/ /g;
+$data =~ s/\s+/ /g;
+$data =~ s/\. \. \. /... /g;
+my $self = new Poetaster;
+my $poem = $self->poem($data);
+print $poem;
+
+sub load_data
+ {
+ my ($file) = @_;
+ my $data = '';
+ if ($file =~ /^http/)
+ {
+ $data = Rest->new->rest_get_raw($file);
+ }
+ else
+ {
+ local $/;
+ open F, $file;
+ $data = <F>;
+ close F;
+ }
+ return $data;
+ }
diff --git a/search/bin/watch-index.pl b/search/bin/watch-index.pl
new file mode 100755
index 0000000..c9d950b
--- /dev/null
+++ b/search/bin/watch-index.pl
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+
+while (1)
+ {
+ system("./build-index");
+ sleep(60*60);
+ }
+
diff --git a/search/lib/Bucky.pm b/search/lib/Bucky.pm
new file mode 100644
index 0000000..181c1ae
--- /dev/null
+++ b/search/lib/Bucky.pm
@@ -0,0 +1,159 @@
+package Bucky;
+
+use strict 'vars';
+
+use Data::Dumper;
+use Common;
+
+use localbucky qw("config");
+
+use Bucky::DB;
+use Bucky::Keyword;
+use Bucky::Search;
+use Bucky::Session;
+use Bucky::Thread;
+# use Bucky::Comment;
+# use Bucky::File;
+use Bucky::SVN;
+
+our $TYPE_Bucky = "bucky";
+our $TYPE_Keyword = "keyword";
+our $TYPE_Thread = "thread";
+our $TYPE_Comment = "comment";
+our $TYPE_File = "file";
+
+our $VALID_TYPES =
+ {
+ $TYPE_Bucky => 1,
+ $TYPE_Keyword => 1,
+ $TYPE_Thread => 1,
+ $TYPE_Comment => 1,
+ $TYPE_File => 1,
+ };
+sub valid_types
+ { return $VALID_TYPES; }
+sub is_valid_type
+ {
+ my ($self, $type) = @_;
+# print "TYPE $type IS VALID? >>> " . $self->valid_types->{$type} . "\n";
+ return $self->valid_types->{$type};
+ }
+sub bucky_data_path
+ { return "/var/www/vhosts/carbonpictures.com" }
+sub new
+ {
+ my ($class, $self) = @_;
+ $self ||= {};
+ bless $self, $class;
+ return $self;
+ }
+sub type
+ { return $TYPE_Bucky; }
+sub inherit
+ {
+ my ($self, $parent) = @_;
+ if ($parent && ref($parent) =~ /Bucky/)
+ {
+ $self->db($parent);
+ $self->bucky($parent);
+ }
+ }
+sub bucky
+ {
+ my ($self, $parent) = @_;
+ return $self->{_bucky} if $self->{_bucky};
+ if ($parent && ref($parent) eq "Bucky")
+ { $self->{_bucky} = $parent; }
+ elsif ($parent && ref($parent) =~ /Bucky/)
+ { $self->{_bucky} = $parent->bucky; }
+ elsif ($self && ref($self) eq "Bucky")
+ { $self->{_bucky} = $self; }
+ else
+ { $self->{_bucky} = new Bucky; }
+ return $self->{_bucky};
+ }
+sub db
+ {
+ my ($self, $parent) = @_;
+ return $self->{_db} if $self->{_db};
+ if ($parent && ref($parent) =~ /Bucky/)
+ { $self->{_db} = $parent->bucky->db; }
+ else
+ { $self->{_db} = new Bucky::DB; }
+ return $self->{_db};
+ }
+sub keywords
+ {
+ }
+sub keyword ($)
+ { return shift->entity( $TYPE_Keyword, @_ ); }
+sub thread ($)
+ { return shift->entity( $TYPE_Thread, @_ ); }
+sub comment ($)
+ { return shift->entity( $TYPE_Comment, @_ ); }
+sub file ($)
+ { return shift->entity( $TYPE_File, @_ ); }
+# return unless my $criteria = $self->check_criteria($which);
+sub check_criteria
+ {
+ my ($self, $type, $which) = @_;
+ my $accessor = "_" . $type;
+ if ($self->can($accessor))
+ { $which ||= $self->$accessor; }
+ return undef unless $type && $which;
+ my $criteria = {};
+ if ( $self->is_number($which) )
+ { $criteria->{id} = $which; }
+ elsif ( length($which) )
+ { $criteria->{keyword} = $which; }
+ return scalar keys %$criteria ? $criteria : undef;
+ }
+# my $keyword = $self->entity( $TYPE_Keyword, $which );
+sub entity
+ {
+ my ($self, $type, $which) = @_;
+ return unless my $criteria = $self->check_criteria($type, $which);
+ my $entity_list = $self->db->select($type, $criteria);
+ foreach my $entity (@$entity_list)
+ {
+ # TODO: privacy check?
+ return $self->condone( $entity, $type );
+ }
+ return undef;
+ }
+# my $threads = $keyword->threads;
+# my $files = $thread->files;
+# my $children = $keyword->children;
+# join " ", map { $_->type }, $keyword->children;
+sub comments_by_id
+ {
+ my ($self, $comments_to_get) = @_;
+ return $self->db->select_by_id("comment", $comments_to_get);
+ }
+sub files_by_id
+ {
+ my ($self, $files_to_get) = @_;
+ return $self->db->select_by_id("file", $files_to_get);
+ }
+sub threads
+ {
+ my ($self) = @_;
+ return {};
+ }
+sub family
+ {
+ my ($self, $which) = @_;
+ my $type = $self->type || return;
+ my $entity_list = $self->db->select("family", { $type => $self->id });
+ }
+sub condone
+ {
+ my ($self, $ref, $type) = @_;
+ if ($type !~ /Bucky/ && $self->is_valid_type($type))
+ { $type = "Bucky::" . ucfirst($type); }
+ bless $ref, $type;
+ $ref->inherit($self);
+ return $ref;
+ }
+1;
+
diff --git a/search/lib/Bucky/DB.pm b/search/lib/Bucky/DB.pm
new file mode 100644
index 0000000..1e33b32
--- /dev/null
+++ b/search/lib/Bucky/DB.pm
@@ -0,0 +1,175 @@
+package Bucky::DB;
+
+use base 'Bucky';
+
+use Data::Dumper;
+use DBI;
+
+my $DB_LOOKUP =
+ {
+ bucky => '',
+ user => 'users',
+ keyword => 'keywords',
+ thread => 'threads',
+ file => 'files',
+ comment => 'comments',
+ family => 'family',
+ search_log => 'search_log',
+ poetaster_log => 'poetaster_log',
+ svn => 'svn',
+ };
+sub insert
+ {
+ my ($self, $type, $record) = @_;
+ $type = $DB_LOOKUP->{$type};
+ return unless $type && ref($record) eq "HASH" && scalar keys %$record;
+ my $keys = [];
+ my $values = [];
+ foreach my $key (keys %$record)
+ {
+ push @$keys, $key;
+ push @$values, $self->quote($record->{$key});
+ }
+ my $key_string = join ",", @$keys;
+ my $value_string = join ",", @$values;
+ return unless length $key_string && length $value_string;
+ my $sql = "INSERT INTO $type ($key_string) VALUES($value_string)";
+ $self->execute($sql);
+ return $self->lastinsertid($sql);
+ }
+sub update
+ {
+ my ($self, $type, $opt) = @_;
+ my $criteria = $opt->{'criteria'};
+ my $record = $opt->{'record'};
+
+ $type = $DB_LOOKUP->{$type};
+ return unless $type && ref($record) eq "HASH" && scalar keys %$record;
+ my $key_values = [];
+ foreach my $key (keys %$record)
+ {
+ push @$key_values, $key . "=" . $self->quote($record->{$key});
+ }
+ my $key_value_string = join ",", @$key_values;
+ return unless length $key_value_string;
+
+ my $criteria_string = $self->criteria($criteria);
+ return unless length $criteria_string;
+
+ my $sql = "UPDATE $type SET $key_value_string $criteria_string";
+
+ $self->execute($sql);
+ }
+sub update_by_id
+ {
+ my ($self, $type, $opt) = @_;
+ my $id = $opt->{'id'} + 0;
+ $opt->{'criteria'} = "id=$id";
+
+ $self->update($type, $opt)
+ }
+sub select
+ {
+ my ($self, $type, $criteria) = @_;
+ $type = $DB_LOOKUP->{$type};
+ return unless $type;
+ my $criteria_string = $self->criteria($criteria);
+ my $rows = [];
+ my $sql = "SELECT * FROM $type";
+ $sql .= " " . $criteria_string if $criteria_string;
+ my $sth = $self->execute($sql);
+ while (my $row = $sth->fetchrow_hashref)
+ {
+ push @$rows, $row;
+ }
+ return $rows;
+ }
+sub select_by_id
+ {
+ my ($self, $type, $id_array) = @_;
+ $type = $DB_LOOKUP->{$type};
+ return unless $type and ref($id_array) eq "ARRAY" and scalar @$id_array;
+ my $rows = {};
+ my $ids = join ",", @$id_array;
+ my $sql = "SELECT * FROM $type";
+ $sql .= " WHERE id IN ($ids)";
+ my $sth = $self->execute($sql);
+ while (my $row = $sth->fetchrow_hashref)
+ {
+ $rows->{ $row->{'id'} } = $row;
+ }
+ return $rows;
+ }
+sub criteria
+ {
+ my ($self, $criteria) = @_;
+
+ my $criteria_list = [];
+
+ if ($self->is_string($criteria))
+ {
+ push @$criteria_list, $criteria;
+ }
+ elsif (ref $criteria eq "HASH")
+ {
+ foreach my $key (keys %$criteria)
+ {
+ my $criterion = $key;
+ if ($criteria->{$key})
+ { $criterion .= "=" . $self->quote($criteria->{$key}); }
+ push @$criteria_list, $criterion;
+ }
+ }
+ return undef unless scalar @$criteria_list;
+
+ my $criteria_string = join(" AND ", @$criteria_list);
+ $criteria_string = "WHERE " . $criteria_string if $criteria_string =~ /[=<>]|( (IS|IN) )/;
+ return $criteria_string;
+ }
+sub execute
+ {
+ my ($self, $sql) = @_;
+ my $sth = $self->dbh->prepare($sql);
+ $sth->execute;
+ return $sth;
+ }
+sub quote
+ {
+ my ($self, $string) = @_;
+ return $self->dbh->quote($string);
+ }
+sub lastinsertid
+ {
+ my ($self) = @_;
+ return $self->dbh->last_insert_id(0, undef, undef, undef);
+ }
+sub dbh
+ {
+ my ($self, $parent) = @_;
+ if ($parent && ref($parent) =~ /Bucky/)
+ {
+ $self->{_dbh} ||= $parent->dbh;
+ }
+ if (! $self->{_dbh})
+ {
+ $self->{_dbh} ||= DBI->connect($self->dsn);
+ }
+ return $self->{_dbh};
+ }
+sub dsn
+ {
+ my ($self) = @_;
+ $self->{_dsn} ||=
+ "DBI:mysql:database=" . $self->db_name .
+ ":" . $self->db_host .
+ ";mysql_read_default_file=" . $self->my_cnf;
+ return $self->{_dsn};
+ }
+sub db_name
+ { 'bucky' }
+sub db_host
+ { 'localhost' }
+sub my_cnf
+ { '/var/www/vhosts/carbonpictures.com/.my.cnf' }
+
+1;
diff --git a/search/lib/Bucky/Keyword.pm b/search/lib/Bucky/Keyword.pm
new file mode 100644
index 0000000..8c52256
--- /dev/null
+++ b/search/lib/Bucky/Keyword.pm
@@ -0,0 +1,26 @@
+package Bucky::Keyword;
+
+use base 'Bucky';
+
+sub type { $Bucky::Keyword }
+sub fields
+ {[qw[
+ id keyword threads owner createdate
+ owner ops public
+ agglutinate
+ color display
+ ]]}
+
+sub _id { shift->{id} }
+sub _keyword { shift->{keyword} }
+sub _threads { shift->{threads} }
+sub _username { shift->{owner} }
+sub _ops { shift->{ops} }
+sub _public { shift->{public} }
+sub _createdate { shift->{createdate} }
+sub _agglutinate { shift->{agglutinate} }
+sub _color { shift->{color} }
+sub _display { shift->{display} }
+
+1;
+
diff --git a/search/lib/Bucky/SVN.pm b/search/lib/Bucky/SVN.pm
new file mode 100644
index 0000000..ef04464
--- /dev/null
+++ b/search/lib/Bucky/SVN.pm
@@ -0,0 +1,103 @@
+package Bucky::SVN;
+use base "Bucky";
+use Bucky::Session;
+sub svn_secret
+ { return shift->config("SVN_SECRET"); }
+sub list
+ {
+ my ($self, $count) = @_;
+ $count ||= 7;
+ return $self->db->select("svn", "ORDER BY date DESC LIMIT $count");
+ }
+sub query_incoming
+ {
+ my ($self) = @_;
+ my $session = new Bucky::Session;
+ error() unless scalar $session->q->param && length $session->q->param("secret") && $session->q->param("secret") eq $self->svn_secret();
+ if ($session->q->param("user"))
+ {
+ print $self->query_add($session);
+ }
+ else
+ {
+ print "Content-type: text/html\n\n";
+ print $self->query_list;
+ }
+ }
+sub query_list
+ {
+ my ($self) = @_;
+ my $svns = $self->list;
+ my $out .= <<__HEAD__;
+<table cellpadding=0 cellspacing=0 style="border: 1px solid #333;">
+__HEAD__
+ my $r = 0;
+ foreach my $svn (@$svns)
+ {
+ $r = $r ? 0 : 1;
+ my $user = $svn->{'user'};
+ $user = "default" if $user eq "root";
+ my $user_profile = "/cgi-bin/bucky/profile/$user";
+ my $user_img = "/bucky/data/profile/.thumb/am.$user.jpg";
+ my $date = $self->show_date($svn->{'date'});
+ my $revision = $svn->{'revision'};
+ my $comment = $svn->{'comment'};
+ $out .= <<__SVN__;
+<tr>
+<td style="border: 1px solid #333;" align="center">
+<a href="$user_profile"><img src="$user_img" border=0></a><!--<br><small>$user</small>-->
+</td>
+<td style="border: 1px solid #333; padding: 3px" class="r$r">
+<small>$revision: $comment</small>
+</td>
+</small>
+</tr>
+__SVN__
+ }
+ $out .= <<__FOOT__;
+</table>
+__FOOT__
+ return $out;
+ }
+sub query_add
+ {
+ my ($self, $session) = @_;
+
+ my $user = $session->q->param("user");
+ my $revision = $session->q->param("revision");
+ my $comment = $session->q->param("comment");
+ my $date = time;
+
+ error("missing some parameters\npossible: secret, user, revision, comment\n")
+ unless $user && $comment && $revision
+ && $self->is_number($revision) && length $user && length $comment;
+
+ my $query =
+ {
+ user => $user,
+ comment => $comment,
+ revision => $revision,
+ date => $date,
+ };
+
+ if (my $id = $self->db->insert("svn", $query))
+ { success("Successfully inserted $id"); }
+ else
+ { error("Unable to insert!"); }
+ }
+sub success
+ {
+ my ($success) = @_;
+ $success ||= "NICE ONE";
+ print "Content-type: text/plain\n\nSUCCESS: $success";
+ exit;
+ }
+sub error
+ {
+ my ($error) = @_;
+ $error ||= "SORRY GUY";
+ print "Content-type: text/plain\n\nERROR: $error";
+ exit;
+ }
+
+1;
diff --git a/search/lib/Bucky/Search.pm b/search/lib/Bucky/Search.pm
new file mode 100644
index 0000000..e01d55a
--- /dev/null
+++ b/search/lib/Bucky/Search.pm
@@ -0,0 +1,413 @@
+package Bucky::Search;
+
+use base 'Bucky';
+
+use Data::Dumper;
+use DB_File;
+
+sub index
+ {
+ my ($self, $index) = @_;
+ $self->{'_index'} = $index || $self->index_read;
+ return $self->{'_index'};
+ }
+sub index_read
+ {
+ my ($self) = @_;
+ my %index;
+ tie %index, "DB_File", $self->index_filename, O_RDONLY, 0666, $DB_HASH ;
+ return \%index;
+ }
+sub index_write
+ {
+ my ($self) = @_;
+ my %index;
+ tie %index, "DB_File", $self->index_filename, O_CREAT|O_RDWR, 0666, $DB_HASH ;
+ return \%index;
+ }
+sub index_close
+ {
+ my ($self, $index) = @_;
+ $index ||= $self->index;
+ untie %$index;
+ }
+sub index_filename
+ { "gross.db" }
+sub auto_index
+ {
+ my ($self, $auto_index) = @_;
+ $self->{'_auto_index'} = $auto_index || $self->auto_index_read;
+ return $self->{'_auto_index'};
+ }
+sub auto_index_read
+ {
+ my ($self) = @_;
+ my %auto_index;
+ tie %auto_index, "DB_File", $self->auto_index_filename, O_RDONLY, 0666, $DB_HASH ;
+ return \%auto_index;
+ }
+sub auto_index_write
+ {
+ my ($self) = @_;
+ my %auto_index;
+ tie %auto_index, "DB_File", $self->auto_index_filename, O_CREAT|O_RDWR, 0666, $DB_HASH ;
+ return \%auto_index;
+ }
+sub auto_index_close
+ {
+ my ($self, $auto_index) = @_;
+ $auto_index ||= $self->auto_index;
+ untie %$auto_index;
+ }
+sub auto_index_filename
+ { "auto.db" }
+sub lexicon_store
+ {
+ my ($self, $lexicon) = @_;
+ my $index = $self->index_write;
+ foreach my $term (keys %$lexicon)
+ {
+ next if $self->is_stopword($term);
+ my $serialized = $self->serialize_matches($lexicon->{$term});
+ next unless $serialized;
+ $index->{$term} = $serialized;
+ }
+ $self->index_close($index);
+ }
+sub unserialize_matches
+ {
+ my ($self, $serialized_string) = @_;
+ my @serialized_matches = split ",", $serialized_string;
+ my @matches;
+ foreach my $serialized_match (@serialized_matches)
+ {
+ my ($thread, $comment, $file, $strength) = split " ", $serialized_match;
+ my $match = {};
+ $match->{'thread'} = $thread;
+ $match->{'comment'} = $comment;
+ $match->{'file'} = $file;
+ $match->{'strength'} = $strength;
+ push @matches, $match;
+ }
+ return \@matches;
+ }
+sub serialize_matches
+ {
+ my ($self, $matches) = @_;
+ my @serialized_matches;
+ foreach my $match (values %$matches)
+ {
+ next unless $match && ref($match) eq "HASH";
+ my $string = join " ",
+ $match->{'thread'},
+ $match->{'comment'},
+ $match->{'file'},
+ $match->{'strength'};
+ next unless $string;
+ push @serialized_matches, $string if $string;
+ }
+ return undef unless scalar @serialized_matches;
+ return join ",", @serialized_matches;
+ }
+my $STOPWORDS = {( map { lc $_, 1 } qw(
+a about above across adj after again against all almost alone along also
+although always am among an and another any anybody anyone anything anywhere
+apart are around as aside at away be because been before behind being below
+besides between beyond both but by can cannot could deep did do does doing done
+down downwards during each either else enough etc even ever every everybody
+everyone except far few for forth from get gets got had hardly has have having
+her here herself him himself his how however i if in indeed instead into inward
+is it its itself just kept many maybe might mine more most mostly much must
+myself near neither next no nobody none nor not nothing nowhere of off often on
+only onto or other others ought our ours out outside over own p per please plus
+pp quite rather really said seem self selves several shall she should since so
+some somebody somewhat still such than that the their theirs them themselves
+then there therefore these they this thorough thoroughly those through thus to
+together too toward towards under until up upon v very was well were what
+whatever when whenever where whether which while who whom whose will with
+within without would yet young your yourself s ) )};
+sub is_stopword
+ {
+ my ($self, $term) = @_;
+ return exists $STOPWORDS->{lc $term};
+ }
+sub autocomplete
+ {
+ my ($self, $query) = @_;
+ return unless $query;
+ my $terms = parse_terms($query);
+ my $last_term = pop @$terms;
+
+ my $auto_index = $self->auto_index;
+ my $guess_term = $auto_index->{$last_term};
+ my $guess_full = join " ", @$terms, $guess_term;
+ my $guess_tail = $guess_term;
+ $guess_tail =~ s/^$last_term//;
+
+ my $guess = {};
+ $guess->{'full'} = $guess_full;
+ $guess->{'tail'} = $guess_tail;
+ $guess->{'term'} = $guess_term;
+ return $guess;
+ }
+sub search_light
+ {
+ my ($self, $query, $start, $limit) = @_;
+ return unless $query;
+ $start ||= 0;
+ $limit ||= 10;
+ my $scores = {};
+ my $terms = parse_terms($query);
+ my $index = $self->index;
+ foreach my $term (@$terms)
+ {
+ next if $self->is_stopword($term);
+ next unless my $serial = $index->{$term};
+ my $results = $self->unserialize_matches($serial);
+ foreach my $result (@$results)
+ {
+ my $thread = $result->{'thread'};
+ $scores->{$thread} ||= {};
+ $scores->{$thread}->{thread} ||= $result->{'thread'};
+ $scores->{$thread}->{file} ||= $result->{'file'};
+ $scores->{$thread}->{strength} += $result->{'strength'};
+ $scores->{$thread}->{count}++;
+ }
+ }
+ my $total = scalar keys %$scores;
+ my $i = 0;
+ my $to_display = $limit;
+ my $threads = {};
+ my $comments_to_get = [];
+ my $files_to_get = [];
+ foreach my $match (sort { $b->{count} <=> $a->{count} || $b->{strength} * $b->{count} <=> $a->{strength} * $a->{count} } values %$scores )
+ {
+ next if $i++ < $start;
+ my $thread = $self->thread( $match->{'thread'} );
+ next unless $thread;
+ next if $thread->{'private'};
+ last if $to_display-- == 0;
+ push @$results, $match;
+ push @$comments_to_get, $match->{'comment'} if $match->{'comment'};
+ if ( $match->{'file'} )
+ { push @$files_to_get, $match->{'file'}; }
+ if ( $thread->{'flagged'} )
+ { push @$files_to_get, $thread->{'flagged'}; }
+ $threads->{ $thread->{'id'} } = $thread;
+ }
+ my $files = $self->files_by_id($files_to_get);
+ # $self->log_query($query, $total);
+ return
+ {
+ start => $start + $limit,
+ limit => $limit,
+ total => $total,
+ results => $results,
+ threads => $threads,
+ files => $files,
+ terms => $terms,
+ };
+ }
+sub search
+ {
+ my ($self, $query, $start, $limit) = @_;
+ return unless $query;
+ $start ||= 0;
+ $limit ||= 10;
+ my $scores = {};
+ my $terms = parse_terms($query);
+ my $index = $self->index;
+ foreach my $term (@$terms)
+ {
+ next if $self->is_stopword($term);
+ next unless my $serial = $index->{$term};
+ my $results = $self->unserialize_matches($serial);
+ foreach my $result (@$results)
+ {
+ my $thread = $result->{'thread'};
+ $scores->{$thread} ||= {};
+ $scores->{$thread}->{thread} ||= $result->{'thread'};
+ $scores->{$thread}->{comment} ||= $result->{'comment'};
+ $scores->{$thread}->{file} ||= $result->{'file'};
+ $scores->{$thread}->{strength} += $result->{'strength'};
+ $scores->{$thread}->{count}++;
+ }
+ }
+ my $total = scalar keys %$scores;
+ my $i = 0;
+ my $to_display = $limit;
+ my $threads = {};
+ my $comments_to_get = [];
+ my $files_to_get = [];
+ foreach my $match (sort { $b->{count} <=> $a->{count} || $b->{strength} * $b->{count} <=> $a->{strength} * $a->{count} } values %$scores )
+ {
+ next if $i++ < $start;
+ my $thread = $self->thread( $match->{'thread'} );
+ next unless $thread;
+ next if $thread->{'private'};
+ last if $to_display-- == 0;
+ push @$results, $match;
+ push @$comments_to_get, $match->{'comment'} if $match->{'comment'};
+ if ( $match->{'file'} )
+ { push @$files_to_get, $match->{'file'}; }
+ if ( $thread->{'flagged'} )
+ { push @$files_to_get, $thread->{'flagged'}; }
+ $threads->{ $thread->{'id'} } = $thread;
+ }
+ my $files = $self->files_by_id($files_to_get);
+ my $comments = $self->comments_by_id($comments_to_get);
+ $self->log_query($query, $total);
+ return
+ {
+ start => $start + $limit,
+ limit => $limit,
+ total => $total,
+ results => $results,
+ threads => $threads,
+ comments => $comments,
+ files => $files,
+ terms => $terms,
+ };
+ }
+sub score_display
+ {
+ my ($obj) = @_;
+ return scalar(keys %{$obj->{terms}}) . "x" . $obj->{count};
+ }
+sub display_object
+ {
+ my ($obj) = @_;
+ my ($type, $id) = split ":", $obj;
+ my $thread = $bucky->thread($id);
+ my $title = $thread ? $thread->_title : "* * *";
+ return $type . " " . $id . "\t" . $title;
+ }
+sub bold_terms
+ {
+ my ($self, $string, $terms) = @_;
+ $string = $self->strip_html($string);
+ foreach my $term (@$terms)
+ {
+ $string =~ s/\b($term)\b/<b>$1<\/b>/gi;
+ }
+ return $string;
+ }
+sub bold_snippet
+ {
+ my ($self, $string, $terms) = @_;
+ my $snippet = $self->snippet($string, $terms);
+ return $self->bold_terms($snippet, $terms);
+ }
+sub snippet
+ {
+ my ($self, $string, $terms) = @_;
+
+ # clean up the string we got
+ $string = $self->strip_html($string);
+
+ # create a regex out of the search terms
+ my $term_re = join "|", @$terms;
+
+ # take the string to be snippetized and split it into words
+ my @words = split /\s+/, $string;
+
+ # deduper for matching @words indexes, so we don't add a word twice
+ my $index_matches = {};
+
+ # words in the eventual snippet
+ my @words_matched;
+
+ # the snippet itself
+ my $snippet = '';
+
+ # counter for aggregating context after a match
+ my $aggr = 0;
+
+ # amount of context to show, in number of words surrounding a match
+ my $pad = 4;
+
+ # loop over each of the words in the string
+ for (my $i = 0; $i < scalar @words; $i++)
+ {
+ # does this word contain a match?
+ if ($words[$i] =~ /\b($term_re)\b/i && ! $self->is_stopword($1))
+ {
+ # if we aren't already aggregating, add an ellipsis
+ if (! $aggr)
+ {
+ push @words_matched, "...";
+ }
+ # look backward $pad words
+ for (my $j = -$pad; $j < 1; $j++)
+ {
+ # create a new index from the offset
+ my $idx = $i + $j;
+
+ # is this a valid index? has it already been encountered?
+ next if $idx < 0;
+ next if $idx > scalar @words;
+ next if exists $index_matches->{$i+$j};
+
+ # checks out, save this word
+ push @words_matched, $words[$i+$j];
+
+ # note the matching index in our deduper
+ $index_matches->{$i+$j} ++;
+ }
+ # enter aggregate mode -- add the next $pad words
+ $aggr = $pad;
+ }
+ # have we been told to aggregate?
+ elsif ($aggr)
+ {
+ # save this word
+ push @words_matched, $words[$i];
+
+ # add index to the deduper
+ $index_matches->{$i} ++;
+
+ # one less word to aggregate
+ $aggr--;
+ }
+ # keep snippets to a modest length
+ last if scalar @words_matched > 30;
+ }
+ # add a trailing ellipsis
+ push @words_matched, "...";
+
+ # create the snippet from the saved context words
+ $snippet = join " ", @words_matched;
+
+ return $snippet;
+ }
+sub parse_terms
+ {
+ my ($s) = @_;
+ my @terms = split /(\W+)/, lc($s);
+ my $words = [];
+ my $count = 0;
+ foreach my $term (@terms)
+ {
+ if ( $term !~ /\W/ )
+ {
+ push @$words, $term;
+ }
+ }
+ return $words;
+ }
+sub log
+ {
+ my ($self, $date) = @_;
+ my $criteria = {};
+ $criteria->{'date'} = $date if $date;
+ return $self->db->select("search_log", $criteria);
+ }
+sub log_query
+ {
+ my ($self, $query, $total) = @_;
+ return unless $query;
+ my $date = time;
+ $matches ||= '0';
+ $self->db->insert("search_log", { query => $query, date => $date, matches => $total });
+ }
+1;
diff --git a/search/lib/Bucky/Session.pm b/search/lib/Bucky/Session.pm
new file mode 100644
index 0000000..0cff753
--- /dev/null
+++ b/search/lib/Bucky/Session.pm
@@ -0,0 +1,19 @@
+package Bucky::Session;
+
+use base 'Bucky';
+
+use CGI;
+
+sub param
+ {
+ my ($self, $name) = @_;
+ return unless $name;
+ return $self->q->param($name);
+ }
+sub q
+ {
+ my ($self) = @_;
+ $self->{'_q'} ||= new CGI;
+ return $self->{'_q'};
+ }
+1;
diff --git a/search/lib/Bucky/Thread.pm b/search/lib/Bucky/Thread.pm
new file mode 100644
index 0000000..dbd8ad0
--- /dev/null
+++ b/search/lib/Bucky/Thread.pm
@@ -0,0 +1,30 @@
+package Bucky::Thread;
+
+use base 'Bucky';
+
+sub type { $Bucky::Thread }
+sub fields
+ {[qw[
+ id title username keyword private allowed
+ createdate lastmodified revision viewed
+ size color display flagged zipped
+ ]]}
+
+sub _id { shift->{id} }
+sub _title { shift->{title} }
+sub _username { shift->{username} }
+sub _keyword { shift->{keyword} }
+sub _private { shift->{private} }
+sub _allowed { shift->{allowed} }
+sub _createdate { shift->{createdate} }
+sub _lastmodified { shift->{lastmodified} }
+sub _revision { shift->{revision} }
+sub _viewed { shift->{viewed} }
+sub _size { shift->{size} }
+sub _color { shift->{color} }
+sub _display { shift->{display} }
+sub _flagged { shift->{flagged} }
+sub _zipped { shift->{zipped} }
+
+1;
+
diff --git a/search/lib/Common.pm b/search/lib/Common.pm
new file mode 100644
index 0000000..0797943
--- /dev/null
+++ b/search/lib/Common.pm
@@ -0,0 +1,46 @@
+## utility functions
+package Common;
+use base 'Exporter';
+our @EXPORT = qw[is_number is_string show_date get_age trim strip_html];
+
+# promiscuous namespace
+sub is_number
+ { my ($self, $s) = @_; return $s && $s !~ /\D/; }
+sub is_string
+ { my ($self, $s) = @_; return length $s && ! length ref $s; }
+sub show_date
+ { my ($self, $date) = @_; return scalar localtime($date); }
+sub get_age
+ {
+ my ($self, $time) = @_;
+ if ($time < 0)
+ { return "old"; }
+ my $age = time - $time;
+ if ($age < 60)
+ { return int($age)."s"; }
+ $age /= 60;
+ if ($age < 60)
+ { return int($age)."m"; }
+ my $mins = $age % 60;
+ $age /= 60;
+ if ($age < 2)
+ { return int($age)."h".int($mins)."m"; }
+ elsif ($age < 24)
+ { return int($age)."h"; }
+ $age /= 24;
+ if ($age < 10000)
+ { return int($age)."d"; }
+ my $powers = qw[k m g t p e z y];
+ foreach my $prefix (@$powers)
+ {
+ $age /= 1000;
+ if ($age < 10000)
+ { return int($age).$prefix."d"; }
+ }
+ }
+sub trim
+ { my ($self, $s) = @_; $s =~ s/^\s+//; $s =~ s/\s+$//; return $s; }
+sub strip_html
+ { my ($self, $s) = @_; $s =~ s/[<>]+/ /g; return $s; }
+
+1;
diff --git a/search/lib/Time/Stopwatch.pm b/search/lib/Time/Stopwatch.pm
new file mode 100644
index 0000000..b7cec26
--- /dev/null
+++ b/search/lib/Time/Stopwatch.pm
@@ -0,0 +1,13 @@
+################################################3
+package Time::Stopwatch;
+my $VERSION = '1.00';
+use strict;
+use constant HIRES => eval { local $SIG{__DIE__}; require Time::HiRes };
+sub TIESCALAR { my $pkg = shift;
+ my $time = (HIRES ? Time::HiRes::time() : time()) - (@_ ? shift() : 0);
+ bless \$time, $pkg; }
+sub FETCH { (HIRES ? Time::HiRes::time() : time()) - ${$_[0]}; }
+sub STORE { ${$_[0]} = (HIRES ? Time::HiRes::time() : time()) - $_[1]; }
+#################################################
+sub print_timer { print sprintf "%3.2f s %s\n", shift, shift; }
+1;
diff --git a/search/lib/localbucky.pm b/search/lib/localbucky.pm
new file mode 100644
index 0000000..41c7553
--- /dev/null
+++ b/search/lib/localbucky.pm
@@ -0,0 +1,12 @@
+package Bucky;
+my $LOCAL_CONFIG =
+ {
+ SVN_SECRET => '1s0c4h3dr0n',
+ };
+sub config
+ {
+ my ($self, $key) = @_;
+ $key ||= $self;
+ return $LOCAL_CONFIG->{$key} if $LOCAL_CONFIG->{$key};
+ }
+1;
diff --git a/views/pages/details.ejs b/views/pages/details.ejs
index 769db9d..b508560 100644
--- a/views/pages/details.ejs
+++ b/views/pages/details.ejs
@@ -3,6 +3,15 @@
<hr>
<div id="details_rapper">
+ <script type="text/html" class="metadata_template">
+ Posted by {{ username }}
+ on {{ date }} {{ time }}
+ &middot;
+ Last active {{ active }}
+ &middot;
+ {{ views }}
+ </script>
+
<table id="details">
<tr>
<td class="left">
diff --git a/views/pages/message.ejs b/views/pages/message.ejs
index 333908d..bd71a0a 100644
--- a/views/pages/message.ejs
+++ b/views/pages/message.ejs
@@ -4,7 +4,7 @@
<div class="bluebox" id="message">
<script class="template" type="text/html">
- <a href="/profile/{{sender}}" class="av"><img src="//www.carbonpictures.com/bucky/data/profile/.thumb/al.{{sender}}.jpg"></a>
+ <a href="/profile/{{sender}}" class="av"><img src="/data/profile/.thumb/al.{{sender}}.jpg"></a>
<span class="subject">{{subject}}</span>
<span class="sender">
sent by
diff --git a/views/partials/comments.ejs b/views/partials/comments.ejs
index 97d4cea..6226a61 100644
--- a/views/partials/comments.ejs
+++ b/views/partials/comments.ejs
@@ -1,8 +1,8 @@
-<table id="comments" width="450">
+<table id="comments">
<script class="template" type="text/html">
<tr>
<td class="user">
- <a href="/profile/{{username}}"><img src="//www.carbonpictures.com/bucky/data/profile/.thumb/al.{{username}}.jpg"></a><br>
+ <a href="/profile/{{username}}"><div class="avatar" style="background-image:url(/data/profile/{{username}}.jpg)"></div></a>
<a href="/profile/{{username}}">{{username}}</a>
</td>
<td colspan="2" class="comment">
@@ -20,4 +20,16 @@
</td>
</tr>
</script>
+</table>
+
+<table id="comment_form">
+ <tr>
+ <td>
+ <form>
+ <textarea name="comment"></textarea><br>
+ <input type="file" multiple>
+ <input type="submit" value="POST" />
+ </form>
+ </td>
+ </tr>
</table> \ No newline at end of file
diff --git a/views/partials/files.ejs b/views/partials/files.ejs
index d72dcdc..34d476a 100644
--- a/views/partials/files.ejs
+++ b/views/partials/files.ejs
@@ -1,7 +1,7 @@
<div id="audio"></div>
<table id="files">
<script class="template" type="text/html">
- <tr class="row">
+ <tr class="file">
<td>
<a href="{{link}}" class="file">{{filename}}</a>
</td>
diff --git a/views/partials/gallery.ejs b/views/partials/gallery.ejs
index 8fac271..7115d4d 100644
--- a/views/partials/gallery.ejs
+++ b/views/partials/gallery.ejs
@@ -1,7 +1,7 @@
<div id="gallery">
<script class="template" type="text/html">
<div>
- <a href="{{link}}"><img src="{{thumb}}"></a>
+ <a href="{{link}}"><img class="thumb" src="{{thumb}}"></a>
<br>(<a href="/profile/{{username}}">{{username}}</a>, {{age}})
</div>
</script>
diff --git a/views/partials/header.ejs b/views/partials/header.ejs
index 6cd7b2e..f5b21dc 100644
--- a/views/partials/header.ejs
+++ b/views/partials/header.ejs
@@ -8,7 +8,7 @@
<body>
<h1><%= title %></h1>
-
+<span class="metadata"></span>
<hr>
<% if (show_header) { %>
diff --git a/views/partials/hootbox.ejs b/views/partials/hootbox.ejs
index 872ca68..d32ff8f 100644
--- a/views/partials/hootbox.ejs
+++ b/views/partials/hootbox.ejs
@@ -1,16 +1,17 @@
<div class="bluebox" id="hootbox">
- <form>
- <input type="text" name="comment">
+ <form autocomplete="off">
+ <input type="text" name="comment" autocomplete="off">
<button><%= hoot_text %></button>
+ <div class="errors"></div>
</form>
<table id="hoots">
<script class="template" type="text/html">
<tr>
- <td style="background-image:url(//www.carbonpictures.com/bucky/data/profile/.thumb/am.{{username}}.jpg)"><a href="/profile/{{username}}"><div></div></a></td>
+ <td style="background-image:url(/data/profile/{{username}}.jpg)"><a href="/profile/{{username}}"><div></div></a></td>
<td>
{{comment}}
</td>
</tr>
</script>
</table>
-</div> \ No newline at end of file
+</div>
diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs
index 0a5c4d6..8dc99a1 100644
--- a/views/partials/scripts.ejs
+++ b/views/partials/scripts.ejs
@@ -24,6 +24,7 @@
<script src="/assets/js/lib/views/details/comments.js"></script>
<script src="/assets/js/lib/views/details/files.js"></script>
<script src="/assets/js/lib/views/details/gallery.js"></script>
+<script src="/assets/js/lib/views/details/commentform.js"></script>
<script src="/assets/js/lib/views/mail/mailbox.js"></script>
<script src="/assets/js/lib/views/mail/message.js"></script>
diff --git a/views/partials/threads.ejs b/views/partials/threads.ejs
index b809be8..b3a6e75 100644
--- a/views/partials/threads.ejs
+++ b/views/partials/threads.ejs
@@ -1,21 +1,21 @@
<table class="ledger" id="threads">
+
<script class="keywordTemplate" type="text/html">
- <tr>
- <th>
- <b>{{keyword}}</b>
- &middot;
- </th>
- <th>
+ <tr class='keyword'>
+ <td>
+ <b>{{keyword}}</b>&nbsp;&middot;
+ </td>
+ <td>
<a href="/post/{{keyword}}">post</a>
- </th>
+ </td>
</tr>
</script>
+
<script class="template" type="text/html">
- <tr>
+ <tr class='row'>
<td>
- <a href="/profile/{{username}}">{{username}}</a>
- {{privacy_dot}}
+ <a href="/profile/{{username}}">{{username}}</a>&nbsp;{{privacy_dot}}
</td>
<td class="{{color}}">
<a href="/details/{{id}}">{{title}}</a>
@@ -38,4 +38,5 @@
</td>
</tr>
</script>
+
</table>