Skip to content

Instantly share code, notes, and snippets.

@johnwalker
Created November 29, 2013 22:19
Show Gist options
  • Save johnwalker/7712723 to your computer and use it in GitHub Desktop.
Save johnwalker/7712723 to your computer and use it in GitHub Desktop.
(ns factor.handler
(:use [compojure.core]
[hiccup core form page]
[me.raynes.conch :refer [programs with-programs let-programs]]
[clojure.core.async :as async :refer [<! >! chan go put!]]
[ring.middleware.params :only [wrap-params]]
[ring.util.response :as resp]
[incanter core stats charts datasets])
(:require [compojure.handler :as handler]
[compojure.route :as route]
[korma.db :refer :all]
[korma.core :refer :all]
[clojure.java.jdbc :as j]
[clojure.java.jdbc.sql :as s]
[clojure.string :as str]
[clojure.data.json :as json]
[ring.adapter.jetty :as jetty])
(:import [java.io ByteArrayOutputStream ByteArrayInputStream])
(:gen-class))
(def queue (atom clojure.lang.PersistentQueue/EMPTY))
(def composites (chan))
(programs factor)
(def program-map {"factor" factor})
(def db-spec {:classname "org.h2.Driver"
:subprotocol "h2"
:subname "resources/db"
:user "sa"
:password ""
:naming {:keys str/upper-case
:fields str/upper-case}})
(defn init []
(j/with-connection db-spec
(j/create-table :composite
[:id "int auto_increment primary key"]
[:value "varchar(10000)"]
[:duration "varchar(10000)"]
[:algorithm "varchar(100)"]
[:result "varchar(10000)"])))
(defdb korma-db db-spec)
(defentity composite
(entity-fields :id :value :duration :algorithm :result))
(defmacro msecs [body]
`(let [start-time# (System/nanoTime)
result# ~body
end-time# (System/nanoTime)]
[(- end-time# start-time#) result#]))
(defn parse-int [s]
(try (BigInteger. s)
(catch Exception e nil)))
(defn draw-chart [algorithm]
(let [records (->> (select composite
(where {:ALGORITHM algorithm}))
(map #(update-in % [:DURATION] (comp count str parse-int)))
(map #(update-in % [:VALUE] (comp count str parse-int)))
(sort-by :VALUE))]
(with-data (dataset [:DURATION :VALUE] records)
(let [out (ByteArrayOutputStream.)
in (do (save (scatter-plot :VALUE :DURATION
:title algorithm
:legend false
:x-label "Number's Value"
:y-label "Factorization Time")
out :width 1200 :height 600)
(ByteArrayInputStream. (.toByteArray out)))]
{:status 200
:headers {"Content-Type" "image/png"}
:body in}))))
(defn queue-page
([]
(html5
[:head
[:title "Factorization"]]
[:body
(form-to {:name "factor-request"}
[:put "/"]
(text-field {:name "composite"
:autofocus true} :composite)
(text-field {:name "algorithm"} :algorithm)
(submit-button "Factor"))
[:img {:src "/factor"}]
[:p "Currently working on:"]
[:ul (for [[number algorithm] @queue]
[:li number " " algorithm])]]))
([composite algorithm]
(when-let [number (parse-int composite)]
(when (program-map algorithm)
(put! composites [number algorithm])
(swap! queue conj [number algorithm])))))
(defroutes app-routes
(GET "/" [] (queue-page))
(PUT "/" [composite algorithm] (queue-page composite algorithm) (resp/redirect "/"))
(GET "/factor" [] (draw-chart "factor"))
(route/resources "/")
(route/not-found "Not Found"))
(def app
(wrap-params app-routes))
(defn factor-chan []
(go (while true
(let [[number algorithm] (<! composites)
program (program-map algorithm)
string-number (str number)
[ms result] (msecs (program string-number))]
(insert composite (values {:value string-number :duration ms
:result result :algorithm algorithm}))
(swap! queue pop)))))
(defn -main [& [port]]
(let [port (Integer. (or port (System/getenv "PORT") 5000))]
(factor-chan)
(jetty/run-jetty #'app {:port port :join? false})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment