<commit_before>(ns get-here.core
  (:require [org.httpkit.client :as http]
            [clojure.core.memoize :as memo]
            [compojure.core :refer [GET POST defroutes]]
            [ring.adapter.jetty :as jetty]
            [ring.middleware.file-info :refer [wrap-file-info]]
            [ring.middleware.format-params :refer [wrap-restful-params]]
            [ring.middleware.format-response :refer [wrap-restful-response]]
            [ring.middleware.params :as params]
            [ring.middleware.reload :as reload]
            [ring.middleware.resource :as resource]
            [ring.middleware.stacktrace :as stacktrace]
            [ring.util.response :as response]
            [environ.core :as env]
            [clojure.data.json :as json]
            [clojure.walk :as walk])
  (:import [java.util Date]
           [java.time ZonedDateTime Instant ZoneId]))

(defn epoch-seconds->date [epoch-seconds]
  (Date/from (Instant/ofEpochMilli (* 1000 epoch-seconds))))

(defn seconds->duration [seconds]
  {:hours (-> seconds
              (/ 3600)
              long)
   :minutes (-> seconds
                (/ 60)
                long
                (mod 60))})

(defn google-api-key []
  (environ.core/env :google-api-key))

(defn google-transit-directions [from to arrive-by]
  {:pre [(instance? Date arrive-by)]}
  (future (-> (http/get "https://maps.googleapis.com/maps/api/directions/json"
                        {:query-params {:origin from
                                        :destination to
                                        :mode "transit"
                                        :arrival_time (/ (.. arrive-by
                                                             (toInstant)
                                                             (toEpochMilli))
                                                         1000)
                                        :key (google-api-key)}})
              (deref)
              (update :body json/read-str)
              (update :body walk/keywordize-keys))))

(defn transit-step?
  "Returns true if the provided step is a transit step (as opposed to
  a walking step)."
  [step]
  (contains? step :transit_details))

(def nyc-terminal? (partial contains? #{"Penn Station"}))

(defn peak? [{:keys [origin destination departure arrival] :as directions}]
  {:pre [(instance? Date departure)
         (instance? Date arrival)]}
  (let [ny (ZoneId/of "America/New_York")
        departure-instant (ZonedDateTime/ofInstant (.toInstant departure) ny)
        arrival-instant (ZonedDateTime/ofInstant (.toInstant arrival) ny)]
    (or (and (nyc-terminal? origin)
             (<= 6 (.getHour departure-instant) 10))
        (and (nyc-terminal? arrival)
             (<= (.getHour arrival-instant) 20)))))

(defn reformat-directions [body]
  (let [directions (get-in body [:routes 0 :legs 0])]
    {:summary
     {:origin      (get-in directions [:start_address])
      :destination (get-in directions [:end_address])
      :departure   (epoch-seconds->date (get-in directions [:departure_time :value]))
      :arrival     (epoch-seconds->date (get-in directions [:arrival_time :value]))
      :duration    (seconds->duration (get-in directions [:duration :value]))}
     :route
     (->> (get-in directions [:steps])
          (filter transit-step?)
          (map (fn [step]
                 {:origin      (get-in step [:transit_details :departure_stop :name])
                  :destination (get-in step [:transit_details :arrival_stop :name])
                  :towards     (get-in step [:transit_details :headsign])
                  :route       (get-in step [:transit_details :line :name])
                  :departure   (epoch-seconds->date (get-in step [:transit_details :departure_time :value]))
                  :arrival     (epoch-seconds->date (get-in step [:transit_details :arrival_time :value]))}))
          (map (fn [step]
                 (assoc step :peak (peak? step)))))}))

#_ ;; example response
{:summary
 {:origin "Penn Station",
  :destination "Fire Island Pines",
  :departure {:month 7, :day 10, :hour 7, :minute 49},
  :arrival {:month 7, :day 10, :hour 9, :minute 50},
  :duration {:hours 2, :minutes 1}},
 :route
 ({:origin "Penn Station",
   :destination "Babylon",
   :towards "Babylon",
   :route "Babylon",
   :departure {:month 7, :day 10, :hour 7, :minute 49},
   :arrival {:month 7, :day 10, :hour 8, :minute 47},
   :peak false}
  {:origin "Babylon",
   :destination "Sayville",
   :towards "Montauk",
   :route "Montauk",<commit_msg>Return a vector<commit_after>(ns get-here.core
  (:require [org.httpkit.client :as http]
            [clojure.core.memoize :as memo]
            [compojure.core :refer [GET POST defroutes]]
            [ring.adapter.jetty :as jetty]
            [ring.middleware.file-info :refer [wrap-file-info]]
            [ring.middleware.format-params :refer [wrap-restful-params]]
            [ring.middleware.format-response :refer [wrap-restful-response]]
            [ring.middleware.params :as params]
            [ring.middleware.reload :as reload]
            [ring.middleware.resource :as resource]
            [ring.middleware.stacktrace :as stacktrace]
            [ring.util.response :as response]
            [environ.core :as env]
            [clojure.data.json :as json]
            [clojure.walk :as walk])
  (:import [java.util Date]
           [java.time ZonedDateTime Instant ZoneId]))

(defn epoch-seconds->date [epoch-seconds]
  (Date/from (Instant/ofEpochMilli (* 1000 epoch-seconds))))

(defn seconds->duration [seconds]
  {:hours (-> seconds
              (/ 3600)
              long)
   :minutes (-> seconds
                (/ 60)
                long
                (mod 60))})

(defn google-api-key []
  (environ.core/env :google-api-key))

(defn google-transit-directions [from to arrive-by]
  {:pre [(instance? Date arrive-by)]}
  (future (-> (http/get "https://maps.googleapis.com/maps/api/directions/json"
                        {:query-params {:origin from
                                        :destination to
                                        :mode "transit"
                                        :arrival_time (/ (.. arrive-by
                                                             (toInstant)
                                                             (toEpochMilli))
                                                         1000)
                                        :key (google-api-key)}})
              (deref)
              (update :body json/read-str)
              (update :body walk/keywordize-keys))))

(defn transit-step?
  "Returns true if the provided step is a transit step (as opposed to
  a walking step)."
  [step]
  (contains? step :transit_details))

(def nyc-terminal? (partial contains? #{"Penn Station"}))

(defn peak? [{:keys [origin destination departure arrival] :as directions}]
  {:pre [(instance? Date departure)
         (instance? Date arrival)]}
  (let [ny (ZoneId/of "America/New_York")
        departure-instant (ZonedDateTime/ofInstant (.toInstant departure) ny)
        arrival-instant (ZonedDateTime/ofInstant (.toInstant arrival) ny)]
    (or (and (nyc-terminal? origin)
             (<= 6 (.getHour departure-instant) 10))
        (and (nyc-terminal? arrival)
             (<= (.getHour arrival-instant) 20)))))

(defn reformat-directions [body]
  (let [directions (get-in body [:routes 0 :legs 0])]
    {:summary
     {:origin      (get-in directions [:start_address])
      :destination (get-in directions [:end_address])
      :departure   (epoch-seconds->date (get-in directions [:departure_time :value]))
      :arrival     (epoch-seconds->date (get-in directions [:arrival_time :value]))
      :duration    (seconds->duration (get-in directions [:duration :value]))}
     :route
     (->> (get-in directions [:steps])
          (filter transit-step?)
          (map (fn [step]
                 {:origin      (get-in step [:transit_details :departure_stop :name])
                  :destination (get-in step [:transit_details :arrival_stop :name])
                  :towards     (get-in step [:transit_details :headsign])
                  :route       (get-in step [:transit_details :line :name])
                  :departure   (epoch-seconds->date (get-in step [:transit_details :departure_time :value]))
                  :arrival     (epoch-seconds->date (get-in step [:transit_details :arrival_time :value]))}))
          (mapv (fn [step]
                 (assoc step :peak (peak? step)))))}))

#_ ;; example response
{:summary
 {:origin "Penn Station",
  :destination "Fire Island Pines",
  :departure {:month 7, :day 10, :hour 7, :minute 49},
  :arrival {:month 7, :day 10, :hour 9, :minute 50},
  :duration {:hours 2, :minutes 1}},
 :route
 ({:origin "Penn Station",
   :destination "Babylon",
   :towards "Babylon",
   :route "Babylon",
   :departure {:month 7, :day 10, :hour 7, :minute 49},
   :arrival {:month 7, :day 10, :hour 8, :minute 47},
   :peak false}
  {:origin "Babylon",
   :destination "Sayville",
   :towards "Montauk",
   :route "Montauk",
{'fraction_non_alphanumeric': 0.13643853674612766, 'fraction_numerical': 0.010765681643414259, 'mean_word_length': 1.9898193760262726, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 27, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3180324', 'n_tokens_mistral': 2874, 'n_tokens_neox': 2677, 'n_words': 699}