Log uncaught exceptions to Sentry

Log uncaught exceptions to Sentry

    "use strict"

    express     = require 'express'
    raven       = require 'raven'

    system      = require './system'
    collection  = require './collection'
    document    = require './document'

## Init

    app = express()

### Authentication

This routine is called for all request to the API. It is reponsible for
authenticating the user by validating the `api\_key`. It then sets some request
session variables so they become accessible throughout the entire system during
the rquest.

In future versions of the API this routine will also check the request quota and
blocking the user if the quota is full.

    app.use '/', (req, res, next) ->

      key = req.query.api_key

      return res.json 403, message: 'API key missing' if not key
      return res.json 401, message: 'API key invalid' if not apiKeys[key]

      req.key = key
      req.usr = apiKeys[key]

      next()

### Configuration

    app.use(express.favicon())
    app.use(express.logger(':date :remote-addr - :method :url :status :res[content-length] - :response-time ms')) if not process.env.SILENT
    app.set('json spaces', 0) if app.get('env') isnt 'testing'
    app.use(express.compress())
    app.use(express.json())
    app.disable('x-powered-by')
    app.enable('verbose errors')
    app.set 'port', process.env.PORT_WWW or 8080
    app.use(app.router)

    if process.env.SENTRY_DNS
      app.use raven.middleware.express process.env.SENTRY_DNS
      raven.patchGlobal process.env.SENTRY_DNS

### Error handling

This is the error handler. All errors passed to `next` or exceptions ends up
here. We set the status code to `500` if it is not already defined in the
`Error` object. We then print the error mesage and stack trace to the console
for debug purposes.

Before returning a response to the user the request method is check. HEAD
requests shall not contain any body – this applies for errors as well.

    app.use (err, req, res, next) ->
      res.status(err.status or 500)

      console.error err.message
      console.error err.stack

      return res.end() if req.method is 'HEAD'
      return res.json message: err.message or 'Ukjent feil'

This the fmous 404 Not Found handler. If no route configuration for the request
is found, it ends up here. We don't do much fancy about it – just a standard
error message and HTTP status code.

    app.use (req, res) -> res.json 404, message: "Resurs ikke funnet"

### API keys

This is the dirty part. Here are all the keys to the kingdom. These will be
moved to the database and retrieved when the server starts. Just need to find
the time to do it.

    apiKeys =
      dnt: 'DNT'
      nrk: 'DNT'

      '30ad3a3a1d2c7c63102e09e6fe4bb253': 'TurApp'
      'b523ceb5e16fb92b2a999676a87698d1': 'Pingdom'

      '4c802ac2315ab24db9c992cc6eea0278': 'DNT' # ETA
      'de2986ac75c5af9d7f92a26f37dc1b77': 'DNT' # sherpa2.api
      '5dd5a39057cb479c3c4bce7f9eae5e6c': 'DNT' # dev.ut.no
      '146bbe01b477e9e07e85e0ddd3f5095a': 'DNT' # beta.ut.no
      'e6fa27292ffbcc689c49179c47bc708e': 'DNT' # prod.ut.no

## GET /

    app.get '/', (req, res) ->
      res.json message: 'Here be dragons'

## GET /system

Hsssssj!!! Don't tell anyone about the secret system API endpoint!

    app.get '/system', system.info

## GET /CloudHealthCheck

> So...You’re seeing the dotCloud active health check looking to make sure that
> your service is up. There is no way for you to disable it, but you can prevent
> it and you can handle it [1]!

[1] [dotCloud](http://docs.dotcloud.com/tutorials/more/cloud-health-check/)

    app.get '/CloudHealthCheck', system.check

## GET /objekttyper

    app.get '/objekttyper', (req, res, next) ->
      res.json 200, ['turer', 'steder', 'områder', 'grupper', 'arrangementer', 'bilder']

## ALL /{collection}

    app.param 'collection', collection.param
    app.all '/:collection', (req, res, next) ->
      switch req.method
        when 'OPTIONS' then collection.options req, res, next
        when 'HEAD', 'GET' then collection.get req, res, next
        when 'POST' then collection.post req, res, next
        when 'PUT'  then collection.put req, res, next
        when 'PATCH' then collection.patch req, res, next
        else res.json 405, message: 'HTTP method not supported'

## ALL /{collection}/{objectid}

    app.param 'objectid', document.param
    app.all '/:collection/:objectid', (req, res, next) ->
      switch req.method
        when 'OPTIONS' then document.options req, res, next
        when 'HEAD', 'GET' then document.get req, res, next
        when 'PUT' then document.put req, res, next
        when 'PATCH' then document.patch req, res, next
        when 'DELETE' then document.delete req, res, next
        else res.json 405, message: 'HTTP method not supported'

## Start

Ok, so if the server is running in stand-alone mode i.e. there is not
`module.parent` then continue with starting the databse and listening to a port.

    if not module.parent
      require('./db/redis')
      require('./db/mongo').once 'ready', ->
        console.log 'Database is open...'

        app.listen app.get('port'), ->
          console.log "Server is listening on port #{app.get('port')}"

However, if there is a `module.parent` don't do all the stuff above. This means
that there is some program that is including the server from it, e.g a test, and
hence it should not listen to a port for incomming connections and rather just
return the application instance so that we can do some testing on it.

    else
      module.exports = app

    "use strict"

    express     = require 'express'
    raven       = require 'raven'

    system      = require './system'
    collection  = require './collection'
    document    = require './document'

## Init

    app = express()

### Authentication

This routine is called for all request to the API. It is reponsible for
authenticating the user by validating the `api\_key`. It then sets some request
session variables so they become accessible throughout the entire system during
the rquest.

In future versions of the API this routine will also check the request quota and
blocking the user if the quota is full.

    app.use '/', (req, res, next) ->

      key = req.query.api_key

      return res.json 403, message: 'API key missing' if not key
      return res.json 401, message: 'API key invalid' if not apiKeys[key]

      req.key = key
      req.usr = apiKeys[key]

      next()

### Configuration

    app.use(express.favicon())
    app.use(express.logger(':date :remote-addr - :method :url :status :res[content-length] - :response-time ms')) if not process.env.SILENT
    app.set('json spaces', 0) if app.get('env') isnt 'testing'
    app.use(express.compress())
    app.use(express.json())
    app.disable('x-powered-by')
    app.enable('verbose errors')
    app.set 'port', process.env.PORT_WWW or 8080
    app.use(app.router)
    app.use(raven.middleware.express(process.env.SENTRY_DNS)) if process.env.SENTRY_DNS

### Error handling

This is the error handler. All errors passed to `next` or exceptions ends up
here. We set the status code to `500` if it is not already defined in the
`Error` object. We then print the error mesage and stack trace to the console
for debug purposes.

Before returning a response to the user the request method is check. HEAD
requests shall not contain any body – this applies for errors as well.

    app.use (err, req, res, next) ->
      res.status(err.status or 500)

      console.error err.message
      console.error err.stack

      return res.end() if req.method is 'HEAD'
      return res.json message: err.message or 'Ukjent feil'

This the fmous 404 Not Found handler. If no route configuration for the request
is found, it ends up here. We don't do much fancy about it – just a standard
error message and HTTP status code.

    app.use (req, res) -> res.json 404, message: "Resurs ikke funnet"

### API keys

This is the dirty part. Here are all the keys to the kingdom. These will be
moved to the database and retrieved when the server starts. Just need to find
the time to do it.

    apiKeys =
      dnt: 'DNT'
      nrk: 'DNT'

      '30ad3a3a1d2c7c63102e09e6fe4bb253': 'TurApp'
      'b523ceb5e16fb92b2a999676a87698d1': 'Pingdom'

      '4c802ac2315ab24db9c992cc6eea0278': 'DNT' # ETA
      'de2986ac75c5af9d7f92a26f37dc1b77': 'DNT' # sherpa2.api
      '5dd5a39057cb479c3c4bce7f9eae5e6c': 'DNT' # dev.ut.no
      '146bbe01b477e9e07e85e0ddd3f5095a': 'DNT' # beta.ut.no
      'e6fa27292ffbcc689c49179c47bc708e': 'DNT' # prod.ut.no

## GET /

    app.get '/', (req, res) ->
      res.json message: 'Here be dragons'

## GET /system

Hsssssj!!! Don't tell anyone about the secret system API endpoint!

    app.get '/system', system.info

## GET /CloudHealthCheck

> So...You’re seeing the dotCloud active health check looking to make sure that
> your service is up. There is no way for you to disable it, but you can prevent
> it and you can handle it [1]!

[1] [dotCloud](http://docs.dotcloud.com/tutorials/more/cloud-health-check/)

    app.get '/CloudHealthCheck', system.check

## GET /objekttyper

    app.get '/objekttyper', (req, res, next) ->
      res.json 200, ['turer', 'steder', 'områder', 'grupper', 'arrangementer', 'bilder']

## ALL /{collection}

    app.param 'collection', collection.param
    app.all '/:collection', (req, res, next) ->
      switch req.method
        when 'OPTIONS' then collection.options req, res, next
        when 'HEAD', 'GET' then collection.get req, res, next
        when 'POST' then collection.post req, res, next
        when 'PUT'  then collection.put req, res, next
        when 'PATCH' then collection.patch req, res, next
        else res.json 405, message: 'HTTP method not supported'

## ALL /{collection}/{objectid}

    app.param 'objectid', document.param
    app.all '/:collection/:objectid', (req, res, next) ->
      switch req.method
        when 'OPTIONS' then document.options req, res, next
        when 'HEAD', 'GET' then document.get req, res, next
        when 'PUT' then document.put req, res, next
        when 'PATCH' then document.patch req, res, next
        when 'DELETE' then document.delete req, res, next
        else res.json 405, message: 'HTTP method not supported'

## Start

Ok, so if the server is running in stand-alone mode i.e. there is not
`module.parent` then continue with starting the databse and listening to a port.

    if not module.parent
      require('./db/redis')
      require('./db/mongo').once 'ready', ->
        console.log 'Database is open...'

        app.listen app.get('port'), ->
          console.log "Server is listening on port #{app.get('port')}"

However, if there is a `module.parent` don't do all the stuff above. This means
that there is some program that is including the server from it, e.g a test, and
hence it should not listen to a port for incomming connections and rather just
return the application instance so that we can do some testing on it.

    else
      module.exports = app


add said nothing post

add said nothing post

# Super secret queue methods

    @QueueMethods =
      popAndServeNextTicket: ->

Move the current connection to the processed queue

TODO: get postID

        queueMeta = QueueMeta.findOne()

Update object, extended at various point for updating the QueueMeta in one swoop

        update =
          $set: {}

If `theOnlyConnectionAllowedIn` is set to something, check if the connection
has expired and process the connection if it has.

        if queueMeta.theOnlyConnectionAllowedIn isnt undefined

          previousConnection = queueMeta.theOnlyConnectionAllowedIn
          previousConnectionDidntPosted = not queueMeta.hasCurrentConnectionPosted

Return if timeCurrentTicketExpires is in the future (hasn't expired)

          hasntExpired = queueMeta.timeCurrentTicketExpires > moment.utc().toDate()
          return if hasntExpired

Okay then, the current connection has expired, time to get bumped.
Insert the processed connection into the ProcessedQueue

          try

Calculate how long the connection had to wait in line.

            waitTimeSeconds = moment.utc().diff (moment.utc queueMeta.theOnlyConnectionAllowedIn.timeEnqueued), 'seconds'

Make the processed object.

            processed =
              connection: queueMeta.theOnlyConnectionAllowedIn
              waitTimeSeconds: waitTimeSeconds

Insert the processed connection to `QueueProcessed`

            QueueProcessed.insert processed
          catch err
            console.log err

Remove the connection from the `Queue`

          criteria = connectionId: queueMeta.theOnlyConnectionAllowedIn.connectionId
          Queue.remove criteria

Update `QueueMeta` stats and ticket number.

          try
            totalWaitTimeSeconds = queueMeta.totalWaitTimeSeconds + waitTimeSeconds
            currentlyServingTicketNumber = queueMeta.currentlyServingTicketNumber + 1
            _.extend update.$set,
              currentlyServingTicketNumber: currentlyServingTicketNumber
              hasCurrentConnectionPosted: no
              totalWaitTimeSeconds: totalWaitTimeSeconds
          catch err
            console.log err

Lookup the lowest ticket # waiting in the `Queue`

        nextConnection = Queue.findOne {}, $sort: [ 'ticketNumber': 'asc' ]

Set the allowed connection and expireTime if one exists

If there is a nextConnection (i.e. someone waiting in line), then serve them.
Otherwise clear out theOnlyConnectionAllowedIn.

        if nextConnection?
          timeCurrentTicketExpires = moment.utc()
          timeCurrentTicketExpires.add 1, 'minutes'
          _.extend update.$set,
            theOnlyConnectionAllowedIn: nextConnection
            timeCurrentTicketExpires: timeCurrentTicketExpires.toDate()
            currentlyServingTicketNumber: nextConnection.ticketNumber

If there is no nextConnection, unset theOnlyConnectionAllowedIn.
Note, fake data is filled in to pass schema, even though we're $unset'ing

        else
          update.$unset = theOnlyConnectionAllowedIn: ""

        criteria = _id: queueMeta._id

Delete `update.$set` if it's empty

        if _.isEmpty update.$set
          delete update.$set

If `update` isn't empty, update!

        if not _.isEmpty update
          QueueMeta.update criteria, update

If previousConnection connection didn't post, post for her

        if previousConnectionDidntPosted
          post =
            name: previousConnection.name
            message: 'Had nothing to say...'
            connectionId: previousConnection.connectionId
            ticketNumber: previousConnection.ticketNumber

          Posts.insert post

TODO: keep it DRY; logic isn't exactly shared and want to keep update atomic to
avoid extraneous DDP messages.

## Disconnect, remove from queue

    Meteor.onConnection (connection) ->
      connection.onClose ->

Remove the connection from the `Queue`

          criteria = connectionId: connection.id
          Queue.remove criteria

# Super secret queue methods

    @QueueMethods =
      popAndServeNextTicket: ->

Move the current connection to the processed queue

TODO: get postID

        queueMeta = QueueMeta.findOne()

Update object, extended at various point for updating the QueueMeta in one swoop

        update =
          $set: {}

If `theOnlyConnectionAllowedIn` is set to something, check if the connection
has expired and process the connection if it has.

        if queueMeta.theOnlyConnectionAllowedIn isnt undefined

Return if timeCurrentTicketExpires is in the future (hasn't expired)

          hasntExpired = queueMeta.timeCurrentTicketExpires > moment.utc().toDate()
          return if hasntExpired

Okay then, the current connection has expired, time to get bumped.
Insert the processed connection into the ProcessedQueue

          try

Calculate how long the connection had to wait in line.

            waitTimeSeconds = moment.utc().diff (moment.utc queueMeta.theOnlyConnectionAllowedIn.timeEnqueued), 'seconds'

Make the processed object.

            processed =
              connection: queueMeta.theOnlyConnectionAllowedIn
              waitTimeSeconds: waitTimeSeconds

Insert the processed connection to `QueueProcessed`

            QueueProcessed.insert processed
          catch err
            console.log err

Remove the connection from the `Queue`

          criteria = connectionId: queueMeta.theOnlyConnectionAllowedIn.connectionId
          Queue.remove criteria

Update `QueueMeta` stats and ticket number.

          try
            totalWaitTimeSeconds = queueMeta.totalWaitTimeSeconds + waitTimeSeconds
            currentlyServingTicketNumber = queueMeta.currentlyServingTicketNumber + 1
            _.extend update.$set,
              currentlyServingTicketNumber: currentlyServingTicketNumber
              hasCurrentConnectionPosted: no
              totalWaitTimeSeconds: totalWaitTimeSeconds
          catch err
            console.log err

Lookup the lowest ticket # waiting in the `Queue`

        nextConnection = Queue.findOne {}, $sort: [ 'ticketNumber': 'asc' ]

Set the allowed connection and expireTime if one exists

If there is a nextConnection (i.e. someone waiting in line), then serve them.
Otherwise clear out theOnlyConnectionAllowedIn.

        if nextConnection?
          timeCurrentTicketExpires = moment.utc()
          timeCurrentTicketExpires.add 1, 'minutes'
          _.extend update.$set,
            theOnlyConnectionAllowedIn: nextConnection
            timeCurrentTicketExpires: timeCurrentTicketExpires.toDate()
            currentlyServingTicketNumber: nextConnection.ticketNumber

If there is no nextConnection, unset theOnlyConnectionAllowedIn.
Note, fake data is filled in to pass schema, even though we're $unset'ing

        else
          update.$unset = theOnlyConnectionAllowedIn: ""

        criteria = _id: queueMeta._id

Delete `update.$set` if it's empty

        if _.isEmpty update.$set
          delete update.$set

If `update` isn't empty, update!

        if not _.isEmpty update
          QueueMeta.update criteria, update

TODO: keep it DRY; logic isn't exactly shared and want to keep update atomic to
avoid extraneous DDP messages.

## Disconnect, remove from queue

    Meteor.onConnection (connection) ->
      connection.onClose ->

Remove the connection from the `Queue`

          criteria = connectionId: connection.id
          Queue.remove criteria


add docs for Enumerable::inGroupsOf

add docs for Enumerable::inGroupsOf

# /api/Data Structures/Batman.Enumerable

`Batman.Enumerable` is a mixin that defines methods available for every
enumerable type (`Batman.Set` and `Batman.Hash` being the main two).

Note that where the signature of the callback functions is defined, `element`
is the value of the current element being iterated over, and `value` is
`null`—except in the case of `Batman.Hash` where `element` is the key and
`value` is the value.

## Implementing your own `Batman.Enumerable`

To make these methods available for a new type, all you need to do is define
`forEach()` and `length`. Then, in your type, you can just `Batman.extend
@prototype, Batman.Enumerable` to copy the `Enumerable` methods onto your
prototype.

## ::.length : number

The number of elements.

## ::forEach(func)

Calls `func` once for each element.
`func` receives the arguments `(element, value, this)`

    test "forEach runs n times", ->
      set = new Batman.Set('a', 'b')
      count = 0
      set.forEach -> count++
      equal count, 2

## ::map(func[, context = Batman.container]) : Array

Calls `func` once for each element, and returns an array composed of the return
value at each iteration.  `func` receives the arguments `(element, value,
this)`

    test "forEach runs n times", ->
      set = new Batman.Set(1, 2)
      deepEqual [2, 3], set.map (x) -> x + 1

## ::mapToProperty(key : string) : Array

Returns an array composed of the property specified of each item.
`func` receives the arguments `(element, value, this)`

    test "mapToProperty pulls out the property specified", ->
      set = new Batman.Set({key: 'a'}, {key: 'b'})
      deepEqual ['a', 'b'], set.mapToProperty('key')

## ::every(func[, context = Batman.container]) : boolean

Calls `func` once for each element, and returns true if `func` returns true for
every iteration.  `func` receives the arguments `(element, value, this)`

    test "every is false when any element doesn't satisfy the selector function", ->
      set = new Batman.Set(true, false, true)
      equal false, set.every (x) -> x

## ::some(func[, context = Batman.container]) : boolean

Calls `func` once for each element, and returns true if `func` returns true for
any iteration.  `func` receives the arguments `(element, value, this)`

    test "some is true when any element satisfies the selector function", ->
      set = new Batman.Set(true, false, true)
      equal true, set.some (x) -> x

## ::reduce(func[, accumulator]) : Array

Calls `func` once for each element, accumulating the result as it goes along.
If you pass your own `accumulator` it will retain its initial value, otherwise
the first element will become the initial accumulator value.  `func` receives
the arguments `(accumulator, element, value, index, this)`

    test "reduce can implement a sum", ->
      set = new Batman.Set(1, 2, 3)
      equal 6, set.reduce (accumulator, x) -> accumulator + x

## ::filter(func) : Object

Creates a new instance of the current type, and adds every element for which
`func` returns true.  `func` receives the arguments `(element, value, this)`

    test "filter strips out the crud", ->
      set = new Batman.Set('wheat', 'crud', 'grain')
      deepEqual ['wheat', 'grain'], (set.filter (x) -> x != 'crud').toArray()

## ::count(func) : number

Returns the number of elements for which `func` returns true, or the total
number of elements if you don't pass a `func`.  `func` receives the arguments
`(element, value, this)`

    test "count counts", ->
      set = new Batman.Set(1, 2, 3)
      equal 3, set.count()
      equal 2, set.count (x) -> x > 1

## ::inGroupsOf(groupSize: number) : Array

Splits the enumerable into groups of up to `groupSize` and returns the items in an array of arrays.

  test "inGroupsOf returns an array of arrays", ->
    set = new Batman.Set(1,2,3,4,5,6,7,8)
    groups = set.inGroupsOf(3)
    equal 3, groups[0].length
    equal 3, groups[1].length
    equal 2, groups[2].length, "The last group might be smaller"

# /api/Data Structures/Batman.Enumerable

`Batman.Enumerable` is a mixin that defines methods available for every
enumerable type (`Batman.Set` and `Batman.Hash` being the main two).

Note that where the signature of the callback functions is defined, `element`
is the value of the current element being iterated over, and `value` is
`null`—except in the case of `Batman.Hash` where `element` is the key and
`value` is the value.

## ::.length : number

The number of elements.

## ::forEach(func)

Calls `func` once for each element.
`func` receives the arguments `(element, value, this)`

    test "forEach runs n times", ->
      set = new Batman.Set('a', 'b')
      count = 0
      set.forEach -> count++
      equal count, 2

## ::map(func[, context = Batman.container]) : Array

Calls `func` once for each element, and returns an array composed of the return
value at each iteration.  `func` receives the arguments `(element, value,
this)`

    test "forEach runs n times", ->
      set = new Batman.Set(1, 2)
      deepEqual [2, 3], set.map (x) -> x + 1

## ::mapToProperty(key : string) : Array

Returns an array composed of the property specified of each item.
`func` receives the arguments `(element, value, this)`

    test "mapToProperty pulls out the property specified", ->
      set = new Batman.Set({key: 'a'}, {key: 'b'})
      deepEqual ['a', 'b'], set.mapToProperty('key')

## ::every(func[, context = Batman.container]) : boolean

Calls `func` once for each element, and returns true if `func` returns true for
every iteration.  `func` receives the arguments `(element, value, this)`

    test "every is false when any element doesn't satisfy the selector function", ->
      set = new Batman.Set(true, false, true)
      equal false, set.every (x) -> x

## ::some(func[, context = Batman.container]) : boolean

Calls `func` once for each element, and returns true if `func` returns true for
any iteration.  `func` receives the arguments `(element, value, this)`

    test "some is true when any element satisfies the selector function", ->
      set = new Batman.Set(true, false, true)
      equal true, set.some (x) -> x

## ::reduce(func[, accumulator]) : Array

Calls `func` once for each element, accumulating the result as it goes along.
If you pass your own `accumulator` it will retain its initial value, otherwise
the first element will become the initial accumulator value.  `func` receives
the arguments `(accumulator, element, value, index, this)`

    test "reduce can implement a sum", ->
      set = new Batman.Set(1, 2, 3)
      equal 6, set.reduce (accumulator, x) -> accumulator + x

## ::filter(func) : Object

Creates a new instance of the current type, and adds every element for which
`func` returns true.  `func` receives the arguments `(element, value, this)`

    test "filter strips out the crud", ->
      set = new Batman.Set('wheat', 'crud', 'grain')
      deepEqual ['wheat', 'grain'], (set.filter (x) -> x != 'crud').toArray()

## ::count(func) : number

Returns the number of elements for which `func` returns true, or the total
number of elements if you don't pass a `func`.  `func` receives the arguments
`(element, value, this)`

    test "count counts", ->
      set = new Batman.Set(1, 2, 3)
      equal 3, set.count()
      equal 2, set.count (x) -> x > 1

## Implementing your own `Batman.Enumerable`

To make these methods available for a new type, all you need to do is define
`forEach()` and `length`. Then, in your type, you can just `Batman.extend
@prototype, Batman.Enumerable` to copy the `Enumerable` methods onto your
prototype.