var express = require('express');
var gm = require('gm');
var hashblot = require('hashblot');

var pdFunctions = {sha1q: hashblot.sha1qpd};

// Raster types we support for retrieval.
var rasterTypes = ['png','jpg','jpeg','gif','bmp','tga'];

module.exports = function appctor(opts) {

var gmopts = opts.gm || {};
  function magickPd(size, pd, type, cb) {
    return gm(size, size, '#fff').options(gmopts)
    .draw([
      'scale', size/255, size/255,
      'fill-rule nonzero',
      'path "' + pd + '"', ].join(' '))
    .toBuffer(type, cb);
  }

  function svgPd(size, pd) {
    return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 255 255" '
      + 'width="' + size + '" height="'+ size + '">'
      + '<path d="'+ pd + '" /></svg>';
  }

  function hashpathImage(req, res, next) {
    var hashpath = req.params.hashpath;
    var str = req.params.input;
    var pd;
    if (pdFunctions[hashpath]) {
      pd = pdFunctions[hashpath](str);
    } else return next();

    var extension = req.params.extension.toLowerCase();
    if (extension != 'svg' && ~rasterTypes.indexOf(extension))
      return next();

    var size;

    try {
      size = parseInt(req.params.size, 10);
    } catch(err) {
      return res.status(400).send('Invalid image size');
    }
    if (size < 15) {
      res.redirect('/'+ encodeURIComponent(hashpath)
        + '/15/' + encodeURIComponent(str)
        + '.' + encodeURIComponent(extension));
    } if (size > 2048) {
      res.redirect('/'+ encodeURIComponent(hashpath)
        + '/2048/' + encodeURIComponent(str)
        + '.' + encodeURIComponent(extension));
    }

    if (extension == 'svg') {
      res.type('svg');
      res.send(svgPd(size,pd));
    } else { // image is a raster type we support
      magickPd(size, pd, extension, function(err, buffer) {
        if (err) return next(err);
        res.type(extension);
        res.send(buffer);
      });
    }
  }

  var app = express();

  app.get('/:hashpath/:size/:input(|[^/]+?).:extension', hashpathImage);

  return app;
};

@@ -91,52 +91,38 @@
 ');%0A
-%0A
 var 
-pdFunctions = %7Bsha1q: hashblot.sha1qpd%7D
+crypto = require('crypto')
 ;%0A%0A/
@@ -778,42 +778,273 @@
 ) %7B%0A
-    var hashpath = req.params.hash
+%0A    // 404 for extensions we don't support%0A    var extension = req.params.extension.toLowerCase();%0A    if (extension != 'svg' && ~rasterTypes.indexOf(extension))%0A      return next();%0A%0A    var hashType = req.params.hash;%0A    var hash;%0A    var pathType = req.params.
 path
@@ -1093,231 +1093,462 @@
 pd;%0A
+%0A
     
-if (pdFunctions%5Bhashpath%5D) %7B%0A      pd = pdFunctions%5Bhashpath%5D(str);%0A    %7D else return next(
+// If there's a hashblot function for the path type,%0A    // define a path from the byte-array-ified buffer for the given hash,%0A    // and 404 otherwise%0A    if (hashblot.pd%5BpathType%5D) %7B%0A      try %7B%0A        hash = crypto.createHash(hashType
 );%0A
-%0A
     
-var extension = req.params.extension.toLowerCase();%0A    if (extension != 'svg' && ~rasterTypes.indexOf(extension
+  %7D catch (err) %7B%0A        // 404 when the hash type is not supported%0A        return next();%0A      %7D%0A      pd = hashblot.pd%5BpathType%5D(Array.apply(%5B%5D,%0A        hash.update(str, 'utf8').digest()
 ))
+;
 %0A    
- 
+%7D else
  ret
@@ -1707,24 +1707,25 @@
 ze');%0A    %7D%0A
+%0A
     if (size
@@ -1747,32 +1747,33 @@
 res.redirect('/'
+ 
 + encodeURICompo
@@ -1773,36 +1773,81 @@
 RIComponent(hash
-path
+Type)%0A        + '/' + encodeURIComponent(pathType
 )%0A        + '/15
@@ -1970,16 +1970,17 @@
 rect('/'
+ 
 + encode
@@ -1996,20 +1996,65 @@
 ent(hash
-path
+Type)%0A        + '/' + encodeURIComponent(pathType
 )%0A      
@@ -2226,16 +2226,17 @@
 Pd(size,
+ 
 pd));%0A  
@@ -2491,24 +2491,26 @@
 .get('/:hash
+/:
 path/:size/:

Generalize hash function separate from hashblot path