 
     keys: ->
       Object.keys obj
+
+
   Contract = (cname, ctype, handler) ->
     @handler = handler
     @cname = cname
     @ctype = ctype
     @parent = null
+
+  Contract:: =
+    check: check = (val, pos, neg, parentKs, stack) ->
+      c = unproxy.get(val)
+      if c and c.equals(this)
+        # don't bother wrapping twice though we want to run the handler
+        # for the initialization check that happens and just ignore the return
+        @handler val, pos, neg, parentKs, stack
+        val
+      else
+        @handler val, pos, neg, parentKs, stack
+
+    toContract: ->
+      this
+
+    toString: ->
+      @cname
+
+    equals: (other) ->
+      throw "Equality checking must be overridden"
+
   ModuleName = (filename, linenum, isServer) ->
     @filename = filename
     @linenum = linenum
     @isServer = isServer
+
+  ModuleName::toString = ->
+    @filename + (if @linenum is "" then "" else (":" + @linenum))
+
+  Function::toContract = ->
+    name = "<user defined: " + @toString() + ">"
+    check this, name
+
   check = (p, name) ->
-    c = undefined
-    c = new Contract(name, "check", check = (val, pos, neg, parentKs, stack) ->
+    c = new Contract name, "check", (val, pos, neg, parentKs, stack) ->
       if p(val, stack)
         val
       else
         blame pos, neg, this, val, parentKs
-    )
+
     c.equals = (other) ->
       (@cname is other.cname) and (@handler is other.handler)
 
     c
+
   fun = (dom, rng, options) ->
-    callOnly = undefined
-    newOnly = undefined
-    cleanDom = undefined
-    domName = undefined
-    optionsName = undefined
-    contractName = undefined
-    newdom = undefined
-    newrng = undefined
-    calldom = undefined
-    callrng = undefined
-    c = undefined
     cleanDom = (dom) ->
+      # wrap the domain in array so we can be consistent
       dom = [ dom ]  if dom instanceof Contract
+      # don't allow required argument contracts to follow optional
       dom.reduce ((prevWasOpt, curr) ->
         if curr.ctype is "opt"
           true

          lastBlame = e
          continue
        i++
      if ho.length is 1
        @ho[0].check val, pos, neg, parents
      else
        throw lastBlame
    )
    c.flats = flats
    c.ho = ho
    c.equals = (other) ->
      zipFlats = undefined
      pFlats = undefined
      return false  if not other instanceof Contract or other.ctype isnt @ctype
      zipFlats = Utils.zip(@flats, other.flats)
      pFlats = (zipFlats.length isnt 0) and zipFlats.every((zf) ->
        zf[0].equals zf[1]
      )
      pFlats and (@ho.equals(other.ho))

    c
  and = (k1, k2) ->
    c = undefined
    c = new Contract(k1.cname + " and " + k2.cname, "and", (val, pos, neg, parentKs) ->
      k1c = k1.check(val, pos, neg, parentKs)
      k2.check k1c, pos, neg, parentKs
    )
    c.k1 = k1
    c.k2 = k2
    c.equals = (other) ->
      return false  if not other instanceof Contract or other.ctype isnt @ctype
      (@k1.equals(other.k1)) and (@k2.equals(other.k2))

    c
  not = (k) ->
    c = undefined
    res = undefined
    throw "cannot construct a 'not' contract with a function or object contract"  if k.ctype is "fun" or k.ctype is "object"
    c = new Contract("not " + k.cname, "not", (val, pos, neg, parentKs) ->
      try
        res = @k.check(val, pos, neg, parentKs)
        blame pos, neg, this, val, parentKs
      catch b
        return res
    )
    c.k = k
    c.equals = (other) ->
      return false  if not other instanceof Contract or other.ctype isnt @ctype
      @k.equals other.k

    c
  opt = (k) ->
    c = undefined
    c = new Contract("opt(" + k.cname + ")", "opt", (val, pos, neg, parentKs) ->
      if val is `undefined`
        val
      else
        @k.check val, pos, neg, parentKs
    )
    c.k = k
    c.equals = (other) ->
      return false  if not other instanceof Contract or other.ctype isnt @ctype
      @k.equals other.k

    c
  getModName = (isServer) ->
    guardedAt = undefined
    match = undefined
    filename = undefined
    linenum = undefined
    st = printStackTrace(e: new Error())
    guardedAt = st[2]
    match = /\/([^\/]*):(\d*)[\)]?$/.exec(guardedAt)
    if match
      filename = match[1]
      linenum = match[2]
    else
      filename = "unknown"
      linenum = "-1"
    new ModuleName(filename, linenum, isServer)
  guard = (k, x, server, setup) ->
    stack = []
    setup stack  if typeof setup is "function"
    unless server
      server = getModName(true)
    else
      server = new ModuleName(server, "", true)
    use: (client, srvr) ->
      unless client
        client = getModName(false)
      else
        client = new ModuleName(client, "", false)
      server = new ModuleName(srvr, "", false)  if srvr
      if (server.filename is client.filename) and (server.linenum is client.linenum)
        server.linenum = server.linenum + " (server)"
        client.linenum = client.linenum + " (client)"
      if enabled
        k.check x, server, client, [], stack
      else
        x
  "use strict"
  enabled = true
  unproxy = []
  unproxy = (->
    unproxy = undefined
    weak = undefined
    if typeof (WeakMap) isnt "undefined"
      weak = true
      unproxy = new WeakMap()
    else
      weak = false
      unproxy = []
    set: (p, c) ->
      if weak
        unproxy.set p, c
      else
        unproxy.push
          proxy: p
          contract: c

    get: (p) ->
      pc = undefined
      if weak
        if (p isnt null) and typeof p is "object" or typeof p is "function"
          unproxy.get p
        else
          `undefined`
      else
        pc = unproxy.filter((el) ->
          p is el.proxy
        )
        throw "assumption failed: unproxy object stores multiple unique proxies"  if pc.length > 1
        if pc.length is 1
          pc[0]
        else
          `undefined`
  )()
  Utils =
    getPropertyDescriptor: getPropertyDescriptor = (obj, prop) ->
      o = obj
      loop
        desc = Object.getOwnPropertyDescriptor(o, prop)
        return desc  if desc isnt `undefined`
        o = Object.getPrototypeOf(o)
        break unless o isnt null
      `undefined`

    merge: merge = (o1, o2) ->
      o3 = {}
      f = (o) ->
        for name of o
          o3[name] = o[name]  if o.hasOwnProperty(name)

      f o1
      f o2
      o3

    hasNoHoles: hasNoHoles = (obj) ->
      i = 0
      while i < obj.length
        return false  unless i of obj
        i++
      true

    zip: (a1, a2) ->
      i = undefined
      ret = []
      if not Array.isArray(a1) or not Array.isArray(a2) or (a1.length isnt a2.length)
        ret = []
      else
        i = 0
        while i < a1.length
          ret.push [ a1[i], a2[i] ]
          i++
      ret

  Contract:: =
    check: check = (val, pos, neg, parentKs, stack) ->
      c = unproxy.get(val)
      if c and c.equals(this)
        @handler val, pos, neg, parentKs, stack
        val
      else
        @handler val, pos, neg, parentKs, stack

    toContract: ->
      this

    toString: ->
      @cname

    equals: (other) ->
      throw "Equality checking must be overridden"

  ModuleName::toString = ->
    @filename + (if @linenum is "" then "" else (":" + @linenum))

  Function::toContract = ->
    name = "<user defined: " + @toString() + ">"
    check this, name

  any = (any = ->
    c = new Contract("any", "any", (val) ->
      val
    )
    c.equals = (other) ->
      this is other

    c
  )()
  self = (->
    c = new Contract("self", "self", (val) ->
      val
    )
    c.equals = (other) ->
      this is other

    c
  )()
  none = (none = ->
    c = new Contract("none", "none", (val, pos, neg, parentKs) ->
      blame pos, neg, this, val, parentKs
    )
    c.equals = (other) ->
      this is other

    c
  )()
  combinators =
    check: check
    fun: fun

    defineProperty: (name, desc) ->
      Object.defineProperty obj, name, desc

    'delete': (name) ->
      delete obj[name]

    fix: ->
