clojure

Websockets for Clojure Sente in Apache Reverse Proxy

The Clojure library sente allows you to do smooth web-socket work in Clojure. In our case, we wanted the typical “Your Session Expires in N seconds” alert for users of the app. Sente was working smoothly on our local machines, but we were getting obscure errors in the console about 500 responses in our browser console. The Problem As mentioned, our console was showing server errors on the path that was supposed to be doing the Sente channels.

Major Java-interop in Clojure

This project was for a class in which we submitted java. I wrote this Clojure code to produce a Java class that could be run according to their specifications. So here is some of the first Clojure I ever wrote, long ago in grad school, utilizing the OpenCV system for computer vision. Notice the heavy use of obscure (non-Clojurey) APIs on objexts, marked by all the (.XYZ ...) lines. (ns com.

Clojure exercise to transpose three lists

The need: take multiple vectors and view each vector as a column (not a row) of the data, so all the first items go together, all the second, etc. Here’s a rough version that felt too clunky (alert: it features a number) and fragile but happens to demonstrate the needs: (let [[names jobs langs :as all] [["john" "jane" "michael"] ["chef" "driver" "vet"] ["English" "German" "French"]]] (map #(zipmap [:name :job :lang] %) (partition 3 (interleave names jobs langs)))) ;; ({:name "john", :job "chef", :lang "English"} ;; {:name "jane", :job "driver", :lang "German"} ;; {:name "michael", :job "vet", :lang "French"}) Solution (let [[names jobs langs :as all] [["john" "jane" "michael"] ["chef" "driver" "vet"] ["English" "German" "French"]]] (apply map #(zipmap [:name :job :lang] %&) all)) ;; => ({:name "john", :job "chef", :lang "English"} {:name "jane", :job "driver", :lang "German"} {:name "michael", :job "vet", :lang "French"}) This solution taught me two new things:

Creating ToryAnderson.com with ShadowCLJS

After years of a languishing example of The Cobbler’s Children , I finally got around to renovating my own website: toryanderson.com. Admittedly I have a lot to learn about visual design, but I had a good time on the technical front. I took the opportunity to use technologies I love and have been pleased with the result – both in the product and the cost constraints. In other words, it was fun to build and cheap to host: Clojure[script] meets shared hosting.

Accordions out of the box with Clojurescript and Closure

Accordions are actually available out-of-the-box in Clojurescript with the included Google closure.js that Clojurescript is built upon. This code shows the AnimatedZippy, which has a nice slide-out function; there’s also a plain Zippy. They are drop-in replacements for eachother. Rendering the Accordion (Zippy) (ns toryanderson.views.components.shared "Shared components that may be used on multiple views" (:require [reagent.core :as r] [goog.dom :as dom] [goog.string :as gstr]) (:import goog.ui.AnimatedZippy)) (defn accordion [{:keys [header-text content-body]}] (let [header-id (gstr/createUniqueString) content-id (gstr/createUniqueString)] (r/create-class {:display-name "zippy" :reagent-render (fn [id] [:div.

Clojure app setup for Auto-deploy with raw systemd

REPLACED [2022-11-11 Fri] The below is hopefully informative, but it actually only causes a thing to deploy once and then to re-deploy on system restart. For instructions that ACTUALLY auto-deploy, see https://tech.toryanderson.com/2022/11/11/systemd-devops-run-and-restart-services/ Updated [2022-09-19 Mon] Fixed error in deploy script that occurred if trying to restart but nothing was in the docket Updated [2022-07-13 Wed] Enhanced the server-side deploy script to operate more transparently if files are missing.

A Lesson in the Beauty of Data - XML Parsing on the Front End: to CLJS or not to CLJS?

The task came that I need to parse some XML in a front-only app. In a sense, browsers are just big XML (≅ HTML) processors, so embracing the Clojure principle of being a hosted language, it seemed desirable to utilize the built-in power of my browser. This effort turned out to be a rabbit hole, though. Consider the following: A Native Approach (let [s "<title>Tech.ToryAnderson.com</title>" ;; 1 p (js/DOMParser.) ;; 2 doc (.

Fine-grained per-method middleware use with Reitit

Fact: I have middleware performing authentication (in this case, my CAS authentication middleware) Need: This middleware should apply to client-facing SPA-rendered views, which are requested via GET. Constraint: This middleware does NOT apply to non-get routes (which are headless so the authentication must be handled differently) Constraint: There exist headless GET routes, too, which should not be CAS authenticated Constraint: Individual routes may have a CAS-authenticated GET response, as well as non-CAS POST, PATCH, and DELETE responses Reitit allowed me to specify middleware on a delightfully granular level to solve this.

Deploying to Clojars with the new tokens

With a recent, well-deserved funding round to the Clojars repository project, the password you log in to the site with is no longer valid as the password with which you publish deployments. See https://github.com/clojars/clojars-web/wiki/Deploy-Tokens and https://clojars.org/tokens . The annoyingly unanswered question is how I adjust my setup to USE the token. So, here it is with Leiningen. Project.clj I have the following in my project.clj, which is the same as I had before switching from my web password to the token:

Adding Custom Transit Handlers to re-frame-http-fx AJAX requests

Setting the Scene Transit is a seamless alternative to JSON (actually an extension of JSON). Why use Transit when JSON is so prevalent? For me, the simple reason was that it allows me to preserve my data types (mine are Clojure, but they are not necessarily such) over the wire. For me in particular this was my time types, and my uuids (which I wanted to standardize so they stop alternating between UUIDs, strings, and keywords, for matching purposes).