    `update` message with the current wall-clock. Each agent decides
    independently whether or not to submit a catalog during that clock
    tick."
-  (:import (java.io File))
   (:require [clojure.tools.logging :as log]
             [puppetlabs.puppetdb.catalog.utils :as catutils]
             [puppetlabs.trapperkeeper.logging :as logutils]

        facts-pattern (re-pattern "facts.*\\.json$")]
    (fn [acc entry]
      (let [path (.getName entry)
            parsed-entry (json/parse-string (archive/read-entry-content tar-reader))]
        (cond
          (re-find catalog-pattern path) (update-in acc [:catalogs] conj parsed-entry)
          (re-find report-pattern path) (update-in acc [:reports] conj parsed-entry)
          (re-find facts-pattern path) (update-in acc [:facts] conj parsed-entry)
          :else acc)))))

(defn load-data-from-options
  [{:keys [catalogs facts reports archive from-cp?]}]
  (if archive
    (let [tar-reader (archive/tarball-reader archive)
          entries (archive/all-entries tar-reader)]
      (->> (reduce (process-tar-entry archive tar-reader)
                   {:catalogs [] :reports [] :facts []} entries)
           (filter (comp not empty? val))
           (into {})))
    {:catalogs (when catalogs
                 (load-sample-data catalogs from-cp?))
     :facts (when facts
              (load-sample-data facts from-cp?))
     :reports (when reports
                (load-sample-data reports from-cp?))}))

(defn -main
  [& args]
  (let [options         (validate-cli! args)
        config          (-> (:config options)
                            config/load-config)

        {:keys [catalogs reports facts]} (load-data-from-options options)
        nhosts          (:numhosts options)
        hostnames       (set (map #(str "host-" %) (range (Integer/parseInt nhosts))))
        hostname        (get-in config [:jetty :host] "localhost")
        port            (get-in config [:jetty :port] 8080)
        rand-percentage (Integer/parseInt (or (:rand-perc options) "0"))

        ;; Create an agent for each host
        hosts (mapv (fn [host]
                      {:host host
                       :puppetdb-host hostname
                       :puppetdb-port port
                       :rand-percentage rand-percentage
                       :catalog (when catalogs
                                  (associate-catalog-with-host host (rand-nth catalogs)))
                       :report (when reports
                                 (associate-report-with-host host (rand-nth reports)))
                       :factset (when facts
                                   (associate-factset-with-host host (rand-nth facts)))})
                    hostnames)]

    (when-not catalogs
      (log/info "No catalogs specified; skipping catalog submission"))
    (when-not reports
      (log/info "No reports specified; skipping report submission"))
    (when-not facts
      (log/info "No facts specified; skipping fact submission"))
    (if-let [num-cmds (:nummsgs options)]
      (submit-n-messages hosts (Long/valueOf num-cmds))
      (world-loop (mapv (fn [host-map]
                          (let [run-interval (* 60 1000 (Integer/parseInt (:runinterval options)))]
                            (agent (assoc host-map
                                     :run-interval run-interval
                                     :lastrun (- (System/currentTimeMillis) (rand-int run-interval))))))
                        hosts)))))

    hosts catalog changes in accordance to the users preference)

  * Submit the resulting catalog"
  [{:keys [host lastrun catalog report factset base-url run-interval rand-percentage] :as state} clock]
  (if-not (> (- clock lastrun) run-interval)
    state
    (let [catalog (some-> catalog update-catalog (maybe-tweak-catalog rand-percentage))
          report (some-> report update-report-run-fields)
          factset (some-> factset (update-factset rand-percentage))]
      ;; Submit the catalog and reports in separate threads, so as to not
