clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
2020-11-18T04:57:20.293800Z

Hey guys, a little confused by this behavior. (defn vector-X-Long [x] (loop [itr 0 arr []] (if (= itr x) arr (recur (inc itr) (conj arr itr))))) (defn create-data [dates] (->> dates (map (fn [x] {x {:booked? false :nameOfEvent :nothingBookedYet}})) (into {}))) (def lost (create-data (vector-x-long))) Why doesnt this return the hashmap in order. ex. {0 {}, 1 {}, 2 {}, 3{} ...} Instead it returns what feels like randomness. When I println x inside create-date its in order. How could I get it for (def lost) to be in order?

dpsutton 2020-11-18T04:59:16.294500Z

probably best for #beginners but maps are not ordered

dgb23 2020-11-18T05:16:16.295400Z

(seq {:a 1 :b 2 :c 3 :d 4})
=> ([:c 3] [:b 2] [:d 4] [:a 1])

(seq (into (sorted-map) {:a 1 :b 2 :c 3 :d 4}))
=> ([:a 1] [:b 2] [:c 3] [:d 4])

Rhishikesh Joshi 2020-11-18T11:49:44.298300Z

Is anyone here aware of any work done to integrate https://www.oracle.com/corporate/features/understanding-java-9-modules.html into a clojure project ? By that I mean, structuring a large clojure project into Java 9 modules and composing them into services etc.

murtaza52 2020-11-18T14:03:37.299900Z

(with-redefs [inc (fn [v] (+ 2 v))]
  (inc 2)) 

=> 3
what am I doing wrong ? (I was expecting 4)

vlaaad 2020-11-18T14:08:40.300600Z

maybe (inc 2) is inlined, hence the compiled code doesn’t do var dereferencing at all

alexmiller 2020-11-18T14:13:00.300800Z

^^

borkdude 2020-11-18T14:52:22.302400Z

Hackety hack:

(def inlined (atom {}))

(defmacro un-inline [var-sym & body]
  `(do (swap! inlined assoc (var ~var-sym) (:inline (meta (var ~var-sym))))
       (alter-meta! (var ~var-sym) dissoc :inline)
       (try ~@body
            (finally
              (alter-meta! (var ~var-sym) assoc :inline (get @inlined (var ~var-sym)))))))

(un-inline inc
           (with-redefs [inc dec]
             (prn (inc 1)))) ;; 0

(with-redefs [inc dec]
  (prn (inc 1))) ;; 2

alexmiller 2020-11-18T15:03:37.303800Z

keep in mind even that won't work if you call something in core that calls inc, because it's pre-compiled (with direct linking)

bronsa 2020-11-18T15:04:54.304100Z

I mean, even w/o direct linking it would've already been ... inlined

alexmiller 2020-11-18T15:05:43.304300Z

yep

ghadi 2020-11-18T15:06:27.304700Z

Pretty much everyone ignores modules

borkdude 2020-11-18T15:38:14.306700Z

yeah, you would have to reload those namespaces in the body of un-inline. veery hacky

Rhishikesh Joshi 2020-11-18T15:50:31.306800Z

Ok 🙂 What would be the preferred method to organise a large Clojure project and get features like dependency management and modularisation between groups of namespaces, without going down the road of full fledged libraries and services ?

cap10morgan 2020-11-18T16:57:51.309900Z

I'm trying to use Clojure to write a Sonarqube plugin (which expects Java). I have it loading my plugin, but then it crashes with Could not locate clojure/core__init.class, clojure/core.clj or clojure/core.cljc on classpath presumably b/c it loads plugins in their own isolated classloaders but Clojure uses its own (or something like that; I'm a bit out of my depth here). Anyone run into something like that before? Clojure and spec are in the jar file in META-INF/lib, so it seems to be related to the classloader thing.

nwjsmith 2020-11-20T19:58:22.452500Z

@cap10morgan did you end up getting this all worked out?

cap10morgan 2020-11-20T19:59:08.453300Z

I did not. Thanks for the link! Reading it now.

cap10morgan 2020-11-20T20:01:27.455300Z

hmm... interesting. I'm not sure anything like this exists in Sonarqube (what I'm trying to write a plugin for), so I'm trying to set Clojure's classloader to the one Sonarqube is using for the plugin. It gives a custom classloader to each plugin.

2020-11-18T17:01:58.312700Z

As a leiningen user so far, I've come across practicalli/clojure-deps-edn and wanted to try it on a new piece of code. However, on a simple clojure -X:project/new I just receive an error message: No function found on command line or in :exec-fn. Searching the tubes for this doesn't reveal anything helpful -- any idea what might be wrong here?

cap10morgan 2020-11-18T17:11:01.314900Z

@schaueho I think you will need to setup your ~/.clojure/deps.edn file correctly for that to work.

cap10morgan 2020-11-18T17:12:44.316900Z

Looks like the example deps.edn in that GH repo has what you want.

2020-11-18T17:13:03.317200Z

well, I followed the instructions on the practically/clojure-deps-edn repo and so my ~/.clojure/deps.edn actually contains a :project/new alias

2020-11-18T17:13:43.317700Z

that's why I'm puzzled why it doesn't work

2020-11-18T17:15:22.318100Z

Clojure tools are also updated to 1.10.1.727

alexmiller 2020-11-18T17:22:29.319Z

I copied the :project/new alias from that repo into my ~/.clojure/deps.edn and was able to successfully run clojure -X:project/new so must be something in the setup

alexmiller 2020-11-18T17:24:50.319400Z

clj -Srepro -Sdeps '{:aliases {:project/test {:replace-deps {seancorfield/clj-new {:mvn/version "1.1.226"}} :exec-fn clj-new/create :exec-args {:template lib :name practicalli/playground}}}}' -X:project/test

alexmiller 2020-11-18T17:25:07.319800Z

^^ can you try that one-liner? it ignores your ~/.clojure/deps.edn

2020-11-18T17:25:59.320Z

this works

2020-11-18T17:27:05.321300Z

it also works when I copy the deps.edn file to a separate directory and run the command from there, so I guess somehow the deps.edn is not getting picked up from ~/.clojure/

2020-11-18T17:27:57.321900Z

^^ it meaning clojure -X:project/new

seancorfield 2020-11-18T17:29:20.322600Z

@schaueho Maybe there's a typo in your ~/.clojure/deps.edn file? Could you share it, or at least part of it that's relevant to this issue?

alexmiller 2020-11-18T17:29:48.323500Z

can you clj -Sdescribe and look at the output to see if :config-user points at ~/.clojure/deps.edn ?

alexmiller 2020-11-18T17:31:00.324900Z

could be different if you have $CLJ_CONFIG or $XDG_CONFIG_HOME set

2020-11-18T17:31:03.325Z

@seancorfield it's a clone of the current practically/clojure-deps-edn repo that I didn't edit

alexmiller 2020-11-18T17:31:53.325900Z

I checked the practicalli/clojure-deps-edn file and it works fine for me

2020-11-18T17:32:03.326100Z

@alexmiller actually it doesn't, it points at :config-dir "~/.config/clojure"

alexmiller 2020-11-18T17:32:22.326500Z

well there you go :)

alexmiller 2020-11-18T17:32:35.326700Z

you probably have XDG_CONFIG_HOME set

alexmiller 2020-11-18T17:32:52.327100Z

in that case, config will be at $XDG_CONFIG_HOME/clojure

💯 1
alexmiller 2020-11-18T17:33:20.327600Z

you can override that by setting CLJ_CONFIG to your ~/.clojure if you want

2020-11-18T17:34:13.328200Z

thanks a ton!

nwjsmith 2020-11-18T17:47:33.328400Z

I've experience a similar-seeming issue w/ Quartz before, maybe this helps? http://clojurequartz.info/articles/durable_quartz_stores.html#quartz_and_clojure_class_loaders

nod 2020-11-18T18:48:19.330500Z

Hey, I probably did something stupid and can't use either clj or clojure . lein repl still works fine. Could anybody help me figure it out? clojure -Sdescribe output:

nod 2020-11-18T18:49:14.331300Z

{:version "1.10.1.708" 
 :config-files ["/home/myuser/.clojure/deps.edn" ] 
 :config-user "/home/myuser/.clojure/deps.edn" 
 :config-project "deps.edn" 
 :install-dir "/usr/clojure" 
 :config-dir "/home/myuser/.clojure" 
 :cache-dir "/home/myuser/.clojure/.cpcache" 
 :force false 
 :repro false 
 :main-aliases "" 
 :repl-aliases ""}

2020-11-18T18:49:43.331800Z

"can't use" - what specifically fails?

nod 2020-11-18T18:50:07.332300Z

Yeah, sorry, I sent the message accidentally

nod 2020-11-18T18:50:15.332500Z

Error: Could not find or load main class clojure.main Caused by: java.lang.ClassNotFoundException: clojure.main

nod 2020-11-18T18:50:37.333Z

This is the output for both clj and clojure

2020-11-18T18:50:53.333300Z

"/usr/clojure" is a weird install location

nod 2020-11-18T18:53:04.334700Z

I'm on OpenSUSE btw

nod 2020-11-18T18:53:25.335200Z

If I'm not mistaken I just installed it via YaST2's GUI (which I suppose is OpenSUSE's official way)

nod 2020-11-18T18:54:00.335700Z

I don't recall setting any paths manually

nod 2020-11-18T18:55:02.336600Z

I just checked, /usr/clojure doesn't exist

2020-11-18T18:55:58.337500Z

so -Sdescribe is mistaken, or exposing some misconfiguration?

nod 2020-11-18T18:57:17.338Z

I suppose... How can I find out?

dpsutton 2020-11-18T18:58:15.339300Z

Is opensuse Debian based? I know there’s a package there called clojure that is a bad wrapper

2020-11-18T18:59:35.339800Z

opensuse is derived from redhat, but split a long time ago

2020-11-18T18:59:52.340300Z

the debian clojure just wraps clojure.jar, and has none of the cli features, yeah

2020-11-18T19:00:12.340800Z

it wouldn't be able to produce the "-Sdescribe" output

👍 1
2020-11-18T19:01:11.341700Z

@edjroot you could try downloading from http://clojure.org and installing the scripts to ~/bin or /usr/local/bin- it's pretty simple

2020-11-18T19:03:02.343200Z

beyond what it provides, all it needs is java to be on path

nod 2020-11-18T19:03:48.343300Z

Alright, I'll do that and let you know if it works, thanks!

nod 2020-11-18T19:04:11.343700Z

Isn't it weird that lein repl works though?

2020-11-18T19:04:30.344Z

not at all - clojure is just a jar that you put on the java classpath

2020-11-18T19:04:49.344400Z

it doesn't use any global installation that clj / lein would share

2020-11-18T19:05:20.345Z

both use .m2 to cache deps, but that isn't used for clojure itself on startup

nod 2020-11-18T19:05:32.345300Z

Oh, that makes sense

2020-11-18T19:06:20.346100Z

getting down to the basics, clojure is a java library, providing a clojure.main class with a -main entrypoint that runs a REPL compiling clojure code to bytecode and running that bytecode

seancorfield 2020-11-18T19:19:36.347Z

Since there's a brew tap for clojure/tools/clojure that is maintained by the Clojure team, I've found it worth installing linuxbrew and using that to keep my CLI install up-to-date.

alexmiller 2020-11-18T19:21:27.348300Z

fyi, homebrew core tap is now being kept up to date with stable releases from clojure/tools/clojure. and linux tap is tracking that one, so while there is a lag of couple days for each hop there, they should all be showing you approximately the same thing these days.

nod 2020-11-18T19:23:50.349700Z

So, before trying the CLI method I actually uninstalled and installed it again via YaST2 and now it works... Go figure 🙂 Thanks a lot for the quick and helpful responses!

2020-11-18T21:06:56.351500Z

Is it possible to change what a var points to at compile time? Example is I want to replace clojure.core/memoize with my own version.

2020-11-18T21:12:10.352Z

Compile-time is all of the time in Clojure 🙂

2020-11-18T21:15:03.354200Z

The smiley is there because it isn't strictly true, but it is true that whether you are loading code from a file or entering expresssions at a REPL, all top level forms are compiled before they are evaluated. You can use things like alter-var-root to modify the root binding of a Var. If there is a call to that at the top level in a file that you load or require, then it will be evaluated and take effect while loading/requiring that file.

2020-11-18T21:20:05.354300Z

This is what I wasn’t sure about. Like most uses of memoize will be (def my-fn (memoize my-fn*)) , so it seemed like it would be too late to catch those cases if I just alter-var-root

2020-11-18T21:21:09.354500Z

If you do not compile Clojure with direct linking, which is disabled by default, then whenever memoize is called, it will dereference the Var's current value.

2020-11-18T21:22:12.354700Z

That is why in a REPL you can use defn to redefine a function foo, and with a few exceptions, other functions defined earlier that call foo will call the updated version.

2020-11-18T21:22:57.354900Z

Oh, in your case, you will want to make sure that alter-var-root is evaluated before you evaluate that def form.

2020-11-18T21:23:29.355100Z

Because using alter-var-root after such a def form, yes, memoize will have been deref'd at the time that def form is evaluated.

2020-11-18T21:25:38.355300Z

OK, then I will give it another go but try to be more careful about when it’s called. Basically I’ll need to alter-var-root before I do any requires of code that will use it.

2020-11-18T21:28:38.355500Z

There may be easier ways to do it in your code base, but if you have some kind of utils namespace that is require'd by most or all of your namespaces, you could put the alter-var-root in there and know that it will take effect before any namespace that require's that one

2020-11-18T21:29:51.355700Z

Then again, if you have that, then you could instead define your own memoize-like function, and call it instead of clojure.core/memoize throughout your code base, but I'm guessing if you were willing to do that, you wouldn't have asked 🙂

2020-11-18T21:30:50.355900Z

In this case I’m actually trying to target a third party lib.

2020-11-18T21:31:32.356100Z

But I think I can create an entrypoint where I do setup and then do a (require …)

2020-11-18T21:31:41.356300Z

vs using ns

2020-11-18T21:32:06.356500Z

welcome to monkey patching!

😅 1
oliver 2020-11-18T23:04:58.358700Z

Hi! I'm follwowing the current beta of Dmitry Sotnikov's Book on Luminus. I have started over three times by now due to a bug that leaves me mystified, but that inevitably seems to creep up  at some point. I get the following error when I try to start the application (once the REPL has started): Execution error (AssertionError) at ns-tracker.dependency/depend (dependency.clj:57). Assert failed: self-referential dependency (not (= x dep)) As far as I can remember, on each occasion the last thing I did before this happened was wiping one of my database tables – hardly something that I'd expect to lead to an NS-problem. Here's what I know: 1. I definitely have no circular dependencies among my own namespaces 2. All I did was manipulate the DB. Most imortantly none of my clojure namespaces have changed. 3. The Problem is related to Ring's `wrap-reload` middleware, which apparently does it's own dependency-checking. When I remove it from my dev-middleware-chain everything works (except reloading, obiously). I can also create an uberjar without problems. I know that certain people discourage the use `wrap-reload`  in general (as Sean Corfield did in reply to a https://clojurians-log.clojureverse.org/beginners/2020-10-06. However, I can hardly believe that this kind of error is intractable to the point that I have to switch build tooling… Any ideas on where this might stem from? (edited)

2020-11-18T23:10:53.359400Z

you should revisit assertion #1

2020-11-18T23:11:26.360Z

because that error indicates ns-tracker (which is used by wrap-reload) disagrees and thinks you do

oliver 2020-11-18T23:12:00.360600Z

Is it really possible to compile the project into an uberjar in that case?

2020-11-18T23:12:59.361Z

it is complicated

oliver 2020-11-18T23:13:22.361800Z

Well… I guess the circularity might only be resent in the dev-build…

2020-11-18T23:13:27.362100Z

so yes, it is possible I guess in the answer

2020-11-18T23:13:52.362800Z

and ns-tracker and clojure itself may not agree on how they detect circularity

oliver 2020-11-18T23:14:22.363400Z

But then, according to https://www.reddit.com/r/Clojure/comments/8cs5hg/what_does_self_referential_dependency_mean_and/, the circularity might be in one of my dependencies (read: libs)

2020-11-18T23:14:43.364200Z

very unlikely

oliver 2020-11-18T23:15:20.364900Z

hm… I can, of course re-check, but as I said: None of my Clojure source-files have changed… only in CLJS… and even there the ns declarations did not…

oliver 2020-11-18T23:15:45.365300Z

(thanks for taking the time btw)

2020-11-18T23:18:28.367600Z

one of the reasons some people discourage the use of things like wrap-reload is the code reloading is a complicated thing to do, and the state you get into with reloading is very unlikely to be exactly the same as the state you get when starting the system fresh

2020-11-18T23:19:36.368900Z

so if you have been going on and everything has been working fine using reloading for a while, then you kill and restart the process for some reason, and then things are broken, the change that caused the breakage could have been sometime ago and just happened to continue to work with reloading for whatever reason

2020-11-18T23:20:26.369800Z

but I would strongly suggest you go over your code with a fine tooth comb before you start looking at libraries

2020-11-18T23:21:07.371100Z

like, I've seen things where people where trying to debug something not behaving as they expected and it ended up they had two checkouts of the code and were editing and running different checkouts

oliver 2020-11-18T23:22:25.372200Z

I understand that… actually I'd even prefer to use something a bit simpler (not albeit not easier than leiningen): My first go was with boot… but I found my progress greatly hampered by dealing with build troubles 60% of the time when my actual goal was to grok Luminus…

2020-11-18T23:22:45.372400Z

I doubt it is a build tool issue

2020-11-18T23:23:36.373Z

the assertion that is failing is a check that fails when a namespace literally depends on itself

2020-11-18T23:24:29.374200Z

like if you had (ns foo (:require foo))

oliver 2020-11-18T23:25:33.375300Z

I gathered as much (I have dealt with circular dependencies on quite a number of occasions before)… I'll check again… I guess there's no way to find out which ns is actually offending?

2020-11-18T23:25:56.375700Z

there is a pr on the project to include the offending ns in the message

oliver 2020-11-18T23:27:16.376Z

pr? pull request?

2020-11-18T23:28:58.376200Z

yes

2020-11-18T23:29:42.377Z

what steps exactly do you take before you see the error?

oliver 2020-11-18T23:29:51.377200Z

ok, sorry if this is a dumb question… so the project you're talking about would be Ring?

2020-11-18T23:29:56.377400Z

no

2020-11-18T23:30:01.377700Z

ns-tracker

oliver 2020-11-18T23:31:43.380Z

Ok, thanks for you patience: here's how I reproduce it: 1. Jack-in CIDER → REPL Starts, all good so far 2. In user ns: (start) 3. I get this: 2020-11-19 00:27:38,376 [nREPL-session-d79a4c6f-7e7b-4cf4-bed5-9bb3c6896d1d] INFO guestbook.env - -=[guestbook started successfully using the development profile]=- Execution error (AssertionError) at ns-tracker.dependency/depend (dependency.clj:57). Assert failed: self-referential dependency (not (= x dep))

2020-11-18T23:32:03.380500Z

depending on what steps happen before you get the error, you may be able to run code before the error happens, which will allow you to change the definition of the function throwing the error to print out its arguments before throwing the error which will tell you which ns it is

oliver 2020-11-18T23:32:44.381700Z

I get something more detailed when I do it on the console with lei run (which also uses the dev profile)

2020-11-18T23:32:53.382Z

there's also lein check which simply loads up every clj file on local path, and it should hit an error and report it, it definitely tells you which file blew up

oliver 2020-11-18T23:34:20.383400Z

running lein check now…

2020-11-18T23:34:54.384600Z

run (alter-var-root (requiring-resolve 'ns-tracker.dependency/depend) (fn [orig] (fn [& args] (prn args) (apply orig args)))) before calling start

oliver 2020-11-18T23:35:01.384700Z

using lein run generates the following “full report”

2020-11-18T23:35:35.385600Z

the last thing that gets printed out will include the name of the offending namespace

oliver 2020-11-18T23:35:59.386100Z

lein check shows no errors… just one warning that does indeed smell a bit of “circularity”: Reflection warning, guestbook/core.clj:56:42 - call to java.lang.Thread ctor can't be resolved.

2020-11-18T23:36:16.386500Z

that has nothing to do with circularity

oliver 2020-11-18T23:36:23.386700Z

@hiredman I'll run your command right now

2020-11-18T23:37:01.387500Z

it may print out a lot

oliver 2020-11-18T23:37:05.387600Z

(thanks again to both of you for your time and patience)

oliver 2020-11-18T23:37:49.388200Z

@hiredman your command returns a function #function[user/eval29638/fn--29639/fn--29640]

2020-11-18T23:38:00.388500Z

sure, after you run it call start

2020-11-18T23:38:22.389100Z

then you'll get print outs of the arguments to the depend function as ns-tracker uses it

2020-11-18T23:38:45.389600Z

and the last print out will be the arguments it is called with before the assertion error

oliver 2020-11-18T23:38:51.389800Z

Yep… got a big printout

2020-11-18T23:39:37.390900Z

the arguments will generally be a list, the first element being a big map, the rest of the arguments are namespace names

oliver 2020-11-18T23:39:43.391100Z

The last thing printed is this: ({:dependencies {guestbook.routes.home #{guestbook.validation struct.core guestbook.layout guestbook.middleware ring.util.http-response <http://clojure.java.io|clojure.java.io> guestbook.db.core ring.util.response}, guestbook.handler #{mount.core guestbook.layout guestbook.routes.home reitit.ring ring.middleware.content-type guestbook.env guestbook.middleware ring.middleware.webjars}, guestbook.middleware.formats #{luminus-transit.time muuntaja.core}, guestbook.core #{guestbook.nrepl mount.core guestbook.config luminus-migrations.core luminus.http-server clojure.tools.logging clojure.tools.cli guestbook.handler}, guestbook.db.core #{conman.core mount.core guestbook.config next.jdbc.date-time next.jdbc.result-set}}, :dependents {guestbook.validation #{guestbook.routes.home}, guestbook.nrepl #{guestbook.core}, conman.core #{guestbook.db.core}, mount.core #{guestbook.core guestbook.db.core guestbook.handler}, guestbook.config #{guestbook.core guestbook.db.core}, struct.core #{guestbook.routes.home}, next.jdbc.date-time #{guestbook.db.core}, guestbook.layout #{guestbook.routes.home guestbook.handler}, guestbook.routes.home #{guestbook.handler}, reitit.ring #{guestbook.handler}, luminus-migrations.core #{guestbook.core}, luminus.http-server #{guestbook.core}, luminus-transit.time #{guestbook.middleware.formats}, clojure.tools.logging #{guestbook.core}, ring.middleware.content-type #{guestbook.handler}, muuntaja.core #{guestbook.middleware.formats}, guestbook.env #{guestbook.handler}, next.jdbc.result-set #{guestbook.db.core}, guestbook.middleware #{guestbook.routes.home guestbook.handler}, clojure.tools.cli #{guestbook.core}, ring.util.http-response #{guestbook.routes.home}, <http://clojure.java.io|clojure.java.io> #{guestbook.routes.home}, guestbook.db.core #{guestbook.routes.home}, ring.middleware.webjars #{guestbook.handler}, guestbook.handler #{guestbook.core}, ring.util.response #{guestbook.routes.home}}} guestbook.db.core guestbook.db.core)

2020-11-18T23:40:09.391600Z

so ns-tracker thinks guestbook.db.core depends on guestbook.db.core

✔️ 1
oliver 2020-11-18T23:41:07.392300Z

fascinating… ok… I'll have another look at this ns…

oliver 2020-11-18T23:41:53.392600Z

Ok… this is really embarrassing…

oliver 2020-11-18T23:42:18.393300Z

`(:require [next.jdbc.date-time] [next.jdbc.result-set] [conman.core :as conman] [mount.core :refer [defstate]] [guestbook.config :refer [env]] ;; [java-time :refer [java-date]] [guestbook.db.core :as db])`

2020-11-18T23:42:24.393400Z

more embarrassing then that guy who had two code checks and was editting one and running the other?

oliver 2020-11-18T23:42:53.394Z

I have no idea how I managed to do an then miss this…

2020-11-18T23:43:13.394800Z

well, someday that pr will get merged and it won't be a big mystery

👏 1
oliver 2020-11-18T23:43:19.395Z

I was actually looking for exactly this kind of thing (because it was what I understood the error to mean)

oliver 2020-11-18T23:44:05.395700Z

Still… I was lucky to have someone with a thorough knowledge ot ns-tracker's inner workings

oliver 2020-11-18T23:44:50.396400Z

I have an hypothesis as to how this came about… but I feel I've been bothering you long enough…

oliver 2020-11-18T23:45:10.397Z

If we weren't in lockdown I'd buy you a pint…

oliver 2020-11-18T23:45:35.397500Z

Anyway: thanks again (looking forward to that pr)!

dpsutton 2020-11-18T23:48:21.398100Z

what's the hypothesis?

dpsutton 2020-11-18T23:48:28.398300Z

we've come so far on this journey 🙂