 ################################################################################
 # Request handlers
 
+links = """
+<div class="links"><a href="/random">Random</a> - <a href="/date/2015">2015</a> - <a href="/date/2016">2016</a> - <a href="/tag">Tags by freq</a> -
+<a href="/tag?sort=alpha">Tags by alpha</a> - <a href="/journal">Journal</a></div>
+"""
 header = """
+<style type="text/css">body { font-family: Arial, sans-serif; }
+ul li { margin-bottom: 0.5em }
+.links { font-size: large; margin-top: 1em; margin-bottom: 1em; clear: both }</style>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
   <script src="https://npmcdn.com/imagesloaded@4.1/imagesloaded.pkgd.min.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/masonry/4.0.0/masonry.pkgd.min.js"></script>
-<a href="/random">Random</a> - <a href="/tag/monthly">Monthly</a><br />
-         """
-footer = """
-<a href="/random">Random</a> - <a href="/tag/monthly">Monthly</a><br />
-  <script>$('.grid').imagesLoaded(function() { $('.grid').masonry({itemSelector: '.grid-item'}); })</script>
-"""
+  """ + links 
+footer = links
+masonry = "<script>$('.grid').imagesLoaded(function() { $('.grid').masonry({itemSelector: '.grid-item'}); })</script>"
 
 linkTags = (filename) ->
-  return filename.replace(/#([-a-zA-Z]+)/g, (x, tag) ->
+  filename = filename.replace(/#([-a-zA-Z]+)/g, (x, tag) ->
     return '<a href="/tag/' + tag + '">' + x + '</a>'
   )
+  filename = filename.replace(/ref .*/, (x) ->
+    return x.replace(/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][a-z]?/, (y) ->
+      return '<a href="/id/' + y + '">' + y + '</a>'
+    )
+  )
+  return filename
     
 linkToImage = (filename, optionalURL) ->
   url = '/image/' + encodeURIComponent(filename)

  res.sendFile filename

formatList = (list, urlFunc, size) ->
  return '<style type="text/css">.grid-item { width: ' + (size || '50%') + ' }</style><div class="grid">' + (list.map((s) ->
    return linkToImage(s, (if urlFunc then urlFunc(s) else null), size)
  ).join '') + '</div>'
  
serveImagesByTag = (req, res) ->
  tag = req.params.tag.split(/,/g)

    res.header "Cache-Control", "no-cache, no-store, must-revalidate"
    res.header "Pragma", "no-cache"
    res.header "Expires", 0
    res.send header + formatList(list) + footer + masonry

showTextList = (req, res, filter) ->
  getSketches(SKETCH_DIR).then (sketches) ->
    list = sketches.filter(filter)
    res.send header + '<ul>' + list.map((filename) ->
      url = '/image/' + encodeURIComponent(filename)
      return '<li><a href="' + url + '">View</a> - ' + linkTags(filename) + '</li>'
    ).join('') + '</ul>' + footer
  
listNonjournalSketches = (req, res) ->
  showTextList(req, res, (s) ->
    return !s.match(/#journal/) && s.match(/^[0-9]/)
  )
    
listJournalSketches = (req, res) ->
  showTextList(req, res, (s) ->
    return s.match(/#journal|#monthly|#yearly/)
  )

serveImageByID = (req, res) ->
  getSketches(SKETCH_DIR).then (sketches) ->
