diff options
46 files changed, 4384 insertions, 97 deletions
@@ -8,4 +8,5 @@ v1 node_modules/ dist *.sql - +.env +public/data @@ -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 Binary files differnew file mode 100644 index 0000000..410d4e8 --- /dev/null +++ b/search/bin/gross.db 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 }} + · + Last active {{ active }} + · + {{ 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> - · - </th> - <th> + <tr class='keyword'> + <td> + <b>{{keyword}}</b> · + </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> {{privacy_dot}} </td> <td class="{{color}}"> <a href="/details/{{id}}">{{title}}</a> @@ -38,4 +38,5 @@ </td> </tr> </script> + </table> |
