   (assert (= (hash-map :foo 5)
              (assoc (cljs.core.ObjMap. nil (array) (js-obj)) :foo 5)))
 
-  (assert (= "[1 {:a 2, :b 42} #<Array [3, 4]>]"
-             (pr-str [1 {:a 2 :b 42} (array 3 4)])))
+  (assert (= "[1 true {:a 2, :b 42} #<Array [3, 4]>]"
+             (pr-str [1 true {:a 2 :b 42} (array 3 4)])))
   (assert (= "symbol\"'string"
              (pr-str (str 'symbol \" \' "string"))))
   (assert (not (= "one" "two")))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; equality ;;;;;;;;;;;;;;

(extend-protocol IEquiv
  goog.global.Date ; treat dates as values
  (-equiv [o other] (identical? (str o) (str other))))

(defn = [x y]
  (if (satisfies? IEquiv x)

           (recur (f val (-nth cicoll n)) (inc n))
           val))))

(extend-type goog.global.Date
  IEquiv
  (-equiv [o other] (identical? (str o) (str other))))

(extend-type boolean
  IPrintable
  (-pr-seq [bool opts] (list (str bool))))

(extend-type number
  IHash
  (-hash [o] o)

  IPrintable
  (-pr-seq [n opts] (list (str n))))

(extend-type string
  IHash
  (-hash [o] (goog.string/hashCode o))

  ISeqable
  (-seq [string] (prim-seq string 0))
  
  ICounted
  (-count [s] (.length s))

  IIndexed
  (-nth
    ([string n]
       (if (< n (-count string)) (.charAt string n)))
    ([string n not-found]
       (if (< n (-count string)) (.charAt string n)
           not-found)))

  ILookup
  (-lookup
    ([string k]
       (-nth string k))
    ([string k not_found]
       (-nth string k not_found)))

  IReduce
  (-reduce
    ([string f]
       (ci-reduce string f (-nth string 0) 1))
    ([string f start]
       (ci-reduce string f start 0)))

  IPrintable
  (-pr-seq [obj opts]
    (cond
     (keyword? obj)
     (list (str ":"
                (when-let [nspc (namespace obj)]
                  (str nspc "/"))
                (name obj)))
     (symbol? obj)
     (list (str (when-let [nspc (namespace obj)]
                  (str nspc "/"))
                (name obj)))
     (get opts :readably)
     (list (goog.string.quote obj))
     :else (list obj))))

(extend-type array
  ISeqable
  (-seq [array] (array-seq array 0))

  ICounted
  (-count [a] (.length a))

  IIndexed
  (-nth
    ([array n]
       if (< n (-count array)) (aget array n))
    ([array n not_found]
       (if (< n (-count array)) (aget array n)
           not_found)))

  ILookup
  (-lookup
    ([array k]
       (-nth array k))
    ([array k not-found]
       (-nth array k not-found)))

  IReduce
  (-reduce
    ([array f]
       (ci-reduce array f (-nth array 0) 1))
    ([array f start]
       (ci-reduce array f start 0)))

  IPrintable
  (-pr-seq [a opts]
    (pr-sequential pr-seq "#<Array [" ", " "]>" opts a)))

(deftype List [meta first rest count]
  IWithMeta
  (-with-meta [coll meta] (List. meta first rest count))

  IMeta
  (-meta [coll] meta)

  ISeq
  (-first [coll] first)
  (-rest [coll] (if (nil? rest) (EmptyList. meta) rest))

  IStack
  (-peek [coll] first)
  (-pop [coll] (-rest coll))

  ICollection
  (-conj [coll o] (List. meta o coll (inc count)))

  IEmptyableCollection
  (-iempty [coll] coll)

  ISequential
  IEquiv
  (-equiv [coll other] (equiv-sequential coll other))

  IHash
  (-hash [coll] (hash-coll coll))

  ISeqable
  (-seq [coll] coll)

  ICounted
  (-count [coll] count)

  IPrintable
  (-pr-seq [coll opts] (pr-sequential pr-seq "(" " " ")" opts coll)))

(deftype EmptyList [meta]
  IWithMeta
  (-with-meta [coll meta] (EmptyList. meta))

  IMeta
  (-meta [coll] meta)

  ISeq
  (-first [coll] nil)
  (-rest [coll] nil)

  IStack
  (-peek [coll] nil)
  (-pop [coll] #_(throw "Can't pop empty list"))

  ICollection
  (-conj [coll o] (List. meta o nil 1))

  IEmptyableCollection
  (-iempty [coll] coll)

  ISequential
  IEquiv
  (-equiv [coll other] (equiv-sequential coll other))

  IHash
  (-hash [coll] (hash-coll coll))

  ISeqable
  (-seq [coll] nil)

  ICounted
  (-count [coll] 0)

  IPrintable
  (-pr-seq [coll opts] (list "()")))

(set! cljs.core.List/EMPTY (EmptyList. nil))

(defn list [& items]
  (reduce conj () (reverse items)))

(deftype Cons [meta first rest]
  IWithMeta
  (-with-meta [coll meta] (Cons. meta first rest))

  IMeta
  (-meta [coll] meta)

  ISeq
  (-first [coll] first)
  (-rest [coll] (if (nil? rest) () rest))

  ICollection
  (-conj [coll o] (Cons. nil o coll))

  IEmptyableCollection
  (-iempty [coll] (EmptyList. nil))

  ISequential
  IEquiv
  (-equiv [coll other] (equiv-sequential coll other))

  IHash
  (-hash [coll] (hash-coll coll))

  ISeqable
  (-seq [coll] coll)

  IPrintable
  (-pr-seq [coll opts] (pr-sequential pr-seq "(" " " ")" opts coll)))

(defn cons
  "Returns a new seq where x is the first element and seq is the rest."
