In this post I’ll walk through building a simple Blum Mental Hash application using Node and Angular. I’ll write my Node and Angular code using CoffeeScript, and I’ll build my HTML templates with Jade.
Writing the Application in CoffeeScript
I really enjoy CoffeeScript. I get that real programmers don’t use CoffeeScript, but I don’t care. Javascript makes me crazy. This is my CoffeeScript code–I require a bunch of stuff: express
, http
, jade
. Then I define an express
object named app
and set some settings on it. Then I tell the root path, '/'
, to use the './static'
subdirectory on the server. Then I tell any GET
requests to '/'
to return HTML that’s been rendered by jade
using my index.jade
template.
#!/usr/bin/env node
# app.coffee
express = require "express"
http = require "http"
jade = require "jade"
app = express()
app.set( 'views', './static' )
app.set( 'view engine', 'jade' )
app.engine( 'jade', jade.__express )
app.use '/', express.static('./static')
app.get '/', ( req, res ) ->
res.render( 'index.jade' )
server = app.listen 8000, ->
host = server.address().address
port = server.address().port
console.log 'Example at http://%s%s', host, port
We can compile this guy at the command line by calling,
coffee -c app.coffee
This will create an app.js
file in your working directory.
The Controller
The file contoller.coffee
sits in the subdirectory ./static/js/
. The first items, mapping
and perm
, should ideally be picked by the user. In this example I’ve hard coded them for convenience. The convert()
function brings everything together; it combines mapping
and perm
in such a way as to hash a string of capital letters. From there myapp.controller
can compute the hash for the user.
#!/usr/bin/env node
# ./static/js/controller.coffee
mapping =
A: 4, B: 9, C: 4
D: 5, E: 8, F: 5
G: 7, H: 1, I: 8
J: 3, K: 6, L: 8
M: 9, N: 0, O: 9
P: 0, Q: 6, R: 1
S: 9, T: 6, U: 4
V: 7, W: 5, X: 0
Y: 9, Z: 3
f = ( x, mapping ) ->
###
Maps a string `x` to an array of digits
###
a = []
for i in x
a.push( mapping[i] )
return a
perm = [ 8, 2, 5, 4, 9, 0, 3, 7, 1, 6 ]
permute = ( i, perm ) ->
###
Returns the next value in the permutation
###
idx = perm.indexOf( i )
idx = ( idx + 1 ) % 10
return perm[ idx ]
g = ( a, perm ) ->
###
Hashes a list of digits into a string of digits
###
b = [ permute( ( a[0] + a[ a.length-1 ] ) % 10, perm ) ]
for i in [1...a.length]
b.push( permute( ( b[i-1] + a[i] ) % 10, perm ) )
return b.join("")
convert = ( x ) ->
###
Convert a string of characters to a hashed string of digits
###
a = f( x, mapping )
return g( a, perm )
myapp = angular.module( "myapp", [] )
myapp.controller "controller", ($scope) ->
$scope.plain = ""
$scope.b = ""
$scope.update = ( plain ) ->
$scope.b = convert( plain )
This CoffeeScript file should also be compiled into a Javascript file.
The View
The index.jade
file lives in ./static
. This prompts a user for a password, and then returns a hash of that password below. That’s it.
doctype html
html
head
script(src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js")
script(src="/js/controller.js")
link(rel="stylesheet",href="css/style.css")
body(ng-app="myapp")
h1 Manuel Blum's Mental Hash (BMH)
div(ng-controller="controller")
|Password:
input(name="Password: ",type="text",ng-model="plain")
button(ng-click="update(plain)") Convert
p Hash: {{ b }}
We can serve the page by calling
node app.js
from the command line, and then navigating to localhost:5000
.