   [^WIGWriter wtr xs]
   (let [w ^BufferedWriter (.writer wtr)]
     (->> xs
-         (map serialize-wig)
+         serialize-wigs
          (cstr/join \newline)
          (.write w))))

    (as-double s)))

(defn- deserialize-wigs
  "Parse WIG lines and returns a vector of maps."
  [lines]
  (loop [lines lines
         wigs []
         current-track nil]
    (if (nil? (first lines))
      (conj wigs current-track)
      (let [fields (-> lines first cstr/trim (cstr/split #"\s+"))]
        (case (first fields)
          ; declaration line of variableStep
          "variableStep"
          (let [{:keys [chrom span] :or {span 1}} (->> fields rest fields->map)]
            (recur (rest lines)
                   (cond-> wigs
                     (some? current-track) (conj current-track))
                   {:format :variable-step
                    :chrom chrom
                    :span (as-long span)
                    :values []}))

          ; declaration line of fixedStep
          "fixedStep"
          (let [{:keys [chrom start step span] :or {span 1}} (->> fields rest fields->map)]
            (recur (rest lines)
                   (cond-> wigs
                     (some? current-track) (conj current-track))
                   {:format :fixed-step
                    :chrom chrom
                    :start (as-long start)
                    :step (as-long step)
                    :span (as-long span)
                    :values []}))

          ; data line
          (let [v (case (:format current-track)
                    :variable-step
                    (let [[start value] fields]
                      {:start (as-long start)
                       :value (str->wiggle-track-data value)})

                    :fixed-step
                    (-> fields first str->wiggle-track-data)

                    (throw (IllegalArgumentException. "Invalid wiggle format")))]
            (recur (rest lines)
                   wigs
                   (update current-track :values conj v))))))))

(defn- serialize-wig
  "Serialize WIG fields into string."
  [wig]
  {:pre [;; There are two options for formatting wiggle data.
         (or (= (:format wig) :fixed-step) (= (:format wig) :variable-step))
         ;; These fields are required if the format is fixedStep.
         (if (= (:format wig) :fixed-step) (and (:chrom wig) (:span wig) (:start wig) (:step wig) (:values wig)) true)
         ;; These fields are required if the format is variableStep.
         (if (= (:format wig) :variable-step) (and (:chrom wig) (:span wig) (:values wig)) true)]}
  (case (:format wig)
    :variable-step
    (let [{:keys [chrom span values]} wig
          declaration-line (->> (cond-> ["variableStep" (str "chrom=" chrom)]
                                  (not= span 1) (conj (str "span=" span)))
                                (cstr/join \space))
          data-lines (->> values
                          (map (fn [{:keys [start value]}]
                                 (cstr/join \space [start value])))
                          (cstr/join \newline))]
      (cstr/join \newline [declaration-line data-lines]))

    :fixed-step
    (let [{:keys [chrom start step span values]} wig
          declaration-line (->> (cond-> ["fixedStep" (str "chrom=" chrom) (str "start=" start) (str "step=" step)]
                                  (not= span 1) (conj (str "span=" span)))
                                (cstr/join \space))
          data-lines (cstr/join \newline values)]
      (cstr/join \newline [declaration-line data-lines]))

    (throw (IllegalArgumentException. "Invalid wiggle format"))))

(defn read-fields
  "Read sequence of WIG fields from reader"

  [f]
  (WIGWriter. (cio/writer (util/compressor-output-stream f)) (util/as-url f)))

(def ^:const wig-fields [:format :chrom :start :end :value])

(defn- header-or-comment?
  "Checks if given string is neither a header nor a comment line."
  [^String s]
