Permalink
Browse files

first shot at keygen

  • Loading branch information...
1 parent 55585aa commit 71836b03603bddbad9d5f815477f46e239197fa7 @sean-devmode sean-devmode committed Aug 1, 2012
Showing with 215 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +86 −0 Cakefile
  3. +1 −0 README.md
  4. +23 −0 src/index.coffee
  5. +6 −0 src/matrix.coffee
  6. +6 −0 { → src}/package.json
  7. +44 −0 test/keygen_test.coffee
  8. +45 −0 test/matrix_test.coffee
View
@@ -0,0 +1,4 @@
+bin
+docs
+node_modules
+
View
@@ -0,0 +1,86 @@
+fs = require 'fs'
+{print, pump} = require 'util'
+{spawn, exec} = require 'child_process'
+
+# ANSI Terminal Colors
+bold = '\x1B[0;1m'
+red = '\x1B[0;31m'
+green = '\x1B[0;32m'
+reset = '\x1B[0m'
+
+pkg = JSON.parse fs.readFileSync('./src/package.json')
+testCmd = pkg.scripts.test
+startCmd = pkg.scripts.start
+
+log = (message, color, explanation) ->
+ console.log color + message + reset + ' ' + (explanation or '')
+
+# Compiles app.coffee and src directory to the app directory
+copy = (src, dst, callback) ->
+ pump fs.createReadStream(src), fs.createWriteStream(dst), callback
+
+build = (callback) ->
+ copy './src/package.json', './bin/package.json', (err) ->
+ options = ['-c', '-b', '-o', 'bin', 'src']
+ coffee = spawn 'coffee', options
+ coffee.stdout.pipe process.stdout
+ coffee.stderr.pipe process.stderr
+ coffee.on 'exit', (status) -> callback?() if status is 0
+
+# mocha test
+test = (callback) ->
+ options = [
+ '--reporter'
+ 'spec'
+ '--compilers'
+ 'coffee:coffee-script'
+ '--colors'
+ '--require'
+ 'assert'
+ '--require'
+ 'should'
+ ]
+ spec = spawn 'mocha', options
+ spec.stdout.pipe process.stdout
+ spec.stderr.pipe process.stderr
+ spec.on 'exit', (status) -> callback?() if status is 0
+
+install = (dep, callback) ->
+ options = [ 'install', dep ]
+ npm = spawn 'npm', options
+ npm.stdout.pipe process.stdout
+ npm.stderr.pipe process.stdout
+ npm.on 'exit', (status) -> callback?() if status is 0
+
+task 'deps', ->
+ deps = (( dep for dep of pkg.dependencies ).concat ( dep for dep of pkg.devDependencies ))
+ callback = ->
+ dep = deps.shift()
+ install dep, callback if dep?
+ callback()
+
+task 'docs', 'Generate annotated source code with Docco', ->
+ fs.readdir 'src', (err, contents) ->
+ files = ("src/#{file}" for file in contents when /\.coffee$/.test file)
+ docco = spawn 'docco', files
+ # docco.pipe process.stdout
+ docco.stdout.pipe process.stdout
+ docco.stderr.pipe process.stderr
+ docco.on 'exit', (status) -> callback?() if status is 0
+
+task 'spec', 'Run Mocha tests', ->
+ build -> test -> log ":)", green
+
+task 'test', 'Run Mocha tests', ->
+ build -> test -> log ":)", green
+
+task 'build', ->
+ build -> log ":)", green
+
+task 'dev', 'start dev env', ->
+ # watch_coffee
+ options = ['-c', '-b', '-w', '-o', 'bin', 'src']
+ coffee = spawn 'coffee', options
+ coffee.stdout.pipe process.stdout
+ coffee.stderr.pipe process.stderr
+ log 'Watching coffee files', green
View
@@ -0,0 +1 @@
+
View
@@ -0,0 +1,23 @@
+# the 'hex' and 'url' key generators are tuned have a collision probability similar to that
+# of MD5 at a uniqueness factor of 2 (the default) specify a uniqueness factor of 4 for a
+# collision probabiltiy similar to that of SHA256
+
+gen_for = (base, alpha) ->
+ (uq_factor=2) ->
+ (alpha.charAt Math.floor(Math.random() * alpha.length) for [1..base * uq_factor]).join ''
+
+module.exports =
+
+ gen_for: gen_for
+
+ hex: gen_for 16, '0123456789abcdef'
+
+ url: gen_for 11, '23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
+
+ small: 1
+
+ medium: 2
+
+ large: 4
+
+
View
@@ -0,0 +1,6 @@
+module.exports =
+
+ column: (index, rows...) ->
+ if rows.length and index < rows[0].length then (row[index] for row in rows) else []
+
+ columns: (rows...) -> (@column(index, rows...) for val, index in rows[0])
@@ -3,6 +3,12 @@
"version": "0.0.0",
"description": "url-friendly, random, unique key/token generation",
"main": "index.js",
+ "devDependencies": {
+ "coffee-script": "1.3.3",
+ "mocha": "1.3.0",
+ "should": "1.1.0",
+ "docco": "0.3.0"
+ },
"scripts": {
"test": "mocha"
},
@@ -0,0 +1,44 @@
+assert = require 'assert'
+
+keygen = require '../bin'
+
+assertKeyGen = (generator, base, factor, iterations=1000000) ->
+ keys = {}
+ console.log "Attempting to generate #{iterations} unique keys of length #{base * factor}.."
+ for [1..iterations]
+ key = generator(factor)
+ assert.strictEqual base * factor, key.length
+ assert not keys[key], "Duplicate: '#{key}'"
+ keys[key] = true
+
+describe 'keygen', ->
+
+ describe '#hex(small)', ->
+
+ it 'should generate unique ids of length 16', ->
+ assertKeyGen keygen.hex, 16, keygen.small
+
+ describe '#hex(medium)', ->
+
+ it 'should generate unique ids of length 32', ->
+ assertKeyGen keygen.hex, 16, keygen.medium
+
+ describe '#hex(large)', ->
+
+ it 'should generate unique ids of length 64', ->
+ assertKeyGen keygen.hex, 16, keygen.large
+
+ describe '#url(small)', ->
+
+ it 'should generate unique ids of length 11', ->
+ assertKeyGen keygen.url, 11, keygen.small
+
+ describe '#url(medium)', ->
+
+ it 'should generate unique ids of length 22', ->
+ assertKeyGen keygen.url, 11, keygen.medium
+
+ describe '#url(large)', ->
+
+ it 'should generate unique ids of length 44', ->
+ assertKeyGen keygen.url, 11, keygen.large
@@ -0,0 +1,45 @@
+assert = require 'assert'
+
+matrix = require '../bin/matrix'
+
+rows = [
+ [ 'a', 'b', 'c' ]
+ [ '1', '2', '3' ]
+ [ 'A', 'B', 'C' ]
+]
+
+describe 'matrix', ->
+
+ describe '#column(index, rows...)', ->
+
+ it 'should return [] when no rows are given', ->
+ assert.deepEqual [], matrix.column(0)
+
+ it "should return [ 'a' ] when called with 0, [ 'a', 'b', 'c' ]", ->
+ assert.deepEqual [ 'a' ], matrix.column(0, rows[0])
+
+ it "should return [ 'a', '1', 'A' ] when called with 0, [ 'a', 'b', 'c' ], [ '1', '2', '3' ], [ 'A', 'B', 'C' ]", ->
+ assert.deepEqual [ 'a', '1', 'A' ], matrix.column(0, rows...)
+
+ it "should return [ 'b', '2', 'B' ] when called with 1, [ 'a', 'b', 'c' ], [ '1', '2', '3' ], [ 'A', 'B', 'C' ]", ->
+ assert.deepEqual [ 'b', '2', 'B' ], matrix.column(1, rows...)
+
+ it "should return [ 'c', '3', 'C' ] when called with 2, [ 'a', 'b', 'c' ], [ '1', '2', '3' ], [ 'A', 'B', 'C' ]", ->
+ assert.deepEqual [ 'c', '3', 'C' ], matrix.column(2, rows...)
+
+ it "should return [] when called with 3, [ 'a', 'b', 'c' ], [ '1', '2', '3' ], [ 'A', 'B', 'C' ]", ->
+ assert.deepEqual [], matrix.column(3, rows...)
+
+ describe '#columns(rows...)', ->
+
+ it 'should return [] when no rows are given', ->
+ assert.deepEqual [], matrix.columns(0)
+
+ it "should return [ [ 'a' ], ['b'], ['c'] ] when called with [ 'a', 'b', 'c' ]", ->
+ assert.deepEqual [ [ 'a' ], ['b'], ['c'] ], matrix.columns(rows[0])
+
+ it "should return [ [ 'a', '1', 'A' ], [ 'b', '2', 'B' ], [ 'c', '3', 'C' ] ] when called with [ 'a', 'b', 'c' ], [ '1', '2', '3' ], [ 'A', 'B', 'C' ]", ->
+ assert.deepEqual [ [ 'a', '1', 'A' ], [ 'b', '2', 'B' ], [ 'c', '3', 'C' ] ], matrix.columns(rows...)
+
+ it "should be it's own inverse", ->
+ assert.deepEqual rows, matrix.columns(matrix.columns(rows...)...)

0 comments on commit 71836b0

Please sign in to comment.