 (defn source-compare [sources]
   (let [sources (indexed-sources sources)]
     (fn [a b] (compare (sources a) (sources b)))))
+
+;; -----------------------------------------------------------------------------
+;; Decoding
 
 (defn seg->map [seg source-map]
   (let [[gcol source line col name] seg]

            [clojure.set :as set]
            [clojure.pprint :as pp]
            [cljs.source-map.base64-vlq :as base64-vlq]))

(defn indexed-sources [sources]
  (->> sources

             (recur (inc gline) (next lines) (assoc relseg 0 0) result))
           result)))))

;; -----------------------------------------------------------------------------
;; Encoding

(defn lines->segs [lines]
  (let [relseg (atom [0 0 0 0 0])]
    (reduce
      (fn [segs cols]
        (swap! relseg
          (fn [[_ source line col name]]
            [0 source line col name]))
        (conj segs
          (reduce
            (fn [cols [gcol sidx line col name :as seg]]
              (let [offset (map - seg @relseg)]
                (swap! relseg
                  (fn [[_ _ _ _ lname]]
                    [gcol sidx line col (or name lname)]))
                (conj cols (base64-vlq/encode offset))))
            [] cols)))
      [] lines)))

(defn encode [m opts]
  (let [lines (atom [[]])
        names->idx (atom {})
        name-idx (atom 0)
        info->segv
        (fn [info source-idx line col]
          (let [segv [(:gcol info) source-idx line col]]
            (if-let [name (:name info)]
              (let [idx (if-let [idx (get-in @names->idx name)]
                          idx
                          (let [cidx @name-idx]
                            (swap! names->idx assoc name cidx)
                            (swap! name-idx inc)
                            cidx))]
                (conj segv idx))
              segv)))
        encode-cols
        (fn [infos source-idx line col]
          (doseq [info infos]
            (let [segv (info->segv info source-idx line col)
                  gline (:gline info)
                  lc (count @lines)]
              (if (> gline (dec lc))
                (swap! lines
                  (fn [lines]
                    (conj (into lines (repeat (dec (- gline (dec lc))) [])) [segv])))
                (swap! lines
                  (fn [lines]
                    (update-in lines [gline] conj segv)))))))]
    (doseq [[source-idx [_ lines]] (map-indexed (fn [i v] [i v]) m)]
      (doseq [[line cols] lines]
        (doseq [[col infos] cols]
          (encode-cols infos source-idx line col))))
    (with-out-str
      (json/pprint 
       {"version" 3
        "file" (:file opts)
        "sources" (into [] (keys m))
        "lineCount" (:lines opts)
        "mappings" (->> (lines->segs @lines)
                        (map #(string/join "," %))
                        (string/join ";"))
        "names" (into [] (map (set/map-invert @names->idx)
                              (range (count @names->idx))))}))))

;; -----------------------------------------------------------------------------
;; Merging

(defn merge-source-maps
  ([cljs-map closure-map] (merge-source-maps cljs-map closure-map 0))
