          (finally (close-local-contexts contexts merged active))))))
 
 
+(defn- firsts [coll]
+  (vec (map first (partition 2 coll))))
+
+(defn- seconds [coll]
+  (vec (map second (partition 2 coll))))
+
 ;;; Public API
 
 (defmacro is

                         :form '~&form}
                        nil))))

(defmacro given
  "A series of assertions using values from contexts.
  bindings is a vector of name-value pairs, like let, where each value
  is a context created with defcontext.  A string will be attached
  as :doc metadata on the following assertion."
  [bindings & assertions]
  (assert (vector? bindings))
  (assert (even? (count bindings)))
  (let [pairs (partition 2 bindings)
        locals (vec (map first pairs))
        contexts (vec (map second pairs))]
    (loop [r [], as assertions]
      (if (seq as)
        (let [[doc form nxt]
              (if (string? (first as))
                [(first as) (second as) (nnext as)]
                [nil (first as) (next as)])]
          (recur (conj r `(ContextualAssertion
                           ~contexts
                           (fn ~locals ~form)
                           {:doc ~doc,
                            :locals '~locals
                            :form '~form
                            :file *file*,
                            :line ~(:line (meta form))}
                           nil))
                 nxt))
        `(SimpleContainer ~r {:generator 'given
                              :line ~(:line (meta &form))
                              :form '~&form}
                          nil)))))

(defn- attributes
  "Reads optional name symbol and doc string from args,

          (= (+ 8 -1) 7))
"
  [argv expr & values]
  (let [givens (vec (filter #(::given (meta %)) (keys &env)))
        argc (count argv)
        sym (gensym "f")]
    (assert (vector? argv))
    (assert (zero? (rem (count values) argc)))
    `(let [~sym (fn ~argv ~expr)]
       (SimpleContainer ~(vec (map (fn [vs]
                                     (if (seq givens)
                                       `(ContextualAssertion
                                         ~givens
                                         (fn ~givens (~sym ~@vs))
                                         {:form '(~'are ~argv ~expr ~@vs)
                                          :file *file*
                                          :line ~(some #(:line (meta %)) vs)
                                          :locals '~givens}
                                         nil)
                                       `(SimpleAssertion
                                         (fn [] (~sym ~@vs))
                                         {:form '(~'are ~argv ~expr ~@vs)
                                          :file *file*
                                          :line ~(some #(:line (meta %)) vs)}
                                         nil)))
                                   (partition argc values)))
                        {:generator 'are
                         :file *file*
