Fork me on GitHub
#clojure-uk
<
2020-02-11
>
seancorfield05:02:41

Did you survive the storms OK?

yogidevbear05:02:24

I always find the UK's reaction to "storms" fairly comical šŸ˜„ We had a fence pop out, but managed to get it back into place quite easily thankfully. Trampoline did nearly blow away 2 days ago though! How are you doing Sean?

seancorfield05:02:05

We had high winds too this weekend. Several trees down in our town and road closures and a big chunk of the town was without power for a day or so.

seancorfield05:02:25

Most of the schools were closed because of loss of power.

yogidevbear05:02:34

Sounds like you had it a bit worse than us then

yogidevbear05:02:55

Lights only did a little bit of flickering

seancorfield05:02:47

We had several "brown outs" -- lights flickering and our router rebooting... which played havoc with us binge-watching Ragnarok (the Netflix show from Norway).

šŸ˜‚ 4
seancorfield05:02:06

It was awesome! We got through all six episodes last night, despite the storm šŸ™‚

seancorfield05:02:39

We binge-watched October Faction before that. Also awesome.

yogidevbear05:02:42

Don't mess with the internet! I think that would have been rather annoying šŸ˜‚

yogidevbear05:02:43

We got through about 4 episodes of October Faction. I was enjoying it. I think the OH wasn't convinced

yogidevbear05:02:33

We've been binge watching Van Helsing.

yogidevbear05:02:02

Onto the final season that's just come out

seancorfield05:02:34

OF does take a while to really get going. It's worth it.

šŸ‘ 4
dharrigan05:02:45

Good Morning!

dharrigan05:02:14

Sean, I have a question for you. It's about remote repl in production. Not about the merits/demerits, etc., just this. When you run your code (in a docker image? natively, as a jar?), do you always run it with a socket server listening (with appropriate firewall/security rules to prevent those without appropriate permissions to access), or do you have to redploy the image with the socket server listening, or do you have a magic toggle somewhere (db?) that the application polls frequently to determine whether to fire up a socket server?

seancorfield05:02:53

We run everything on the base O/S using java -jar now (we used to use java -cp ... clojure.main -m entry.point) and our "service" script looks for a .jvm_opts file next to the JAR file and uses the contents of that, if present, in that java command.

seancorfield05:02:27

Some processes have .jvm_opts files, some don't. Some only have them when we first put them in production, to aid with debugging, some get to keep them all the time. Some don't have one, but we'll add one temporarily (and just service <whatever> restart to pick it up), if we need to debug something unexpected.

seancorfield05:02:23

All of them are set to bind to 127.0.0.1 only, I believe, and we use an ssh tunnel over the VPN to get access from local systems (I can just connect Atom/Chlorine to a remote process that way and evaluate code in Rich Comment Forms for debugging -- and occasionally eval an updated function directly into production if I need additional debugging or a patched version for a quick bug fix).

seancorfield05:02:47

In the later case, we'll also fast-track a fix through CI/QA to production to make it permanent.

dharrigan05:02:50

right right, so they aren't enabled by default, only if the opts file is there, and if it needs to be, then the file is dropped into place and the service restarted. kk. understood šŸ™‚

dharrigan05:02:47

For me, I run inside a docker container, so if I need a repl I redploy the docker container with the JVM_OPTS magic incantation to enable a socket listener then expose the port on the container - this port is only accessible to the local dev network

seancorfield05:02:33

I just checked on one of our production servers, and two of our seven processes have those files in place. So they're "permanent" in that respect.

dharrigan05:02:58

I was toying with the idea of having a feature toggle that the application would poll every minute or so and if enabled, it would start the socket server, give this a more dynamic ability - I'll ponder.

seancorfield05:02:49

We used to have something like that but moved away from it because we just didn't find we needed to dynamically start REPLs -- and didn't want the extra code (and polling) in production.

mccraigmccraig07:02:14

can you bind the repl to localhost and shell in to your running container to access it @dharrigan ?

dharrigan07:02:37

I can do that too, yes.

thomas08:02:59

morning. CO2 count back to 444ppm at the moment, probably a bit lower today as uesterday we had a fullhouse with 10 people in the office.

Ben Hammond09:02:26

the very-new-and-expensive firth-of-forth roadbridge is close due to risk of ice falling from the suspension cables

Ben Hammond09:02:53

which is a bit embarassing

otfrom09:02:29

given that the risk to the other one was catastrophic failure, there did need to be something

Ben Hammond09:02:19

didn't ice accumulation figure in the original design? that's what I dont understand

Ben Hammond09:02:48

just been a bit windy

Ben Hammond09:02:50

the ice/snow hasn't been spectacular

otfrom09:02:04

I would have thought so. I wonder if this is one of the less likely cases for accumulation (right temp, right humidity, right wind)

Ben Hammond09:02:31

yeah maybe; freak conditions are always possible of course

Ben Hammond09:02:41

it does sound a bit strange though

Conor09:02:57

Oh! ill-fated Bridge of the Silv'ry Tay / I must now conclude my lay / By telling the world fearlessly without the least dismay / That your central girders would not have given way / At least many sensible men do say / Had they been supported on each side with buttresses / At least many sensible men confesses / For the stronger we our houses do build / The less chance we have of being killed

otfrom09:02:00

my understanding is that this one is much better in wind than the old one

otfrom09:02:36

@conor that poem is engraved in the pavement here looking at where that bridge was and where its replacement stands

Conor09:02:38

I should have gone to visit the spot when I lived in Scotland

otfrom09:02:53

(which is the bridge if not the engraving)

Ben Hammond09:02:27

do fragments of steam engine appear at low time?

Ben Hammond09:02:37

long ago swept into the North Sea I suppose

otfrom09:02:38

not that I've seen

otfrom09:02:48

the stumps of the old bridge are visible in that shot tho

otfrom09:02:06

it is a constant reminder to me of the dangers of hubris

Ben Hammond09:02:05

The dark counterpoint to > There's another train, there always is is > The train you are currently on may crash at any moment

otfrom09:02:06

@ben.hammond I'll still hoping a gamma ray burster gets me instead. It might be on its way right now!

otfrom09:02:49

2nd fave is in a meteor strike

Ben Hammond09:02:50

dispatched 10e9 years ago, solely for the purpose of frying you

otfrom09:02:28

oh, not just to get me. I'm just collateral damage in a thoughtless and uncaring universe. It helps keep my megalomania down.

otfrom09:02:25

btw, the Tay is very silvery and the engineering advice is sound. šŸ˜‰

Ben Hammond09:02:26

meglomania is one of life's guilty pleasures why deny it? why keep it down?

šŸ˜‚ 4
otfrom09:02:45

it would be very time consuming. šŸ˜„

Rachel Westmacott09:02:06

RCFOTD:

clojure.test/join-fixtures
([fixtures])
Composes a collection of fixtures, in order.  Always returns a valid
  fixture function, even if the collection is empty.

šŸ‘ 4
Adrian Smith09:02:13

If you're in or around Bristol tomorrow, we're running a meetup with the topic of async in Clojure: https://www.meetup.com/Bristol-Clojurians/events/hdzjnrybcdbqb/ should be good, come along

šŸ‘ 8
cddr10:02:00

re: #queensferrycrossing, here's a civil engineer's blog article on the topic of icy bridges... https://www.newcivilengineer.com/archive/bridge-brilliance-falling-ice-10-08-2016/

cddr10:02:28

Apparently it's rare enough that mitigation is the most pragmatic solution at the moment. Can't design a way out of it without using up too much energy.

šŸ‘ 4
otfrom14:02:30

I'd also read today that over the last 2 years the old bridge would have been closed 34 more times, so the new bridge is an improvement.

Samuel11:02:30

Morning y'all

šŸ‘‹ 8
otfrom14:02:30

I'd also read today that over the last 2 years the old bridge would have been closed 34 more times, so the new bridge is an improvement.

Samuel15:02:48

So, I'm trying to express predicates on maps as maps / vectors, similar to enlive's implementation - but no nesting on the subject, :. no automatons - This doesn't feel like a very idiomatic way to get the job done:

(defn or-map-pred
  "Give map `m' (record), and map `p' (pred|pred|...) return any: p_n is true for m.
  returns true/false on the k/v being present in the record, OR
  returns true if `p' is nil/empty. "
  [m p]
  (boolean
   (or (not p)    ; permit nil/{} blank preds as `true'
       (empty? p) ; covering ^
       (some #{true}
             (map (fn [k]
                    (= (get m k) (get p k)))
                  (keys p))))))

(clojure.core.test/is
  (true?
    (or-map-pred {:title "Test Data Yas" :favourite? true}
                 {:favourite? true})))
This function can be mapped and/or filtered, even composed as and:
(defn and-map-pred
  "Give a map (record), and a vec (pred&pred&...)"
  [m p]
  (every? (fn [pred] (or-map-pred m pred)) p))

(
 (true? (and-map-pred {:title "Test Data Yas" :favourite? true}
                      [{:favourite? true}])))
Filtering:
(defn dec-filter
  [coll pred]
  (filter #(and-map-pred % pred) coll))

(dec-filter [{:title "blah 1" :attr "goose"}]
            [{:attr "goose"}])
;; => [{:title "blah 1" :attr "goose"}]
Before I go down the rabbit hole here, can I get some thoughts from the room? Feel free to roast this implementation Edit: I realise I haven't really asked a question here, so: ā€¢ Would you advise against the use of closures to pass preds down in each of these functions? ā€¢ This implementation is mapping everywhere, and will scale poorly as the size of the predicates grow; are there any strategies you use to sense-check the placement of ISeq functions (map / filter / every?)

Ben Hammond16:02:30

er so it sounds like you are describing

(defn cmp-maps
  "return true if any mapentry in m1 equals a mapentry in m2"
  [m1 m2]
  (reduce-kv (fn [acc k v]
                 (when (= v (get m2 k))
                   (reduced true)))
    nil
    m1))

Ben Hammond16:02:08

similiarly

(defn cmp-maps2
  [m1 m2]
  (some 
    (fn [[k v]] (= v (get m2 k))) 
    m1))

Ben Hammond16:02:06

general scaling advice is to prefer reduce unless you've got something funky (like a string append) where apply may scale better

Samuel16:02:46

Thanks for linking these šŸ‘ This is definitely the same wheelhouse

fmjrey16:02:09

However it sounds like you are trying to do some querying logic, so why not trying to use a logic engine (clara rules, core.logic), or even datascript

Samuel16:02:07

In my free days, I've just been exploring declarative query interfaces, and I was really captured by enlive's implementation. The logic above is just a thought process around a UI component that allows users to filter a grid on a bunch of tokens for arbitrary attributes from the data in the grid

Samuel16:02:16

This is all in efforts to show co-workers (primarily the Csharp devs) that it doesn't take much to write expressive code in Clojure -- I feel like I can't go too deep on core.logic from the jump

fmjrey16:02:15

KISS makes sense indeed. Also metabase, which is open source and written in clojure, may provide some inspiration with respects to declarative querying interfaces: https://www.metabase.com/docs/latest/users-guide/04-asking-questions.html

šŸ‘ 4
Samuel09:02:57

Thanks for linking this - I'll pull it in and have a go today

Samuel16:02:54

@ben.hammond Thanks for taking the time! Those cmp-maps functions are direct subsitutions for or-map-pred (aside from nil/empty considerations), and a much cleaner way to go

šŸ‘ 4
Samuel16:02:47

i had a bad experience with reduce-kv, and haven't gone back for a while haha (shield your eyes for the below)

(defn nsmap
  "Namespace all unqualified keys in `m` with `n'.
  [m]: Takes a map of maps, flattens & namespaces inner keys with outer keys.
       e.g
  (ns-map {:links {:artist \"/Nas/\" :title \"/Nas/Halftime\"}
           :text  {:artist \"Nas\"   :title \"Halftime\"}})
  ;; => {:links/artist \"/Nas/\" :links/title \"/Nas/Halftime\"
         :text/artist  \"Nas\"   :text/title  \"Halftime\"}
  "
  ([m]
   (into {} (map #(nsmap (% m) (name %)) (keys m))))
  ([m n]
   (reduce-kv
    (fn [acc k v]
      (let [new-kw (if (and (keyword? k)
                            (not (qualified-keyword? k)))
                     (keyword (str n) (name k))
                     k)]
        (assoc acc new-kw v)))
    {} m)))

Ben Hammond17:02:36

just for fun, I think I'd write that as

(defn flatten-maps
  "depthfirst traversal of nested map, creating flat map keyed by vector paths "
  ([m]
   (into {} (flatten-maps [] m)))
  ([prev m]
   (if (map? m)
     (eduction
       (mapcat (fn [[k v]] (flatten-maps (conj prev k) v)))
       m)
     [(clojure.lang.MapEntry. prev m)])))

Ben Hammond17:02:57

(flatten-maps {:links {:artist "/Nas/" :title "/Nas/Halftime"}
               :text  {:artist "Nas"   :title "Halftime"}})
=>
{[:links :artist] "/Nas/",
 [:links :title] "/Nas/Halftime",
 [:text :artist] "Nas",
 [:text :title] "Halftime"}

Ben Hammond17:02:20

(flatten-maps {:a {:b 2 :c {:d 3 :e {:f {:g 4 :h 5} :i 6 :j {:k 7 :l {:m 8}}} :n 9}} :10})

=>
{[:a :c :e :i] 6,
 [:a :c :e :j :l :m] 8,
 [:a :c :e :f :h] 5,
 [:a :c :e :f :g] 4,
 [:a :b] 2,
 [:o] 10,
 [:a :c :n] 9,
 [:a :c :e :j :k] 7,
 [:a :c :d] 3}

Ben Hammond17:02:59

I had to solve this in a previous life... but this time round I think I have a nicer solution

Ben Hammond17:02:42

actually that eduction does not really add anything and can be removed

Ben Hammond17:02:39

going the other way is alot easier

(reduce-kv assoc-in {} {[:a :c :e :i] 6,
                        [:a :c :e :j :l :m] 8,
                        [:a :c :e :f :h] 5,
                        [:a :c :e :f :g] 4,
                        [:a :b] 2,
                        [:o] 10,
                        [:a :c :n] 9,
                        [:a :c :e :j :k] 7,
                        [:a :c :d] 3})
=>
{:a {:c {:e {:i 6, :j {:l {:m 8}, :k 7}, :f {:h 5, :g 4}}, :n 9, :d 3}, :b 2},
 :10}

practicalli-johnny17:02:25

We have 25 students signed up for ClojureBridge London on 21/22nd February at Signal. If you are able to coach, please sign up and help us support the students as they learn. https://clojurebridgelondon.github.io/

parrot 16
3Jane20:02:20

how many coaches so far?

practicalli-johnny09:02:16

We have confirmed 12 of the coaches that signed up for ClojureBridge London are coming still. So, ideally we need another 10 coaches confirmed.

practicalli-johnny09:02:16
replied to a thread:how many coaches so far?

We have confirmed 12 of the coaches that signed up for ClojureBridge London are coming still. So, ideally we need another 10 coaches confirmed.