Skip to content

Instantly share code, notes, and snippets.

@johnwalker
Last active May 23, 2018 04:44
Show Gist options
  • Save johnwalker/c8ec5a55924e18e9391a to your computer and use it in GitHub Desktop.
Save johnwalker/c8ec5a55924e18e9391a to your computer and use it in GitHub Desktop.
vigenere
(ns ^:figwheel-always vigenere.core
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[clojure.string :as str]
[cljs.core.async :refer [put! chan <! alts!]]))
(enable-console-print!)
(defonce app-state (atom {}))
(defn handle-change [e owner {:keys [text output]}]
(let [new-text (.. e -target -value)]
(put! output new-text)
(om/set-state! owner :text new-text)))
(defn make-editable [type properties]
(fn [{:keys [output text]} owner]
(reify
om/IInitState
(init-state [_]
{:output output
:text text})
om/IDidMount
(did-mount [_]
(put! output text))
om/IRenderState
(render-state [_ state]
(type
#js {:type "text"
:cols (:cols properties)
:rows (:rows properties)
:value (:text state)
:onChange #(handle-change % owner state)})))))
(defn encrypt [password [alphabet reverse-alphabet] plaintext]
(if (seq password)
(first (reduce (fn [[s p i] c]
(let [char-index (alphabet c)]
(if char-index
[(str s (reverse-alphabet
(mod (+ char-index (alphabet (get p i)))
(count (keys alphabet)))))
(str p c)
(inc i)]
[(str s c)
p
i])))
["" password 0 0] plaintext))
plaintext))
(defn crypto [{:keys [password-chan
plaintext-chan
alphabet-chan]}
owner]
(reify
om/IWillMount
(will-mount [_]
(go (loop []
(let [[v ch] (alts! [password-chan plaintext-chan alphabet-chan])]
(om/set-state! owner ch (if (= ch alphabet-chan)
(let [alpha (into {} (map-indexed (fn [i x] [x i]) (distinct v)))
numer (into {} (map (fn [[k v]] [v k]) alpha))]
[alpha numer])
v)))
(recur))))
om/IRenderState
(render-state [_ state]
(let [plaintext (get state plaintext-chan)
password (get state password-chan)
alphabet (get state alphabet-chan)]
(apply dom/div #js {:id "Ciphertext"}
(map #(dom/p {:class "CiphertextLine"} %)
(str/split-lines (encrypt password alphabet plaintext))))))))
(om/root
(fn [data owner]
(reify
om/IInitState
(init-state [_]
{:plaintext-chan (chan)
:password-chan (chan)
:alphabet-chan (chan)})
om/IRenderState
(render-state [_ {:keys [plaintext-chan password-chan alphabet-chan]}]
(dom/div #js {:id "Interface"}
(dom/div #js {:id "AlphabetPanel"}
(dom/h1 #js {:class "InputTitle"} "Alphabet")
(om/build (make-editable dom/textarea {:cols 80
:rows 1})
{:output alphabet-chan
:text "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,'.?!"}))
(dom/div #js {:id "PasswordPanel"}
(dom/h1 #js {:class "InputTitle"} "Password")
(om/build (make-editable dom/input {}) {:output password-chan
:text "0xDEADBEEF"}))
(dom/div #js {:id "TextPanel"}
(dom/div #js {:id "PlaintextPanel"}
(dom/h1 #js {:class "InputTitle"} "Plaintext")
(om/build (make-editable dom/textarea {:cols 80
:rows 20})
{:output plaintext-chan
:text "There's no place like home."}))
(dom/div #js {:id "CiphertextPanel"}
(dom/h1 {:class "InputTitle"} "Ciphertext")
(om/build crypto {:plaintext-chan plaintext-chan
:password-chan password-chan
:alphabet-chan alphabet-chan})))))))
app-state
{:target (. js/document (getElementById "app"))})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment