           args = (attributes.args ? '').split()
           script = htmlDecode(child.innerHTML)
           type = attributes.type or defaulttype
-          classattributes.$methods[attributes.name] = [transformScript(script, type), args]
+          classattributes.$methods[attributes.name] = [compiler.transform(script, type), args]
           # console.log 'added method', attributes.name, script, classattributes
         when 'setter'
           args = (attributes.args ? '').split()
           script = htmlDecode(child.innerHTML)
           type = attributes.type or defaulttype
-          classattributes.$methods['set_' + attributes.name] = [transformScript(script, type), args]
+          classattributes.$methods['set_' + attributes.name] = [compiler.transform(script, type), args]
           # console.log 'added setter', 'set_' + attributes.name, args, classattributes.$methods
         when 'attribute'
           classattributes[attributes.name] = attributes.value

      @


  typemappings = 
    number: parseFloat
    boolean: (val) -> (if (typeof val == 'string') then val == 'true' else (!! val))
    string: (val) -> val + ''

  installMethod = (scope, methodname, method) ->
    if methodname of scope
      # Cheesy override
      supr = scope[methodname]
      meth = method
      scope[methodname] = ->
        # console.log 'applying overridden method', methodname, arguments
        supr.apply(scope, arguments)
        meth.apply(scope, arguments)
        # console.log('overrode method', methodname, scope, supr, meth)
    else
      scope[methodname] = method
      # console.log('installed method', methodname, scope, scope[methodname])


  cacheKey = "compilecache"
  if cacheKey of localStorage
    compileCache = JSON.parse(localStorage[cacheKey])
    # console.log 'restored', compileCache
  else
    compileCache = {}

  $(window).on('unload', -> 
    localStorage[cacheKey] = JSON.stringify(compileCache) 
    # console.log 'onunload', localStorage[cacheKey]
  )

  findPropertyBindings = do ->
    compileCache.bindings ?= {}
    bindingCache = compileCache.bindings
    scopes = null
    propertyBindings = 
      MemberExpression: (n) ->
        # grab the property name
        name = n.property.name

        # remove the property so we can compute the rest of the expression
        n = n.object

        # push the scope onto the list
        scopes.push({binding: acorn.stringify(n), property: name})
        # console.log 'MemberExpression', name, n, acorn.stringify n
        return true

    (expression) ->
      return bindingCache[expression] if expression of bindingCache
      ast = acorn.parse(expression)
      scopes = []
      acorn.walkDown(ast, propertyBindings)
      bindingCache[expression] = scopes
      # console.log compileCache.bindings
      # return scopes
    # propertyBindings.find = _.memoize(propertyBindings.find)

  # transforms a script to javascript using a runtime compiler
  transformScript = do ->    
    compileCache.script ?= {'coffee': {}}
    coffeeCache = compileCache.script.coffee
    compilers = 
      coffee: (script) ->
        if script of coffeeCache
          # console.log 'cache hit', script
          return coffeeCache[script]
        if not window.CoffeeScript
          console.warn 'missing coffee-script.js include'
          return
        # console.log 'compiling coffee-script', script
        coffeeCache[script] = CoffeeScript.compile(script, bare: true) if script
        # console.log 'compiled coffee-script', script
        # console.log coffeeCache
        # return coffeeCache[script]

    (script='', name) ->
      return script unless name of compilers
      compilers[name](script) 

  # cache compiled scripts to speed up instantiation
  scriptCache = {}
  # compile a string into a function
  compileScript = (script='', args=[]) ->
    key = script + args.join()
    return scriptCache[key] if key of scriptCache
    # console.log 'compileScript', compiler, args, script
    try 
      # console.log scriptCache
      scriptCache[key] = new Function(args, script)
    catch e
      console.error('failed to compile', args, script, e)


  class Node extends Eventable
    matchConstraint = /\${(.+)}/

    # generate a callback for an event expression in a way that preserves scope, e.g. on_x="console.log(value, this, ...)"
    eventCallback = (name, script, scope, fnargs=['value']) ->
      # console.log 'binding to event expression', name, script, scope, fnargs
      js = compileScript(script, fnargs)
      ->
        if name of scope
          args = [scope[name]]
        else 
          args = arguments
        # console.log 'event callback', name, args, scope, js
        js.apply(scope, args)

    constructor: (el, attributes = {}) ->
      @subnodes = []

        # Install methods
        for methodname, method of attributes.$methods
          # console.log 'installing method', methodname, method, @
          installMethod(@, methodname, compiler.compile.apply(null, method))
        delete attributes.$methods

      if attributes.$handlers
