Skip to content

Instantly share code, notes, and snippets.

@ndreckshage
Created January 22, 2014 23:41
Show Gist options
  • Save ndreckshage/8569869 to your computer and use it in GitHub Desktop.
Save ndreckshage/8569869 to your computer and use it in GitHub Desktop.
snapsecret v3 (node + ember, not all code included)
(->
Ember = require 'ember'
moment = require 'moment'
# Socket.io
io = window.io
host = location.origin.replace /^http/, 'ws'
socket = io.connect host
# SnapSecret
window.SnapSecret = SnapSecret = Ember.Application.create()
# Controllers
require('./controllers/application_controller.coffee')(SnapSecret, socket)
require('./controllers/index_controller.coffee')(SnapSecret, socket)
require('./controllers/confess_controller.coffee')(SnapSecret, socket, moment)
# Views
require('./views/application_view.coffee')(SnapSecret)
require('./views/commentable_button_view.coffee')(SnapSecret)
require('./views/blow_the_whistle_button_view.coffee')(SnapSecret)
# Helpers
require('./helpers/moment_helper.coffee')(Ember, moment)
# Templates
require './templates.js'
# Routes
require('./router.coffee')(SnapSecret)
require('./routes/index_route.coffee')(SnapSecret)
require('./routes/confess_route.coffee')(SnapSecret)
)()
module.exports = (SnapSecret, socket) ->
SnapSecret.ApplicationController = Ember.Controller.extend
needs: ['index', 'confess']
defaultCountdown: 60
countdownWarning: false
indexRoute: false
confessRoute: false
activeSecret: false
failureMessage: null
successMessage: null
stats:
showStats: false
totalSpilled: 0
totalRead: 0
countdown: 60
init: () ->
if window.activeExpiry and window.activeSecret
@set 'countdown', window.activeExpiry
@set 'activeSecret', true
@startTheClock()
if window.secretStats
@set('stats.totalSpilled', window.secretStats.totalSpilled) \
if window.secretStats.totalSpilled
@set('stats.totalRead', window.secretStats.totalRead) \
if window.secretStats.totalRead
@setShowStats()
@initIO()
initIO: () ->
indexController = @get 'controllers.index'
socket.on 'spill secret', (data) =>
if @get 'activeSecret'
indexController.send 'addToQueue', data
else
@send 'newSecret', data
indexController.send 'activateSecret', data
indexController.set 'waitingMessage', false
socket.on 'comment added', (data) =>
indexController.send 'commentAdded', data
setShowStats: (() ->
if @get('stats.totalSpilled') > 10 and @get('stats.totalRead') > 10
@set 'stats.showStats', true
else
@set 'stats.showStats', false
).observes('stats.totalSpilled', 'stats.totalRead')
flash: (message, type = 'error') ->
# console.log 'hit'
if type is 'error' \
then @set 'failureMessage', message \
else @set 'successMessage', message
flashClear: () ->
@set 'successMessage', null
@set 'failureMessage', null
startTheClock: () ->
@countdownInterval = setInterval $.proxy(@contentCountdown, @), 1000
reset: () ->
clearInterval @countdownInterval
@set 'countdown', @defaultCountdown
@set 'activeSecret', false
contentCountdown: () ->
indexController = @get 'controllers.index'
indexController.set 'waitingMessage', false
counter = @get 'countdown'
counter--
@set 'countdown', counter
if counter is 0
@reset()
# TODO - implement confirmation behavior
indexController.send 'nextInQueue'
warnAtTen: (() ->
if @countdown <= 10
@set 'countdownWarning', true
else if @countdown > 10
@set 'countdownWarning', false
).observes('countdown')
actions:
newSecret: (data) ->
@set 'activeSecret', true
currentSpilled = @get 'stats.totalSpilled'
# console.log 'applicationController', '@actions.newSecret', data
newSpilled = currentSpilled += data.view_count
@set 'stats.totalSpilled', newSpilled
currentRead = @get 'stats.totalRead'
@set 'stats.totalRead', ++currentRead
@startTheClock()
navigateHome: () ->
@transitionToRoute 'index'
module.exports = (SnapSecret, socket, moment) ->
SnapSecret.ConfessController = Ember.Controller.extend
needs: ['application', 'index']
init: () ->
# console.log 'confess', 'secretTimes', window.secretTimes
@get('secret.spilled').pushObjects window.secretTimes \
if window.secretTimes
@initIO()
initIO: () ->
socket.on 'create secret response', (data) =>
# if no errors
# console.log 'confessController', '@initIO', 'response data', data
@transitionToRoute 'index'
if data == 0
@get('controllers.index').send 'queueFlash', \
"your secret is safe with us.", \
'success'
else
@get('controllers.index').send 'queueFlash', \
"your secret is set to spill " + \
"#{moment().add('minutes', data).fromNow()}", \
'success'
@set 'message.value', ''
@set 'inFlight', false
# console.log 'confess io response', 'before', @get('secret.spilled')
@get('secret.spilled').pushObject Date.now()
# console.log 'confess io response', 'after', @get('secret.spilled')
disableForm: (() ->
@get('inFlight') or @get('secret.inValid')
).property('inFlight', 'secret.inValid')
inFlight: false
secret:
maxPerHour: 2
inValid: false
spilled: Ember.A()
updateSecretCount: () ->
# console.log 'confess', 'updateSecretCount', \
# 'before', @get('secret.spilled')
@set 'secret.spilled', @get('secret.spilled').filter (item) ->
Date.now() - item <= 60 * 60 * 1000
# console.log 'confess', 'updateSecretCount', \
# 'after', @get('secret.spilled')
secretValidate: (() ->
# console.log 'confess', 'secretValidate', \
# 'called', @get('secret.spilled').length, @get 'secret.maxPerHour'
applicationController = @get('controllers.application')
if @get('secret.spilled').length >= @get 'secret.maxPerHour'
@set 'secret.inValid', true
applicationController.flash "easy there, snowden. " + \
"#{@get('secret.maxPerHour')} secrets per hour."
false
else
@set 'secret.inValid', false
applicationController.flashClear()
true
# console.log 'confess', 'secretValidate', @get 'secret.inValid'
).observes 'secret.spilled.@each'
commentable: true
commentableCurrent: (() ->
if @get('commentable') then 'on' else 'off'
).property('commentable')
name: ''
location: ''
message:
value : ''
minWords : 10
maxWords : 500
valid : false
error : null
messageValidate: (() ->
message = @get('message.value')
wordCount = (message.match(/\S+/g) || []).length
minWords = @get 'message.minWords'
maxWords = @get 'message.maxWords'
if maxWords >= wordCount >= minWords
@get('controllers.application').flashClear()
@set 'message.valid', true
@set 'message.error', null
true
else
error = if wordCount < minWords then \
"a secret with less then #{minWords} words is hardly a secret." else \
"#{maxWords} words max. this isnt wikileaks. " + \
"(you entered #{wordCount})"
@set 'message.valid', false
@set 'message.error', error
false
).observes 'message.value'
actions:
toggleComments: () ->
if @get('commentable') is on \
then @set('commentable', off) \
else @set('commentable', on)
confessSecret: () ->
# console.log 'confessSecret', 'action', @get('secret.inValid')
unless @get('secret.inValid')
@messageValidate()
if @get 'message.valid'
@set 'inFlight', true
socket.emit 'create secret',
ip_address: window.staticIP
message: @get('message.value')
commentable: @get('commentable')
location: @get('location')
name: @get('name')
else
@get('controllers.application').flash @get 'message.error'
module.exports = (SnapSecret, socket) ->
SnapSecret.IndexController = Ember.ObjectController.extend
needs: ['application']
queue: Ember.A()
queueFlash:
message: null
type: null
comments: Ember.A()
commentable: false
commentsEnabled: true
showComments: false
waitingMessage: false
secretsRead: 0
nsaCheck: false
comment:
maxCount: 1
valid: true
inValid: false
count: 0
value: ''
init: () ->
secret = window.activeSecret
@set 'content', secret: secret if secret
if window.activeCommentCount
@set('comment.count', window.activeCommentCount)
if secret and secret.comments
secret.comments.forEach (comment) =>
@comments.pushObject comment
@comments.reverse()
@setCommentable()
@commentValidate()
@commentInvalid()
@setShowComments()
commentInvalid: (() ->
if @get('comment.valid')
@set('comment.inValid', false)
else
@set('comment.inValid', true)
).observes('comment.valid')
setNSACheck: (() ->
secretsRead = @get 'secretsRead'
if secretsRead % 5 == 0
@set 'nsaCheck', true
else
@set 'nsaCheck', false
).observes('secretsRead')
setShowComments: (() ->
commentable = @get 'commentable'
# console.log 'indexController', '@setShowComments', \
# '#commentable', commentable
commentsEnabled = @get 'commentsEnabled'
# console.log 'indexController', '@setShowComments', \
# '#commentsEnabled', commentsEnabled
showComments = commentable and commentsEnabled
# console.log 'indexController', '@setShowComments', \
# '#showComments', showComments
@set 'showComments', showComments
).observes('commentable', 'commentsEnabled')
setCommentable: (() ->
commentable = @get('content.secret.commentable')
# console.log 'indexController', '@setCommentable', commentable
@set('commentable', commentable)
).observes('content.secret.commentable')
commentValidate: (() ->
if @get('comment.count') < @get('comment.maxCount')
@set('comment.valid', true)
else
@set('comment.valid', false)
).observes('comment.count')
_clearSecretSwitch: () ->
# console.log 'indexController', '@_clearSecretSwitch'
@set 'waitingMessage', false
clearTimeout @noSecretTimeout if @noSecretTimeout
_noSecretSwitch: () ->
# console.log 'indexController', '@_noSecretSwitch', 'called'
unless @get('controllers.application').get 'activeSecret'
# console.log 'indexController', '@_noSecretSwitch', 'waiting'
@noSecretTimeout = setTimeout () =>
# console.log 'indexController', '@_noSecretSwitch', 'active'
@set 'waitingMessage', true
, 3000
clearContent: () ->
# console.log 'indexController', '@clearContent'
@set 'content', null
@_noSecretSwitch()
actions:
queueFlash: (message, type = 'error') ->
@set 'queueFlash.message', message
@set 'queueFlash.type', type
addToQueue: (secret) ->
@queue.pushObject secret: secret
activateSecret: (secret) ->
@set 'content', secret: secret
secretsRead = @get 'secretsRead'
# console.log 'indexController', '@actions.activeSecret', \
# '#secretsRead', secretsRead
@set 'secretsRead', ++secretsRead
# console.log '@activeSecret', 'active'
commentAdded: (comment) ->
@comments.unshiftObject comment
nextInQueue: () ->
applicationController = @get 'controllers.application'
secret = @queue.shiftObject()
if secret
content = secret
applicationController.send('newSecret', secret) if secret
# console.log '@nextInQueue', 'secret active'
else
content = null
@_noSecretSwitch()
# console.log '@nextInQueue', 'no secrets'
@set 'content', content
addComment: () ->
@commentValidate()
if @get('comment.valid')
socket.emit 'add comment',
ip_address: window.staticIP
message: @get('comment.value')
belongsTo: null
@set('comment.value', '')
count = @get('comment.count')
@set('comment.count', ++count)
toggleComments: () ->
if @get('commentsEnabled') \
then @set('commentsEnabled', false) \
else @set('commentsEnabled', true)
reportSecret: () ->
socket.emit 'report secret'
applicationController = @get 'controllers.application'
applicationController.send 'flash', 'Thanks! -- The NSA', 'success'
applicationController.send 'reset'
@clearContent()
clearSecretSwitch: () -> @_clearSecretSwitch()
noSecretSwitch: () -> @_noSecretSwitch()
confirmNSA: () ->
# console.log 'indexController', '@actions.confirmNSA', 'hit'
window.location.href = "http://www.whitehouse.gov/" + \
"our-government/the-constitution"
confirmNotNSA: () ->
# console.log 'indexController', '@actions.confirmNotNSA', 'hit'
@set 'nsaCheck', false
module.exports = (SnapSecret) ->
SnapSecret.ConfessRoute = Ember.Route.extend
model: () -> {}
activate: () ->
@controllerFor('application').set 'confessRoute', true
# console.log 'confess route', 'update count'
@controllerFor('confess').updateSecretCount()
deactivate: () ->
applicationController = @controllerFor('application')
applicationController.set 'confessRoute', false
applicationController.flashClear()
module.exports = (SnapSecret) ->
SnapSecret.IndexRoute = Ember.Route.extend
activate: () ->
indexController = @controllerFor 'index'
applicationController = @controllerFor 'application'
# console.log 'here'
queueFlash = indexController.get 'queueFlash'
# console.log queueFlash
if queueFlash.message and queueFlash.type
applicationController.send 'flash', queueFlash.message, queueFlash.type
indexController.set 'queueFlash.message', null
indexController.set 'queueFlash.type', null
applicationController.set 'indexRoute', true
indexController.send 'noSecretSwitch'
deactivate: () ->
@controllerFor('application').set 'indexRoute', false
@controllerFor('index').send 'clearSecretSwitch'
module.exports = (SnapSecret) ->
SnapSecret.Router.map () ->
@route 'read'
@route 'confess'
@route 'what'
@route 'terms'
@route 'privacy'
@route 'use'
if window.history and window.history.pushState
SnapSecret.Router.reopen
location: 'history'
<div class="clearfix">
<form accept-charset="UTF-8" action="/confess" class="new_secret" id="new_secret" method="post" role="form">
<div class="form-group">
{{view Ember.TextArea
valueBinding=message.value
disabledBinding=disableForm
placeholder="tell us a secret..."
class="form-control"
rows="5"
}}
<span {{bind-attr class=":message-requirements message.valid disableForm:secret-invalid"}}>Secret between 10 and 500 words.</span>
</div>
<div class="form-group">
{{view Ember.TextField
valueBinding=name
disabledBinding=disableForm
placeholder="name (optional)"
class="form-control optional"
}}
{{view Ember.TextField
valueBinding=location
disabledBinding=disableForm
placeholder="location (optional)"
class="form-control optional"
}}
{{#view SnapSecret.CommentableButtonView}}
comments <span {{bind-attr class="commentable:enabled:disabled"}}>{{commentableCurrent}}</class>
{{/view}}
</div>
<input type="submit" class="btn btn-default" value="confess" {{action confessSecret}}{{bind-attr disabled=disableForm}}>
</form>
</div>
<div {{bindAttr class=":secret-index nsaCheck showComments"}}>
{{#if nsaCheck}}
<p>
<span>you've read {{secretsRead}} secrets, are you in the NSA?&nbsp;</span>
<button class="btn btn-default" {{action confirmNSA}}>yes</button>&nbsp;
<button class="btn btn-default" {{action confirmNotNSA}}>no</button>
</p>
{{else}}
{{#if secret}}
<div><p>{{secret.message}}</p></div>
{{#if secret.name}}
{{#if secret.location}}
<p><i>Posted by: {{secret.name}} from {{secret.location}}</i></p>
{{else}}
<p><i>Posted by: {{secret.name}}</i></p>
{{/if}}
{{else}}
{{#if secret.location}}
<p><i>Posted from: {{secret.location}}</i></p>
{{/if}}
{{/if}}
<p><i>Seen by: {{secret.view_count}}</i></p>
{{else}}
<p {{bind-attr class="waitingMessage:hide:active"}}>all secrets sealed :(</p>
<p {{bind-attr class="waitingMessage:active:hide"}}>waiting for another<span class="ellipses"></span></p></p>
<p>{{#link-to 'confess'}}leak one{{/link-to}}.</p>
{{/if}}
{{/if}}
</div>
{{#unless nsaCheck}}
{{#if secret}}
{{#if commentable}}
{{#if showComments}}
<div class="secret-comments">
<div class="comments">
{{#each comments}}
<div class="comment">
<p>{{this.message}}&nbsp;<i>{{format-date this.timestamp}}</i></p>
</div>
{{else}}
<div class="comment">
<p><i>no comments...</i></p>
</div>
{{/each}}
</div>
<form accept-charset="UTF-8" action="/index" class="new_comment form-inline" id="new_comment" method="post" role="form">
<div class="form-group">
{{#if comment.valid}}
{{view Ember.TextField
valueBinding=comment.value
placeholder="add a comment..."
class="form-control"
}}
{{else}}
{{view Ember.TextField
disabled=true
placeholder="one comment per secret..."
class="form-control"
}}
{{/if}}
</div>
<input type="submit" class="btn btn-default" value="comment" {{action addComment}}{{bind-attr disabled=comment.inValid}}>
</form>
</div>
<button class="btn btn-default show-comments-btn" {{action toggleComments}}>hide comments</button>
{{else}}
<button class="btn btn-default show-comments-btn" {{action toggleComments}}>show comments</button>
{{/if}}
{{/if}}
{{#view SnapSecret.BlowTheWhistleButton}}blow the whistle{{/view}}
{{/if}}
{{/unless}}
module.exports = (SnapSecret) ->
SnapSecret.CommentableButtonView = Ember.View.extend
tagName: 'a'
classNames: ['btn', 'btn-default']
attributeBindings: ['disabled']
disabled: (() ->
@get('controller').get('disableForm')
).property('disabled')
titleHelper: () ->
value = if @get('controller').get('commentable') then 'off' else 'on'
"click to turn #{value} commenting"
click: () ->
@get('controller').send 'toggleComments'
newTitle = @titleHelper()
$(@get('element')).attr('title', newTitle)
.tooltip('fixTitle')
.data('bs.tooltip')
.$tip.find('.tooltip-inner')
.text(newTitle)
didInsertElement: () ->
title = @titleHelper()
$(@get('element')).tooltip
title: title
module.exports = (SnapSecret) ->
SnapSecret.BlowTheWhistleButton = Ember.View.extend
tagName: 'a'
classNames: ['btn', 'btn-default', 'show-comments-btn']
click: () ->
@get('controller').send 'reportSecret'
didInsertElement: () ->
$(@get('element')).tooltip
title: 'report if the secret is abusive, etc.'
placement: 'right'
class API
constructor: (Secret, expiry = 60) ->
@Secret = Secret
@DEFAULT_COUNTER = expiry
@activeExpiry = @DEFAULT_COUNTER
@activeSecret = null
@totalRead = 0
@totalSpilled = 0
@initSecretStats()
API::initSecretStats = () ->
@Secret.count
displayed: true
, (error, count) =>
unless error
@totalSpilled = count
@Secret.find
displayed: true
, (error, secrets) =>
unless error
totalRead = 0
secrets.forEach (secret) =>
totalRead += secret.view_count
@totalRead = totalRead
API::initIO = (io) ->
io.on "connection", (socket) =>
socket.on "create secret", (reqIO) =>
reqIO.view_count = io.sockets.clients().length
@_createSecret reqIO, socket, () =>
# When this callback is called, activesecret send to sockets
@totalRead += @activeSecret.view_count
@totalSpilled += 1
io.sockets.emit "spill secret", @_serializeSecret()
socket.on 'add comment', (reqIO) =>
@_addComment reqIO, socket, (comment) =>
io.sockets.emit "comment added", @_serializeComment comment
socket.on 'report secret', () => @_reportSecret()
API::getActiveSecret = () ->
if @activeSecret then @_serializeSecret() else null
API::getActiveExpiry = () ->
if @activeSecret then @activeExpiry else null
API::getActiveCommentCount = (ip_address) ->
if @activeSecret
comments = @activeSecret.comments.filter (comment) ->
comment.ip_address == ip_address
comments.length
else
0
API::getSecretStats = () ->
totalRead: @totalRead
totalSpilled: @totalSpilled
API::_serializeSecret = () ->
if @activeSecret
id: @activeSecret.id
message: @activeSecret.message
view_count: @activeSecret.view_count
queue_estimate: @activeSecret.queue_estimate
commentable: @activeSecret.commentable
comments: @activeSecret.comments.map (comment) =>
@_serializeComment comment
name: if @activeSecret.name \
then @activeSecret.name \
else null
location: if @activeSecret.location \
then @activeSecret.location \
else null
API::_serializeComment = (comment) ->
if comment
id: comment.id
message: comment.message
orignal_poster: comment.orignal_poster
timestamp: comment.date
API::_reset = () ->
@activeSecret = null
@activeExpiry = @DEFAULT_COUNTER
API::_createSecret = (reqIO, socket, resIO) ->
secret = new @Secret
message: reqIO.message
ip_address: reqIO.ip_address
view_count: reqIO.view_count
name: reqIO.name
location: reqIO.location
commentable: reqIO.commentable
secret.save (error) =>
unless error
@Secret.count
displayed: false
, (error, count) =>
unless error
unless @activeSecret
@_spillSecret secret, resIO
response = 0
else
response = --count
# Give the secret spiller some info about their secret.
socket.emit 'create secret response', response
API::_spillSecret = (instance, resIO) ->
@activeSecret = instance
@_startTheClock(resIO)
resIO()
API::_startTheClock = (resIO) ->
interval = setInterval () =>
console.log @activeExpiry
if @activeExpiry is 0
clearInterval interval
@_expireSecret(resIO)
else
@activeExpiry--
, 1000
API::_reportSecret = () ->
@Secret.findOne
_id: @activeSecret.id
, (error, secret) =>
unless error
reports = secret.reports
secret.reports = ++reports
secret.save
API::_expireSecret = (resIO) ->
@Secret.findOneAndUpdate
_id: @activeSecret.id
, displayed: true
, {}
, (error) =>
if error
@_reset()
else
@_kickTheQueue(resIO)
API::_kickTheQueue = (resIO) ->
@Secret.findOne
displayed: false
, (error, secret) =>
@_reset()
unless error
if secret
@_spillSecret secret, resIO
API::_addComment = (reqIO, socket, resIO) ->
secret = @activeSecret
comment =
message: reqIO.message
ip_address: reqIO.ip_address
secret.comments.push comment
secret.save (error) =>
unless error
resIO comment
module.exports = () -> API
express = require 'express'
http = require 'http'
path = require 'path'
app = express()
mongoose = require 'mongoose'
if app.get('env') is 'development'
mongoose.connect 'mongodb://localhost/snapsecret'
else
mongoose.connect process.env.MONGOHQ_URL
db = mongoose.connection
db.on 'error', console.error.bind(console, 'connection error:')
db.once 'open', () ->
console.log 'DB CONNECTION'
app.set 'port', process.env.PORT || 3000
app.set 'views', path.join(__dirname, '../', 'views')
app.set 'view engine', 'jade'
app.set 'trust proxy', true
app.use express.favicon()
app.use express.logger('dev')
app.use express.json()
app.use express.urlencoded()
app.use express.methodOverride()
app.use app.router
app.use express.static(path.join(__dirname, '../', 'public'))
if app.get('env') is 'development'
app.use express.errorHandler()
server = http.createServer app
io = require('socket.io').listen server
Secret = require('./models')('secret')()
API = require('./api')()
api = new API(Secret)
api.initIO io
indexRoute = (req, res) ->
Secret.find
ip_address: req.ip
created_at:
$gte: new Date Date.now() - 60 * 60 * 1000
, (error, secrets) ->
secretTimes = []
if error
console.log "Failed to get secrets, #{error}"
else
secrets.forEach (secret) ->
secretTimes.push secret.created_at.getTime()
res.render 'index',
title: 'snapsecret'
activeSecret: JSON.stringify api.getActiveSecret()
activeCommentCount: JSON.stringify api.getActiveCommentCount(req.ip)
activeExpiry: JSON.stringify api.getActiveExpiry()
secretTimes: JSON.stringify secretTimes
secretStats: JSON.stringify api.getSecretStats()
staticIP: JSON.stringify req.ip
# Ember Routes (to work with History API)
app.get '/', indexRoute
app.get '/read', indexRoute
app.get '/confess', indexRoute
app.get '/what', indexRoute
app.get '/terms', indexRoute
app.get '/privacy', indexRoute
app.get '/use', indexRoute
server.listen app.get('port'), () ->
console.log "Express server listening on port #{app.get('port')}"
mongoose = require 'mongoose'
module.exports = () ->
Schema = mongoose.Schema
commentSchema = new Schema
message:
type: String
required: 'Comment needs a body'
date:
type: Date
default: Date.now
ip_address:
type: String
required: 'No IP'
orignal_poster:
type: Boolean
default: false
secretSchema = new Schema
message:
type: String
required: 'Whoops'
ip_address:
type: String
required: 'No IP'
commentable:
type: Boolean
default: true
displayed:
type: Boolean
default: false
view_count:
type: Number
default: 0
created_at:
type: Date
default: Date.now
reports:
type: Number
default: 0
name: String
location: String
queue_estimate: Number
comments: [commentSchema]
Secret = mongoose.model 'Secret', secretSchema
# Validate 2 secrets per hour
# Secret.schema.path('ip_address').validate (value, respond) ->
# Secret.find
# ip_address: value
# created_at:
# $gte: new Date Date.now() - 60 * 60 * 1000
# , (error, secrets) ->
# if error
# console.log "Failed to get secrets, #{error}"
# respond false
# else
# respond secrets.length < 2
# , 'easy there, snowden. 2 secrets per hour'
Secret
doctype 5
html
head
title= title
link(rel='stylesheet', href='/stylesheets/application.css')
script(src='/socket.io/socket.io.js')
script(type='text/javascript', src='/javascripts/application.js')
script(type='text/javascript')!=
window.activeSecret = !{activeSecret};
window.activeExpiry = !{activeExpiry};
window.secretTimes = !{secretTimes};
window.activeCommentCount = !{activeCommentCount};
window.secretStats = !{secretStats};
window.staticIP = !{staticIP};
body
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment