Move ManuForm changes to the main clj

Move ManuForm changes to the main clj

--- src/dactyl_keyboard/dactyl.clj
+++ src/dactyl_keyboard/dactyl.clj
@@ -3,6 +3,18 @@
   (:require [scad-clj.scad :refer :all]
             [scad-clj.model :refer :all]
             [unicode-math.core :refer :all]))
+
+
+(def nrows 6)
+(def ncols 6)                           ; it's not set up to change this
+(def lastrow (dec nrows))
+(def cornerrow (dec lastrow))
+(def α (/ π 12))                        ; curvature of the columns
+(def β (/ π (if (= nrows 4) 26 36)))    ; curvature of the rows
+(def centerrow (- cornerrow 1))         ; controls front-back tilt
+(def centercol 3)                       ; controls left-right tilt / tenting
+(def orthographic-x (> nrows 5))        ; for larger number of rows don't curve them in as much
+; (def orthographic-x true)

 ;;;;;;;;;;;;;;;;;
 ;; Switch Hole ;;
@@ -86,11 +98,9 @@
 ;; Placement Functions ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;

-(def columns (range 0 6))
-(def rows (range 0 5))
-
-(def α (/ π 12))
-(def β (/ π 36))
+(def columns (range 0 ncols))
+(def rows (range 0 nrows))
+
 (def cap-top-height (+ plate-thickness sa-profile-key-height))
 (def row-radius (+ (/ (/ (+ mount-height 1/2) 2)
                       (Math/sin (/ α 2)))
@@ -98,48 +108,40 @@
 (def column-radius (+ (/ (/ (+ mount-width 2.0) 2)
                          (Math/sin (/ β 2)))
                       cap-top-height))
+(def column-x-delta (+ -1 (- (* column-radius (Math/sin β)))))

 (defn key-place [column row shape]
   (let [row-placed-shape (->> shape
                               (translate [0 0 (- row-radius)])
-                              (rotate (* α (- 2 row)) [1 0 0])
+                              (rotate (* α (- centerrow row)) [1 0 0])
                               (translate [0 0 row-radius]))
         column-offset (cond
                         (= column 2) [0 2.82 -4.5]
                         (>= column 4) [0 -5.8 5.64]
+                        ; (= column 22) [0 2.82 -4.5]
+                        ; (>= column 24) [0 -5.8 5.64]
                         :else [0 0 0])
-        column-angle (* β (- 2 column))
+        column-angle (* β (- centercol column))
         placed-shape (->> row-placed-shape
                           (translate [0 0 (- column-radius)])
                           (rotate column-angle [0 1 0])
                           (translate [0 0 column-radius])
-                          (translate column-offset))]
-    (->> placed-shape
+                          (translate column-offset))
+        column-z-delta (* column-radius (- 1 (Math/cos column-angle)))
+        placed-shape-ortho (->> row-placed-shape
+                                (rotate column-angle [0 1 0])
+                                (translate [(- (* (- column centercol) column-x-delta)) 0 column-z-delta])
+                                (translate column-offset))]
+    (->> (if orthographic-x placed-shape-ortho placed-shape)
          (rotate (/ π 12) [0 1 0])
-         (translate [0 0 13]))))
-
-(defn case-place [column row shape]
-  (let [row-placed-shape (->> shape
-                              (translate [0 0 (- row-radius)])
-                              (rotate (* α (- 2 row)) [1 0 0])
-                              (translate [0 0 row-radius]))
-        column-offset [0 -4.35 5.64]
-        column-angle (* β (- 2 column))
-        placed-shape (->> row-placed-shape
-                          (translate [0 0 (- column-radius)])
-                          (rotate column-angle [0 1 0])
-                          (translate [0 0 column-radius])
-                          (translate column-offset))]
-    (->> placed-shape
-         (rotate (/ π 12) [0 1 0])
-         (translate [0 0 13]))))
+         (translate [0 0 24]))))

 (def key-holes
   (apply union
          (for [column columns
                row rows
-               :when (or (not= column 0)
-                         (not= row 4))]
+               :when (or (.contains [2 3] column)
+                         (not= row lastrow))]
            (->> single-plate
                 (key-place column row)))))

@@ -147,8 +149,8 @@
   (apply union
          (for [column columns
                row rows
-               :when (or (not= column 0)
-                         (not= row 4))]
+               :when (or (.contains [2 3] column)
+                         (not= row lastrow))]
            (->> (sa-cap (if (= column 5) 1 1))
                 (key-place column row)))))

@@ -177,10 +179,8 @@
   (apply union
          (concat
           ;; Row connections
-          (for [column (drop-last columns)
-                row rows
-                :when (or (not= column 0)
-                          (not= row 4))]
+          (for [column (range 0 (dec ncols))
+                row (range 0 lastrow)]
             (triangle-hulls
              (key-place (inc column) row web-post-tl)
              (key-place column row web-post-tr)
@@ -189,9 +189,7 @@

           ;; Column connections
           (for [column columns
-                row (drop-last rows)
-                :when (or (not= column 0)
-                          (not= row 3))]
+                row (range 0 cornerrow)]
             (triangle-hulls
              (key-place column row web-post-bl)
              (key-place column row web-post-br)
@@ -199,10 +197,8 @@
              (key-place column (inc row) web-post-tr)))

           ;; Diagonal connections
-          (for [column (drop-last columns)
-                row (drop-last rows)
-                :when (or (not= column 0)
-                          (not= row 3))]
+          (for [column (range 0 (dec ncols))
+                row (range 0 cornerrow)]
             (triangle-hulls
              (key-place column row web-post-br)
              (key-place column (inc row) web-post-tr)
@@ -212,954 +208,287 @@
 ;;;;;;;;;;;;
 ;; Thumbs ;;
 ;;;;;;;;;;;;
-
-(defn thumb-place [column row shape]
-  (let [cap-top-height (+ plate-thickness sa-profile-key-height)
-        α (/ π 12)
-        row-radius (+ (/ (/ (+ mount-height 1) 2)
-                         (Math/sin (/ α 2)))
-                      cap-top-height)
-        β (/ π 36)
-        column-radius (+ (/ (/ (+ mount-width 2) 2)
-                            (Math/sin (/ β 2)))
-                         cap-top-height)
-        #_(+ (/ (/ (+ pillar-width 5) 2)
-                            (Math/sin (/ β 2)))
-                         cap-top-height)]
-    (->> shape
-         (translate [0 0 (- row-radius)])
-         (rotate (* α row) [1 0 0])
-         (translate [0 0 row-radius])
-         (translate [0 0 (- column-radius)])
-         (rotate (* column β) [0 1 0])
-         (translate [0 0 column-radius])
-         (translate [mount-width 0 0])
-         (rotate (* π (- 1/4 3/16)) [0 0 1])
-         (rotate (/ π 12) [1 1 0])
-         (translate [-52 -45 40]))))
-
-(defn thumb-2x-column [shape]
-  (thumb-place 0 -1/2 shape))
-
-(defn thumb-2x+1-column [shape]
-  (union (thumb-place 1 -1/2 shape)
-         (thumb-place 1 1 shape)))
-
-(defn thumb-1x-column [shape]
-  (union (thumb-place 2 -1 shape)
-         (thumb-place 2 0 shape)
-         (thumb-place 2 1 shape)))
-
-(defn thumb-layout [shape]
-  (union
-   (thumb-2x-column shape)
-   (thumb-2x+1-column shape)
-   (thumb-1x-column shape)))
-
-(def double-plates
-  (let [plate-height (/ (- sa-double-length mount-height) 2)
+(def thumborigin [-23 -34 47])
+
+(defn deg2rad [degrees]
+  (* (/ degrees 180) pi))
+
+(defn thumb-tr-place [shape]
+  (->> shape
+       (rotate (deg2rad  10) [1 0 0])
+       (rotate (deg2rad -23) [0 1 0])
+       (rotate (deg2rad  -3) [0 0 1])
+       (translate thumborigin)
+       (translate [-10 -16 0])
+       ))
+(defn thumb-tl-place [shape]
+  (->> shape
+       (rotate (deg2rad  10) [1 0 0])
+       (rotate (deg2rad -23) [0 1 0])
+       (rotate (deg2rad  -3) [0 0 1])
+       (translate thumborigin)
+       (translate [-30 -15 -2])))
+(defn thumb-mr-place [shape]
+  (->> shape
+       (rotate (deg2rad  -6) [1 0 0])
+       (rotate (deg2rad -34) [0 1 0])
+       (rotate (deg2rad  48) [0 0 1])
+       (translate thumborigin)
+       (translate [-29 -40 -13])
+       ))
+(defn thumb-ml-place [shape]
+  (->> shape
+       (rotate (deg2rad   6) [1 0 0])
+       (rotate (deg2rad -34) [0 1 0])
+       (rotate (deg2rad  40) [0 0 1])
+       (translate thumborigin)
+       (translate [-51 -25 -12])))
+(defn thumb-br-place [shape]
+  (->> shape
+       (rotate (deg2rad -16) [1 0 0])
+       (rotate (deg2rad -33) [0 1 0])
+       (rotate (deg2rad  54) [0 0 1])
+       (translate thumborigin)
+       (translate [-37.8 -55.3 -25.3])
+       ))
+(defn thumb-bl-place [shape]
+  (->> shape
+       (rotate (deg2rad  -4) [1 0 0])
+       (rotate (deg2rad -35) [0 1 0])
+       (rotate (deg2rad  52) [0 0 1])
+       (translate thumborigin)
+       (translate [-56.3 -43.3 -23.5])
+       ))
+
+(defn thumb-1x-layout [shape]
+  (union
+   (thumb-mr-place shape)
+   (thumb-ml-place shape)
+   (thumb-br-place shape)
+   (thumb-bl-place shape)))
+
+(defn thumb-15x-layout [shape]
+  (union
+   (thumb-tr-place shape)
+   (thumb-tl-place shape)))
+
+(def larger-plate
+  (let [plate-height (/ (- sa-double-length mount-height) 3)
         top-plate (->> (cube mount-width plate-height web-thickness)
                        (translate [0 (/ (+ plate-height mount-height) 2)
                                    (- plate-thickness (/ web-thickness 2))]))
-        stabilizer-cutout (union (->> (cube 14.2 3.5 web-thickness)
-                                      (translate [0.5 12 (- plate-thickness (/ web-thickness 2))])
-                                      (color [1 0 0 1/2]))
-                                 (->> (cube 16 3.5 web-thickness)
-                                      (translate [0.5 12 (- plate-thickness (/ web-thickness 2) 1.4)])
-                                      (color [1 0 0 1/2])))
-        top-plate (difference top-plate stabilizer-cutout)]
+        ]
     (union top-plate (mirror [0 1 0] top-plate))))

 (def thumbcaps
   (union
-   (thumb-2x-column (sa-cap 2))
-   (thumb-place 1 -1/2 (sa-cap 2))
-   (thumb-place 1 1 (sa-cap 1))
-   (thumb-1x-column (sa-cap 1))))
+   (thumb-1x-layout (sa-cap 1))
+   (thumb-15x-layout (rotate (/ π 2) [0 0 1] (sa-cap 1.5)))))
+
+
+(def thumb
+  (union
+   (thumb-1x-layout single-plate)
+   (thumb-15x-layout single-plate)
+   (thumb-15x-layout larger-plate)
+   ))
+
+(def thumb-post-tr (translate [(- (/ mount-width 2) post-adj)  (- (/ mount-height  1.15) post-adj) 0] web-post))
+(def thumb-post-tl (translate [(+ (/ mount-width -2) post-adj) (- (/ mount-height  1.15) post-adj) 0] web-post))
+(def thumb-post-bl (translate [(+ (/ mount-width -2) post-adj) (+ (/ mount-height -1.15) post-adj) 0] web-post))
+(def thumb-post-br (translate [(- (/ mount-width 2) post-adj)  (+ (/ mount-height -1.15) post-adj) 0] web-post))

 (def thumb-connectors
   (union
-   (apply union
-          (concat
-           (for [column [2] row [1]]
-             (triangle-hulls (thumb-place column row web-post-br)
-                             (thumb-place column row web-post-tr)
-                             (thumb-place (dec column) row web-post-bl)
-                             (thumb-place (dec column) row web-post-tl)))
-           (for [column [2] row [0 1]]
-             (triangle-hulls
-              (thumb-place column row web-post-bl)
-              (thumb-place column row web-post-br)
-              (thumb-place column (dec row) web-post-tl)
-              (thumb-place column (dec row) web-post-tr)))))
-   (let [plate-height (/ (- sa-double-length mount-height) 2)
-         thumb-tl (->> web-post-tl
-                       (translate [0 plate-height 0]))
-         thumb-bl (->> web-post-bl
-                       (translate [0 (- plate-height) 0]))
-         thumb-tr (->> web-post-tr
-                       (translate [0 plate-height 0]))
-         thumb-br (->> web-post-br
-                       (translate [0 (- plate-height) 0]))]
-     (union
-
-      ;;Connecting the two doubles
-      (triangle-hulls (thumb-place 0 -1/2 thumb-tl)
-                      (thumb-place 0 -1/2 thumb-bl)
-                      (thumb-place 1 -1/2 thumb-tr)
-                      (thumb-place 1 -1/2 thumb-br))
-
-      ;;Connecting the double to the one above it
-      (triangle-hulls (thumb-place 1 -1/2 thumb-tr)
-                      (thumb-place 1 -1/2 thumb-tl)
-                      (thumb-place 1 1 web-post-br)
-                      (thumb-place 1 1 web-post-bl))
-
-      ;;Connecting the 4 with the double in the bottom left
-      (triangle-hulls (thumb-place 1 1 web-post-bl)
-                      (thumb-place 1 -1/2 thumb-tl)
-                      (thumb-place 2 1 web-post-br)
-                      (thumb-place 2 0 web-post-tr))
-
-      ;;Connecting the two singles with the middle double
-      (hull (thumb-place 1 -1/2 thumb-tl)
-            (thumb-place 1 -1/2 thumb-bl)
-            (thumb-place 2 0 web-post-br)
-            (thumb-place 2 -1 web-post-tr))
-      (hull (thumb-place 1 -1/2 thumb-tl)
-            (thumb-place 2 0 web-post-tr)
-            (thumb-place 2 0 web-post-br))
-      (hull (thumb-place 1 -1/2 thumb-bl)
-            (thumb-place 2 -1 web-post-tr)
-            (thumb-place 2 -1 web-post-br))
-
-      ;;Connecting the thumb to everything
-      (triangle-hulls (thumb-place 0 -1/2 thumb-br)
-                      (key-place 1 4 web-post-bl)
-                      (thumb-place 0 -1/2 thumb-tr)
-                      (key-place 1 4 web-post-tl)
-                      (key-place 1 3 web-post-bl)
-                      (thumb-place 0 -1/2 thumb-tr)
-                      (key-place 0 3 web-post-br)
-                      (key-place 0 3 web-post-bl)
-                      (thumb-place 0 -1/2 thumb-tr)
-                      (thumb-place 0 -1/2 thumb-tl)
-                      (key-place 0 3 web-post-bl)
-                      (thumb-place 1 -1/2 thumb-tr)
-                      (thumb-place 1 1 web-post-br)
-                      (key-place 0 3 web-post-bl)
-                      (key-place 0 3 web-post-tl)
-                      (thumb-place 1 1 web-post-br)
-                      (thumb-place 1 1 web-post-tr))
-      (hull (thumb-place 0 -1/2 web-post-tr)
-            (thumb-place 0 -1/2 thumb-tr)
-            (key-place 1 4 web-post-bl)
-            (key-place 1 4 web-post-tl))))))
-
-(def thumb
-  (union
-   thumb-connectors
-   (thumb-layout (rotate (/ π 2) [0 0 1] single-plate))
-   (thumb-place 0 -1/2 double-plates)
-   (thumb-place 1 -1/2 double-plates)))
+      (triangle-hulls    ; top two
+             (thumb-tl-place thumb-post-tr)
+             (thumb-tl-place thumb-post-br)
+             (thumb-tr-place thumb-post-tl)
+             (thumb-tr-place thumb-post-bl))
+      (triangle-hulls    ; bottom two on the right
+             (thumb-br-place web-post-tr)
+             (thumb-br-place web-post-br)
+             (thumb-mr-place web-post-tl)
+             (thumb-mr-place web-post-bl))
+      (triangle-hulls    ; bottom two on the left
+             (thumb-bl-place web-post-tr)
+             (thumb-bl-place web-post-br)
+             (thumb-ml-place web-post-tl)
+             (thumb-ml-place web-post-bl))
+      (triangle-hulls    ; centers of the bottom four
+             (thumb-br-place web-post-tl)
+             (thumb-bl-place web-post-bl)
+             (thumb-br-place web-post-tr)
+             (thumb-bl-place web-post-br)
+             (thumb-mr-place web-post-tl)
+             (thumb-ml-place web-post-bl)
+             (thumb-mr-place web-post-tr)
+             (thumb-ml-place web-post-br))
+      (triangle-hulls    ; top two to the middle two, starting on the left
+             (thumb-tl-place thumb-post-tl)
+             (thumb-ml-place web-post-tr)
+             (thumb-tl-place thumb-post-bl)
+             (thumb-ml-place web-post-br)
+             (thumb-tl-place thumb-post-br)
+             (thumb-mr-place web-post-tr)
+             (thumb-tr-place thumb-post-bl)
+             (thumb-mr-place web-post-br)
+             (thumb-tr-place thumb-post-br))
+      (triangle-hulls    ; top two to the main keyboard, starting on the left
+             (thumb-tl-place thumb-post-tl)
+             (key-place 0 cornerrow web-post-bl)
+             (thumb-tl-place thumb-post-tr)
+             (key-place 0 cornerrow web-post-br)
+             (thumb-tr-place thumb-post-tl)
+             (key-place 1 cornerrow web-post-bl)
+             (thumb-tr-place thumb-post-tr)
+             (key-place 1 cornerrow web-post-br)
+             (key-place 2 lastrow web-post-tl)
+             (key-place 2 lastrow web-post-bl)
+             (thumb-tr-place thumb-post-tr)
+             (key-place 2 lastrow web-post-bl)
+             (thumb-tr-place thumb-post-br)
+             (key-place 2 lastrow web-post-br)
+             (key-place 3 lastrow web-post-bl)
+             (key-place 2 lastrow web-post-tr)
+             (key-place 3 lastrow web-post-tl)
+             (key-place 3 cornerrow web-post-bl)
+             (key-place 3 lastrow web-post-tr)
+             (key-place 3 cornerrow web-post-br)
+             (key-place 4 cornerrow web-post-bl))
+      (triangle-hulls
+             (key-place 1 cornerrow web-post-br)
+             (key-place 2 lastrow web-post-tl)
+             (key-place 2 cornerrow web-post-bl)
+             (key-place 2 lastrow web-post-tr)
+             (key-place 2 cornerrow web-post-br)
+             (key-place 3 cornerrow web-post-bl)
+             )
+      (triangle-hulls
+             (key-place 3 lastrow web-post-tr)
+             (key-place 3 lastrow web-post-br)
+             (key-place 3 lastrow web-post-tr)
+             (key-place 4 cornerrow web-post-bl))
+  ))

 ;;;;;;;;;;
 ;; Case ;;
 ;;;;;;;;;;
-
-;; In column units
-(def right-wall-column (+ (last columns) 0.55))
-(def left-wall-column (- (first columns) 1/2))
-(def thumb-back-y 0.93)
-(def thumb-right-wall (- -1/2 0.05))
-(def thumb-front-row (+ -1 0.07))
-(def thumb-left-wall-column (+ 5/2 0.05))
-(def back-y 0.02)
-
-(defn range-inclusive [start end step]
-  (concat (range start end step) [end]))
-
-(def wall-step 0.2)
-(def wall-sphere-n 20) ;;Sphere resolution, lower for faster renders
-
-(defn wall-sphere-at [coords]
-  (->> (sphere 1)
-       (translate coords)
-       (with-fn wall-sphere-n)))
-
-(defn scale-to-range [start end x]
-  (+ start (* (- end start) x)))
-
-(defn wall-sphere-bottom [front-to-back-scale]
-  (wall-sphere-at [0
-                   (scale-to-range
-                    (+ (/ mount-height -2) -3.5)
-                    (+ (/ mount-height 2) 5.0)
-                    front-to-back-scale)
-                   -6]))
-
-(defn wall-sphere-top [front-to-back-scale]
-  (wall-sphere-at [0
-                   (scale-to-range
-                    (+ (/ mount-height -2) -3.5)
-                    (+ (/ mount-height 2) 3.5)
-                    front-to-back-scale)
-                   10]))
-
-(def wall-sphere-top-back (wall-sphere-top 1))
-(def wall-sphere-bottom-back (wall-sphere-bottom 1))
-(def wall-sphere-bottom-front (wall-sphere-bottom 0))
-(def wall-sphere-top-front (wall-sphere-top 0))
-
-(defn top-case-cover [place-fn sphere
-                 x-start x-end
-                 y-start y-end
-                 step]
-  (apply union
-         (for [x (range-inclusive x-start (- x-end step) step)
-               y (range-inclusive y-start (- y-end step) step)]
-           (hull (place-fn x y sphere)
-                 (place-fn (+ x step) y sphere)
-                 (place-fn x (+ y step) sphere)
-                 (place-fn (+ x step) (+ y step) sphere)))))
-
-(def front-wall
-  (let [step wall-step ;;0.1
-        wall-step 0.05 ;;0.05
-        place case-place
-        top-cover (fn [x-start x-end y-start y-end]
-                    (top-case-cover place wall-sphere-top-front
-                                    x-start x-end y-start y-end
-                                    wall-step))]
-    (union
-     (apply union
-            (for [x (range-inclusive 0.7 (- right-wall-column step) step)]
-              (hull (place x 4 wall-sphere-top-front)
-                    (place (+ x step) 4 wall-sphere-top-front)
-                    (place x 4 wall-sphere-bottom-front)
-                    (place (+ x step) 4 wall-sphere-bottom-front))))
-     (apply union
-            (for [x (range-inclusive 0.5 0.7 0.01)]
-              (hull (place x 4 wall-sphere-top-front)
-                    (place (+ x step) 4 wall-sphere-top-front)
-                    (place 0.7 4 wall-sphere-bottom-front))))
-     (top-cover 0.5 1.7 3.6 4)
-     (top-cover 1.59 2.41 3.35 4) ;; was 3.32
-     (top-cover 2.39 3.41 3.6 4)
-     (apply union
-            (for [x (range 2 5)]
-              (union
-               (hull (place (- x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                     (place (+ x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                     (key-place x 4 web-post-bl)
-                     (key-place x 4 web-post-br))
-               (hull (place (- x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                     (key-place x 4 web-post-bl)
-                     (key-place (- x 1) 4 web-post-br)))))
-     (hull (place right-wall-column 4 (translate [0 1 1] wall-sphere-bottom-front))
-           (place (- right-wall-column 1) 4 (translate [0 1 1] wall-sphere-bottom-front))
-           (key-place 5 4 web-post-bl)
-           (key-place 5 4 web-post-br))
-     (hull (place (+ 4 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-           (place (- right-wall-column 1) 4 (translate [0 1 1] wall-sphere-bottom-front))
-           (key-place 4 4 web-post-br)
-           (key-place 5 4 web-post-bl))
-     (hull (place 0.7 4 (translate [0 1 1] wall-sphere-bottom-front))
-           (place 1.7 4 (translate [0 1 1] wall-sphere-bottom-front))
-           (key-place 1 4 web-post-bl)
-           (key-place 1 4 web-post-br)))))
-
-(def back-wall
-  (let [step wall-step
-        wall-sphere-top-backtep 0.05
-        place case-place
-        front-top-cover (fn [x-start x-end y-start y-end]
-                          (apply union
-                                 (for [x (range-inclusive x-start (- x-end wall-sphere-top-backtep) wall-sphere-top-backtep)
-                                       y (range-inclusive y-start (- y-end wall-sphere-top-backtep) wall-sphere-top-backtep)]
-                                   (hull (place x y wall-sphere-top-back)
-                                         (place (+ x wall-sphere-top-backtep) y wall-sphere-top-back)
-                                         (place x (+ y wall-sphere-top-backtep) wall-sphere-top-back)
-                                         (place (+ x wall-sphere-top-backtep) (+ y wall-sphere-top-backtep) wall-sphere-top-back)))))]
-    (union
-     (apply union
-            (for [x (range-inclusive left-wall-column (- right-wall-column step) step)]
-              (hull (place x back-y wall-sphere-top-back)
-                    (place (+ x step) back-y wall-sphere-top-back)
-                    (place x back-y wall-sphere-bottom-back)
-                    (place (+ x step) back-y wall-sphere-bottom-back))))
-     (front-top-cover 1.56 2.44 back-y 0.1)
-     (front-top-cover 3.56 4.44 back-y 0.13)
-     (front-top-cover 4.3 right-wall-column back-y 0.13)
-
-
-     (hull (place left-wall-column 0 (translate [1 -1 1] wall-sphere-bottom-back))
-           (place (+ left-wall-column 1) 0  (translate [0 -1 1] wall-sphere-bottom-back))
-           (key-place 0 0 web-post-tl)
-           (key-place 0 0 web-post-tr))
-
-     (hull (place 5 0 (translate [0 -1 1] wall-sphere-bottom-back))
-           (place right-wall-column 0 (translate [0 -1 1] wall-sphere-bottom-back))
-           (key-place 5 0 web-post-tl)
-           (key-place 5 0 web-post-tr))
-
-     (apply union
-            (for [x (range 1 5)]
-              (union
-               (hull (place (- x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
-                     (place (+ x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
-                     (key-place x 0 web-post-tl)
-                     (key-place x 0 web-post-tr))
-               (hull (place (- x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
-                     (key-place x 0 web-post-tl)
-                     (key-place (- x 1) 0 web-post-tr)))))
-     (hull (place (- 5 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
-           (place 5 0 (translate [0 -1 1] wall-sphere-bottom-back))
-           (key-place 4 0 web-post-tr)
-           (key-place 5 0 web-post-tl)))))
-
-(def right-wall
-  (let [place case-place]
-    (union
-     (apply union
-            (map (partial apply hull)
-                 (partition 2 1
-                            (for [scale (range-inclusive 0 1 0.01)]
-                              (let [x (scale-to-range 4 0.02 scale)]
-                                (hull (place right-wall-column x (wall-sphere-top scale))
-                                      (place right-wall-column x (wall-sphere-bottom scale))))))))
-
-          (apply union
-            (concat
-             (for [x (range 0 5)]
-               (union
-                (hull (place right-wall-column x (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                      (key-place 5 x web-post-br)
-                      (key-place 5 x web-post-tr))))
-             (for [x (range 0 4)]
-               (union
-                (hull (place right-wall-column x (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                      (place right-wall-column (inc x) (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                      (key-place 5 x web-post-br)
-                      (key-place 5 (inc x) web-post-tr))))
-             [(union
-               (hull (place right-wall-column 0 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                     (place right-wall-column 0.02 (translate [-1 -1 1] (wall-sphere-bottom 1)))
-                     (key-place 5 0 web-post-tr))
-               (hull (place right-wall-column 4 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                     (place right-wall-column 4 (translate [-1 1 1] (wall-sphere-bottom 0)))
-                     (key-place 5 4 web-post-br)))])))))
-
-(def left-wall
-  (let [place case-place]
-    (union
-     (apply union
-            (for [x (range-inclusive -1 (- 1.6666 wall-step) wall-step)]
-              (hull (place left-wall-column x wall-sphere-top-front)
-                    (place left-wall-column (+ x wall-step) wall-sphere-top-front)
-                    (place left-wall-column x wall-sphere-bottom-front)
-                    (place left-wall-column (+ x wall-step) wall-sphere-bottom-front))))
-     (hull (place left-wall-column -1 wall-sphere-top-front)
-           (place left-wall-column -1 wall-sphere-bottom-front)
-           (place left-wall-column 0.02 wall-sphere-top-back)
-           (place left-wall-column 0.02 wall-sphere-bottom-back))
-     (hull (place left-wall-column 0 (translate [1 -1 1] wall-sphere-bottom-back))
-           (place left-wall-column 1 (translate [1 0 1] wall-sphere-bottom-back))
-           (key-place 0 0 web-post-tl)
-           (key-place 0 0 web-post-bl))
-     (hull (place left-wall-column 1 (translate [1 0 1] wall-sphere-bottom-back))
-           (place left-wall-column 2 (translate [1 0 1] wall-sphere-bottom-back))
-           (key-place 0 0 web-post-bl)
-           (key-place 0 1 web-post-bl))
-     (hull (place left-wall-column 2 (translate [1 0 1] wall-sphere-bottom-back))
-           (place left-wall-column 1.6666  (translate [1 0 1] wall-sphere-bottom-front))
-           (key-place 0 1 web-post-bl)
-           (key-place 0 2 web-post-bl))
-     (hull (place left-wall-column 1.6666  (translate [1 0 1] wall-sphere-bottom-front))
-           (key-place 0 2 web-post-bl)
-           (key-place 0 3 web-post-tl))
-     (hull (place left-wall-column 1.6666  (translate [1 0 1] wall-sphere-bottom-front))
-           (thumb-place 1 1 web-post-tr)
-           (key-place 0 3 web-post-tl))
-     (hull (place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
-           (thumb-place 1 1 web-post-tr)
-           (thumb-place 1/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))))))
-
-(def thumb-back-wall
-  (let [step wall-step
-        top-step 0.05
-        front-top-cover (fn [x-start x-end y-start y-end]
-                          (apply union
-                                 (for [x (range-inclusive x-start (- x-end top-step) top-step)
-                                       y (range-inclusive y-start (- y-end top-step) top-step)]
-                                   (hull (thumb-place x y wall-sphere-top-back)
-                                         (thumb-place (+ x top-step) y wall-sphere-top-back)
-                                         (thumb-place x (+ y top-step) wall-sphere-top-back)
-                                         (thumb-place (+ x top-step) (+ y top-step) wall-sphere-top-back)))))
-        back-y thumb-back-y]
-    (union
-     (apply union
-            (for [x (range-inclusive 1/2 (- (+ 5/2 0.05) step) step)]
-              (hull (thumb-place x back-y wall-sphere-top-back)
-                    (thumb-place (+ x step) back-y wall-sphere-top-back)
-                    (thumb-place x back-y wall-sphere-bottom-back)
-                    (thumb-place (+ x step) back-y wall-sphere-bottom-back))))
-     (hull (thumb-place 1/2 back-y wall-sphere-top-back)
-           (thumb-place 1/2 back-y wall-sphere-bottom-back)
-           (case-place left-wall-column 1.6666 wall-sphere-top-front))
-     (hull (thumb-place 1/2 back-y wall-sphere-bottom-back)
-           (case-place left-wall-column 1.6666 wall-sphere-top-front)
-           (case-place left-wall-column 1.6666 wall-sphere-bottom-front))
-     (hull
-      (thumb-place 1/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
-      (thumb-place 1 1 web-post-tr)
-      (thumb-place 3/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
-      (thumb-place 1 1 web-post-tl))
-     (hull
-      (thumb-place (+ 5/2 0.05) thumb-back-y (translate [1 -1 1] wall-sphere-bottom-back))
-      (thumb-place 3/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
-      (thumb-place 1 1 web-post-tl)
-      (thumb-place 2 1 web-post-tl)))))
-
-(def thumb-left-wall
-  (let [step wall-step
-        place thumb-place]
-    (union
-     (apply union
-            (for [x (range-inclusive (+ -1 0.07) (- 1.95 step) step)]
-              (hull (place thumb-left-wall-column x wall-sphere-top-front)
-                    (place thumb-left-wall-column (+ x step) wall-sphere-top-front)
-                    (place thumb-left-wall-column x wall-sphere-bottom-front)
-                    (place thumb-left-wall-column (+ x step) wall-sphere-bottom-front))))
-     (hull (place thumb-left-wall-column 1.95 wall-sphere-top-front)
-           (place thumb-left-wall-column 1.95 wall-sphere-bottom-front)
-           (place thumb-left-wall-column thumb-back-y wall-sphere-top-back)
-           (place thumb-left-wall-column thumb-back-y wall-sphere-bottom-back))
-
-     (hull
-      (thumb-place thumb-left-wall-column thumb-back-y (translate [1 -1 1] wall-sphere-bottom-back))
-      (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
-      (thumb-place 2 1 web-post-tl)
-      (thumb-place 2 1 web-post-bl))
-     (hull
-      (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
-      (thumb-place 2 0 web-post-tl)
-      (thumb-place 2 1 web-post-bl))
-     (hull
-      (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
-      (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
-      (thumb-place 2 0 web-post-tl)
-      (thumb-place 2 0 web-post-bl))
-     (hull
-      (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
-      (thumb-place 2 -1 web-post-tl)
-      (thumb-place 2 0 web-post-bl))
-     (hull
-      (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
-      (thumb-place thumb-left-wall-column (+ -1 0.07) (translate [1 1 1] wall-sphere-bottom-front))
-      (thumb-place 2 -1 web-post-tl)
-      (thumb-place 2 -1 web-post-bl)))))
-
-(def thumb-front-wall
-  (let [step wall-step ;;0.1
-        wall-sphere-top-fronttep 0.05 ;;0.05
-        place thumb-place
-        plate-height (/ (- sa-double-length mount-height) 2)
-        thumb-tl (->> web-post-tl
-                      (translate [0 plate-height 0]))
-        thumb-bl (->> web-post-bl
-                      (translate [0 (- plate-height) 0]))
-        thumb-tr (->> web-post-tr
-                      (translate [-0 plate-height 0]))
-        thumb-br (->> web-post-br
-                      (translate [-0 (- plate-height) 0]))]
-    (union
-     (apply union
-            (for [x (range-inclusive thumb-right-wall (- (+ 5/2 0.05) step) step)]
-              (hull (place x thumb-front-row wall-sphere-top-front)
-                    (place (+ x step) thumb-front-row wall-sphere-top-front)
-                    (place x thumb-front-row wall-sphere-bottom-front)
-                    (place (+ x step) thumb-front-row wall-sphere-bottom-front))))
-
-     (hull (place thumb-right-wall thumb-front-row wall-sphere-top-front)
-           (place thumb-right-wall thumb-front-row wall-sphere-bottom-front)
-           (case-place 0.5 4 wall-sphere-top-front))
-     (hull (place thumb-right-wall thumb-front-row wall-sphere-bottom-front)
-           (case-place 0.5 4 wall-sphere-top-front)
-           (case-place 0.7 4 wall-sphere-bottom-front))
-
-     (hull (place thumb-right-wall thumb-front-row wall-sphere-bottom-front)
-           (key-place 1 4 web-post-bl)
-           (place 0 -1/2 thumb-br)
-           (place 0 -1/2 web-post-br)
-           (case-place 0.7 4 wall-sphere-bottom-front))
-
-     (hull (place (+ 5/2 0.05) thumb-front-row (translate [1 1 1] wall-sphere-bottom-front))
-           (place (+ 3/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-           (place 2 -1 web-post-bl)
-           (place 2 -1 web-post-br))
-
-     (hull (place thumb-right-wall thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-           (place (+ 1/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-           (place 0 -1/2 thumb-bl)
-           (place 0 -1/2 thumb-br))
-     (hull (place (+ 1/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-           (place (+ 3/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-           (place 0 -1/2 thumb-bl)
-           (place 1 -1/2 thumb-bl)
-           (place 1 -1/2 thumb-br)
-           (place 2 -1 web-post-br)))))
-
-(def new-case
-  (union front-wall
-         right-wall
-         back-wall
-         left-wall
-         thumb-back-wall
-         thumb-left-wall
-         thumb-front-wall))
-
-;;;;;;;;;;;;
-;; Bottom ;;
-;;;;;;;;;;;;
-

 (defn bottom [height p]
   (->> (project p)
        (extrude-linear {:height height :twist 0 :convexity 0})
        (translate [0 0 (/ height 2)])))

-(defn bottom-hull [p]
-  (hull p (bottom 1 p)))
-
-
-(def bottom-key-guard (->> (cube mount-width mount-height web-thickness)
-                           (translate [0 0 (+ (- (/ web-thickness 2)) -4.5)])))
-(def bottom-front-key-guard (->> (cube mount-width (/ mount-height 2) web-thickness)
-                                 (translate [0 (/ mount-height 4) (+ (- (/ web-thickness 2)) -4.5)])))
-
-(def bottom-plate
-  (union
-   (apply union
-          (for [column columns
-                row (drop-last rows) ;;
-                :when (or (not= column 0)
-                          (not= row 4))]
-            (->> bottom-key-guard
-                 (key-place column row))))
-   (thumb-layout (rotate (/ π 2) [0 0 1] bottom-key-guard))
-   (apply union
-          (for [column columns
-                row [(last rows)] ;;
-                :when (or (not= column 0)
-                          (not= row 4))]
-            (->> bottom-front-key-guard
-                 (key-place column row))))
-   (let [shift #(translate [0 0 (+ (- web-thickness) -5)] %)
-         web-post-tl (shift web-post-tl)
-         web-post-tr (shift web-post-tr)
-         web-post-br (shift web-post-br)
-         web-post-bl (shift web-post-bl)
-         half-shift-correction #(translate [0 (/ mount-height 2) 0] %)
-         half-post-br (half-shift-correction web-post-br)
-         half-post-bl (half-shift-correction web-post-bl)
-         row-connections (concat
-                          (for [column (drop-last columns)
-                                row (drop-last rows)
-                                :when (or (not= column 0)
-                                          (not= row 4))]
-                            (triangle-hulls
-                             (key-place (inc column) row web-post-tl)
-                             (key-place column row web-post-tr)
-                             (key-place (inc column) row web-post-bl)
-                             (key-place column row web-post-br)))
-                          (for [column (drop-last columns)
-                                row [(last rows)]
-                                :when (or (not= column 0)
-                                          (not= row 4))]
-                            (triangle-hulls
-                             (key-place (inc column) row web-post-tl)
-                             (key-place column row web-post-tr)
-                             (key-place (inc column) row half-post-bl)
-                             (key-place column row half-post-br))))
-         column-connections (for [column columns
-                                  row (drop-last rows)
-                                  :when (or (not= column 0)
-                                            (not= row 3))]
-                              (triangle-hulls
-                               (key-place column row web-post-bl)
-                               (key-place column row web-post-br)
-                               (key-place column (inc row) web-post-tl)
-                               (key-place column (inc row) web-post-tr)))
-         diagonal-connections (for [column (drop-last columns)
-                                    row (drop-last rows)
-                                    :when (or (not= column 0)
-                                              (not= row 3))]
-                                (triangle-hulls
-                                 (key-place column row web-post-br)
-                                 (key-place column (inc row) web-post-tr)
-                                 (key-place (inc column) row web-post-bl)
-                                 (key-place (inc column) (inc row) web-post-tl)))
-         main-keys-bottom (concat row-connections
-                                  column-connections
-                                  diagonal-connections)
-         front-wall (concat
-                     (for [x (range 2 5)]
-                       (union
-                        (hull (case-place (- x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                              (case-place (+ x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                              (key-place x 4 half-post-bl)
-                              (key-place x 4 half-post-br))
-                        (hull (case-place (- x 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                              (key-place x 4 half-post-bl)
-                              (key-place (- x 1) 4 half-post-br))))
-                     [(hull (case-place right-wall-column 4 (translate [0 1 1] wall-sphere-bottom-front))
-                            (case-place (- right-wall-column 1) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                            (key-place 5 4 half-post-bl)
-                            (key-place 5 4 half-post-br))
-                      (hull (case-place (+ 4 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                            (case-place (- right-wall-column 1) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                            (key-place 4 4 half-post-br)
-                            (key-place 5 4 half-post-bl))])
-         right-wall (concat
-                     (for [x (range 0 4)]
-                       (hull (case-place right-wall-column x (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                             (key-place 5 x web-post-br)
-                             (key-place 5 x web-post-tr)))
-                     (for [x (range 0 4)]
-                       (hull (case-place right-wall-column x (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                             (case-place right-wall-column (inc x) (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                             (key-place 5 x web-post-br)
-                             (key-place 5 (inc x) web-post-tr)))
-                     [(union
-                       (hull (case-place right-wall-column 0 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                             (case-place right-wall-column 0.02 (translate [-1 -1 1] (wall-sphere-bottom 1)))
-                             (key-place 5 0 web-post-tr)
-                             )
-                       (hull (case-place right-wall-column 4 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                             (case-place right-wall-column 4 (translate [0 1 1] (wall-sphere-bottom 0)))
-                             (key-place 5 4 half-post-br)
-                             )
-                       (hull (case-place right-wall-column 4 (translate [-1 0 1] (wall-sphere-bottom 1/2)))
-                             (key-place 5 4 half-post-br)
-                             (key-place 5 4 web-post-tr)))])
-         back-wall (concat
-                    (for [x (range 1 6)]
-                      (union
-                       (hull (case-place (- x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
-                             (case-place (+ x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
-                             (key-place x 0 web-post-tl)
-                             (key-place x 0 web-post-tr))
-                       (hull (case-place (- x 1/2) 0 (translate [0 -1 1] wall-sphere-bottom-back))
-                             (key-place x 0 web-post-tl)
-                             (key-place (- x 1) 0 web-post-tr))))
-                    [(hull (case-place left-wall-column 0 (translate [1 -1 1] wall-sphere-bottom-back))
-                           (case-place (+ left-wall-column 1) 0  (translate [0 -1 1] wall-sphere-bottom-back))
-                           (key-place 0 0 web-post-tl)
-                           (key-place 0 0 web-post-tr))])
-         left-wall (let [place case-place]
-               [(hull (place left-wall-column 0 (translate [1 -1 1] wall-sphere-bottom-back))
-                      (place left-wall-column 1 (translate [1 0 1] wall-sphere-bottom-back))
-                      (key-place 0 0 web-post-tl)
-                      (key-place 0 0 web-post-bl))
-                (hull (place left-wall-column 1 (translate [1 0 1] wall-sphere-bottom-back))
-                      (place left-wall-column 2 (translate [1 0 1] wall-sphere-bottom-back))
-                      (key-place 0 0 web-post-bl)
-                      (key-place 0 1 web-post-bl))
-                (hull (place left-wall-column 2 (translate [1 0 1] wall-sphere-bottom-back))
-                      (place left-wall-column 1.6666  (translate [1 0 1] wall-sphere-bottom-front))
-                      (key-place 0 1 web-post-bl)
-                      (key-place 0 2 web-post-bl))
-                (hull (place left-wall-column 1.6666  (translate [1 0 1] wall-sphere-bottom-front))
-                      (key-place 0 2 web-post-bl)
-                      (key-place 0 3 web-post-tl))])
-         thumbs [(hull (thumb-place 0 -1/2 web-post-bl)
-                       (thumb-place 0 -1/2 web-post-tl)
-                       (thumb-place 1 -1/2 web-post-tr)
-                       (thumb-place 1 -1/2 web-post-br))
-                 (hull (thumb-place 1 -1/2 web-post-tr)
-                       (thumb-place 1 -1/2 web-post-tl)
-                       (thumb-place 1 1 web-post-bl)
-                       (thumb-place 1 1 web-post-br))
-                 (hull (thumb-place 2 -1 web-post-tr)
-                       (thumb-place 2 -1 web-post-tl)
-                       (thumb-place 2 0 web-post-bl)
-                       (thumb-place 2 0 web-post-br))
-                 (hull (thumb-place 2 0 web-post-tr)
-                       (thumb-place 2 0 web-post-tl)
-                       (thumb-place 2 1 web-post-bl)
-                       (thumb-place 2 1 web-post-br))
-                 (triangle-hulls (thumb-place 2 1 web-post-tr)
-                                 (thumb-place 1 1 web-post-tl)
-                                 (thumb-place 2 1 web-post-br)
-                                 (thumb-place 1 1 web-post-bl)
-                                 (thumb-place 2 0 web-post-tr)
-                                 (thumb-place 1 -1/2 web-post-tl)
-                                 (thumb-place 2 0 web-post-br)
-                                 (thumb-place 1 -1/2 web-post-bl)
-                                 (thumb-place 2 -1 web-post-tr)
-                                 (thumb-place 2 -1 web-post-br))
-                 (hull (thumb-place 2 -1 web-post-br)
-                       (thumb-place 1 -1/2 web-post-bl)
-                       (thumb-place 1 -1 web-post-bl))
-                 (hull (thumb-place 1 -1/2 web-post-bl)
-                       (thumb-place 1 -1 web-post-bl)
-                       (thumb-place 1 -1/2 web-post-br)
-                       (thumb-place 1 -1 web-post-br))
-                 (hull (thumb-place 0 -1/2 web-post-bl)
-                       (thumb-place 0 -1 web-post-bl)
-                       (thumb-place 0 -1/2 web-post-br)
-                       (thumb-place 0 -1 web-post-br))
-                 (hull (thumb-place 0 -1/2 web-post-bl)
-                       (thumb-place 0 -1 web-post-bl)
-                       (thumb-place 1 -1/2 web-post-br)
-                       (thumb-place 1 -1 web-post-br))]
-         thumb-back-wall [(hull
-                           (thumb-place 1/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
-                           (thumb-place 1 1 web-post-tr)
-                           (thumb-place 3/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
-                           (thumb-place 1 1 web-post-tl))
-
-                          (hull
-                           (thumb-place (+ 5/2 0.05) thumb-back-y (translate [1 -1 1] wall-sphere-bottom-back))
-                           (thumb-place 3/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
-                           (thumb-place 1 1 web-post-tl)
-                           (thumb-place 2 1 web-post-tl))
-                          (hull
-                           (thumb-place 1/2 thumb-back-y (translate [0 -1 1] wall-sphere-bottom-back))
-                           (case-place left-wall-column 1.6666 (translate [1 0 1] wall-sphere-bottom-front))
-                           (key-place 0 3 web-post-tl)
-                           (thumb-place 1 1 web-post-tr))
-                          ]
-         thumb-left-wall [(hull
-                           (thumb-place thumb-left-wall-column thumb-back-y (translate [1 -1 1] wall-sphere-bottom-back))
-                           (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
-                           (thumb-place 2 1 web-post-tl)
-                           (thumb-place 2 1 web-post-bl))
-                          (hull
-                           (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
-                           (thumb-place 2 0 web-post-tl)
-                           (thumb-place 2 1 web-post-bl))
-                          (hull
-                           (thumb-place thumb-left-wall-column 0 (translate [1 0 1] wall-sphere-bottom-back))
-                           (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
-                           (thumb-place 2 0 web-post-tl)
-                           (thumb-place 2 0 web-post-bl))
-                          (hull
-                           (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
-                           (thumb-place 2 -1 web-post-tl)
-                           (thumb-place 2 0 web-post-bl))
-                          (hull
-                           (thumb-place thumb-left-wall-column -1 (translate [1 0 1] wall-sphere-bottom-back))
-                           (thumb-place thumb-left-wall-column (+ -1 0.07) (translate [1 1 1] wall-sphere-bottom-front))
-                           (thumb-place 2 -1 web-post-tl)
-                           (thumb-place 2 -1 web-post-bl))]
-         thumb-front-wall [(hull (thumb-place (+ 5/2 0.05) thumb-front-row (translate [1 1 1] wall-sphere-bottom-front))
-                                 (thumb-place (+ 3/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-                                 (thumb-place 2 -1 web-post-bl)
-                                 (thumb-place 2 -1 web-post-br))
-                           (hull (thumb-place (+ 1/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-                                 (thumb-place (+ 3/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-                                 (thumb-place 0 -1 web-post-bl)
-                                 (thumb-place 1 -1 web-post-bl)
-                                 (thumb-place 1 -1 web-post-br)
-                                 (thumb-place 2 -1 web-post-br))
-                           (hull (thumb-place thumb-right-wall thumb-front-row (translate [-1 1 1] wall-sphere-bottom-front))
-                                 (thumb-place (+ 1/2 0.05) thumb-front-row (translate [0 1 1] wall-sphere-bottom-front))
-                                 (thumb-place 0 -1 web-post-bl)
-                                 (thumb-place 0 -1 web-post-br))]
-         thumb-inside [(triangle-hulls
-                        (thumb-place 1 1 web-post-tr)
-                        (key-place 0 3 web-post-tl)
-                        (thumb-place 1 1 web-post-br)
-                        (key-place 0 3 web-post-bl)
-                        (thumb-place 1 -1/2 web-post-tr)
-                        (thumb-place 0 -1/2 web-post-tl)
-                        (key-place 0 3 web-post-bl)
-                        (thumb-place 0 -1/2 web-post-tr)
-                         (key-place 0 3 web-post-br)
-                         (key-place 1 3 web-post-bl)
-                         (thumb-place 0 -1/2 web-post-tr)
-                         (key-place 1 4 web-post-tl)
-                         (key-place 1 4 half-post-bl))
-
-                       (hull
-                        (thumb-place 0 -1/2 web-post-tr)
-                        (thumb-place 0 -1/2 web-post-br)
-                        (key-place 1 4 half-post-bl))
-
-                       (hull
-                        (key-place 1 4 half-post-bl)
-                        (key-place 1 4 half-post-br)
-                        (case-place (- 2 1/2) 4 (translate [0 1 1] wall-sphere-bottom-front))
-                        (case-place 0.7 4 (translate [0 1 1] wall-sphere-bottom-front)))
-
-                       (hull
-                        (thumb-place 0 -1 web-post-br)
-                        (thumb-place 0 -1/2 web-post-br)
-                        (thumb-place thumb-right-wall thumb-front-row (translate [-1 1 1] wall-sphere-bottom-front))
-                        (key-place 1 4 (translate [0 0 8.5] web-post-bl))
-                        (key-place 1 4 half-post-bl)
-                        )]
-         stands (let [bumper-diameter 9.6
-                      bumper-radius (/ bumper-diameter 2)
-                      stand-diameter (+ bumper-diameter 2)
-                      stand-radius (/ stand-diameter 2)
-                      stand-at #(difference (->> (sphere stand-radius)
-                                                 (translate [0 0 (+ (/ stand-radius -2) -4.5)])
-                                                 %
-                                                 (bottom-hull))
-                                            (->> (cube stand-diameter stand-diameter stand-radius)
-                                                 (translate [0 0 (/ stand-radius -2)])
-                                                 %)
-                                            (->> (sphere bumper-radius)
-                                                 (translate [0 0 (+ (/ stand-radius -2) -4.5)])
-                                                 %
-                                                 (bottom 1.5)))]
-                  [(stand-at #(key-place 0 1 %))
-                   (stand-at #(thumb-place 1 -1/2 %))
-                   (stand-at #(key-place 5 0 %))
-                   (stand-at #(key-place 5 3 %))])]
-     (apply union
-            (concat
-             main-keys-bottom
-             front-wall
-             right-wall
-             back-wall
-             left-wall
-             thumbs
-             thumb-back-wall
-             thumb-left-wall
-             thumb-front-wall
-             thumb-inside
-             stands)))))
-
-(def screw-hole (->> (cylinder 1.5 60)
-                     (translate [0 0 3/2])
-                     (with-fn wall-sphere-n)))
-
-(def screw-holes
-  (union
-   (key-place (+ 4 1/2) 1/2 screw-hole)
-   (key-place (+ 4 1/2) (+ 3 1/2) screw-hole)
-   (thumb-place 2 -1/2 screw-hole)))
-
-(defn circuit-cover [width length height]
-  (let [cover-sphere-radius 1
-        cover-sphere (->> (sphere cover-sphere-radius)
-                          (with-fn 20))
-        cover-sphere-z (+ (- height) (- cover-sphere-radius))
-        cover-sphere-x (+ (/ width 2) cover-sphere-radius)
-        cover-sphere-y (+ (/ length 2) (+ cover-sphere-radius))
-        cover-sphere-tl (->> cover-sphere
-                             (translate [(- cover-sphere-x) (- cover-sphere-y) cover-sphere-z])
-                             (key-place 1/2 3/2))
-        cover-sphere-tr (->> cover-sphere
-                             (translate [cover-sphere-x (- cover-sphere-y) cover-sphere-z])
-                             (key-place 1/2 3/2))
-        cover-sphere-br (->> cover-sphere
-                             (translate [cover-sphere-x cover-sphere-y cover-sphere-z])
-                             (key-place 1/2 3/2))
-        cover-sphere-bl (->> cover-sphere
-                             (translate [(- cover-sphere-x) cover-sphere-y cover-sphere-z])
-                             (key-place 1/2 3/2))
-
-        lower-to-bottom #(translate [0 0 (+ (- cover-sphere-radius) -5.5)] %)
-        bl (->> cover-sphere lower-to-bottom (key-place 0 1/2))
-        br (->> cover-sphere lower-to-bottom (key-place 1 1/2))
-        tl (->> cover-sphere lower-to-bottom (key-place 0 5/2))
-        tr (->> cover-sphere lower-to-bottom (key-place 1 5/2))
-
-        mlb (->> cover-sphere
-                 (translate [(- cover-sphere-x) 0 (+ (- height) -1)])
-                 (key-place 1/2 3/2))
-        mrb (->> cover-sphere
-                 (translate [cover-sphere-x 0 (+ (- height) -1)])
-                 (key-place 1/2 3/2))
-
-        mlt (->> cover-sphere
-                 (translate [(+ (- cover-sphere-x) -4) 0 -6])
-                 (key-place 1/2 3/2))
-        mrt (->> cover-sphere
-                 (translate [(+ cover-sphere-x 4) 0 -6])
-                 (key-place 1/2 3/2))]
-    (union
-      (hull cover-sphere-bl cover-sphere-br cover-sphere-tl cover-sphere-tr)
-      (hull cover-sphere-br cover-sphere-bl bl br)
-      (hull cover-sphere-tr cover-sphere-tl tl tr)
-      (hull cover-sphere-tl tl mlb mlt)
-      (hull cover-sphere-bl bl mlb mlt)
-      (hull cover-sphere-tr tr mrb mrt)
-      (hull cover-sphere-br br mrb mrt))))
-
-(def io-exp-width 10)
-(def io-exp-height 8)
-(def io-exp-length 36)
-
-(def teensy-width 20)
+(defn bottom-hull [& p]
+  (hull p (bottom 10.001 p)))
+
+(defn wall-brace [place1 dx1 dy1 post1 place2 dx2 dy2 post2]
+  (union
+    (hull
+      (place1 post1)
+      (place1 (translate [0 0 -15] post1))
+      (place1 (translate [(* dx1 5) (* dy1 5) -4] post1))
+      (place1 (translate [(* dx1 5) (* dy1 5) -15] post1))
+      (place2 post2)
+      (place2 (translate [0 0 -15] post2))
+      (place2 (translate [(* dx2 5) (* dy2 5) -4] post2))
+      (place2 (translate [(* dx2 5) (* dy2 5) -15] post2)))
+    (bottom-hull
+      (place1 (translate [(* dx1 5) (* dy1 5) -15] post1))
+      (place1 (translate [0         0         -15] post1))
+      (place1 (translate [(* dx1 5) (* dy1 5) -15] post1))
+      (place2 (translate [0         0         -15] post2))
+      (place2 (translate [(* dx2 5) (* dy2 5) -15] post2)))))
+
+(defn key-wall-brace [x1 y1 dx1 dy1 post1 x2 y2 dx2 dy2 post2]
+  (wall-brace (partial key-place x1 y1) dx1 dy1 post1
+              (partial key-place x2 y2) dx2 dy2 post2))
+
+(def case-walls
+  (union
+   ; back wall
+   (for [x (range 0 6)] (key-wall-brace x 0 0 1 web-post-tl x       0 0 1 web-post-tr))
+   (for [x (range 1 6)] (key-wall-brace x 0 0 1 web-post-tl (dec x) 0 0 1 web-post-tr))
+   (key-wall-brace 0 0 0 1 web-post-tl 0 0 -1 0 web-post-tl)
+   (key-wall-brace 5 0 0 1 web-post-tr 5 0 1 0 web-post-tr)
+   ; right wall
+   (for [y (range 0 lastrow)] (key-wall-brace 5 y 1 0 web-post-tr 5 y       1 0 web-post-br))
+   (for [y (range 1 lastrow)] (key-wall-brace 5 (dec y) 1 0 web-post-br 5 y 1 0 web-post-tr))
+   (key-wall-brace 5 cornerrow 0 -1 web-post-br 5 cornerrow 1 0 web-post-br)
+   ; left wall
+   (for [y (range 0 lastrow)] (key-wall-brace 0 y -1 0 web-post-tl 0 y       -1 0 web-post-bl))
+   (for [y (range 1 lastrow)] (key-wall-brace 0 (dec y) -1 0 web-post-bl 0 y -1 0 web-post-tl))
+   ; front wall
+   (key-wall-brace 3 lastrow   0 -1 web-post-bl 3 lastrow 0.5 -1 web-post-br)
+   (key-wall-brace 4 cornerrow 0 -1 web-post-bl 4 cornerrow 0 -1 web-post-br)
+   (key-wall-brace 5 cornerrow 0 -1 web-post-bl 5 cornerrow 0 -1 web-post-br)
+   (key-wall-brace 3 lastrow 0.5 -1 web-post-br 4 cornerrow 1 -1 web-post-bl)
+   (key-wall-brace 4 cornerrow 0 -1 web-post-br 5 cornerrow 0 -1 web-post-bl)
+   ; thumb walls
+   (wall-brace thumb-mr-place  0 -1 web-post-br thumb-tr-place  0 -1 thumb-post-br)
+   (wall-brace thumb-mr-place  0 -1 web-post-br thumb-mr-place  0 -1 web-post-bl)
+   (wall-brace thumb-br-place  0 -1 web-post-br thumb-br-place  0 -1 web-post-bl)
+   (wall-brace thumb-ml-place  0  1 web-post-tr thumb-ml-place  0  1 web-post-tl)
+   (wall-brace thumb-bl-place  0  1 web-post-tr thumb-bl-place  0  1 web-post-tl)
+   (wall-brace thumb-br-place -1  0 web-post-tl thumb-br-place -1  0 web-post-bl)
+   (wall-brace thumb-bl-place -1  0 web-post-tl thumb-bl-place -1  0 web-post-bl)
+   ; thumb corners
+   (wall-brace thumb-br-place -1  0 web-post-bl thumb-br-place  0 -1 web-post-bl)
+   (wall-brace thumb-bl-place -1  0 web-post-tl thumb-bl-place  0  1 web-post-tl)
+   ; thumb tweeners
+   (wall-brace thumb-mr-place  0 -1 web-post-bl thumb-br-place  0 -1 web-post-br)
+   (wall-brace thumb-ml-place  0  1 web-post-tl thumb-bl-place  0  1 web-post-tr)
+   (wall-brace thumb-bl-place -1  0 web-post-bl thumb-br-place -1  0 web-post-tl)
+   (wall-brace thumb-tr-place  0 -1 thumb-post-br (partial key-place 3 lastrow)  0 -1 web-post-bl)
+   ; clunky bit on the top left thumb connection
+   (wall-brace thumb-ml-place  0  1 web-post-tr thumb-tl-place -2.5  0 thumb-post-tl)
+   (wall-brace thumb-tl-place -1  0 thumb-post-tl (partial key-place 0 cornerrow) -1  0 web-post-bl)
+   ;; another incomplete try to fix this
+   ;  (bottom-hull (thumb-tl-place thumb-post-tl)
+   ;               (thumb-tl-place (translate [-7 0 0] thumb-post-tl))
+   ;               (thumb-ml-place web-post-tr)
+   ;               (thumb-ml-place (translate [0 5 -4] web-post-tr)))
+  ))
+
+(defn on-wall-place [column depth shape]
+  (translate [0 0 (- depth)]
+    (key-place column 0
+      (->> shape
+           (rotate (+ (* β (- centercol column)) (/ π 12)) [0 -1 0])
+           (rotate (* α centerrow) [-1 0 0])
+           (translate [0 (/ mount-height 2) -15])
+           ))))
+
+(def rj9-cube   (cube 14.78 13 22.38))
+(def rj9-space  (on-wall-place 1 20 rj9-cube))
+(def rj9-holder (on-wall-place 1 20
+                  (difference rj9-cube
+                              (union (translate [0 2 0] (cube 10.78  9 18.38))
+                                     (translate [0 0 5] (cube 10.78 13  5))))))
+
+(def teensy-width 20)  ; was 20
 (def teensy-height 12)
 (def teensy-length 33)
-
-(def io-exp-cover (circuit-cover io-exp-width io-exp-length io-exp-height))
-(def teensy-cover (circuit-cover teensy-width teensy-length teensy-height))
-
-(def trrs-diameter 6.6)
-(def trrs-radius (/ trrs-diameter 2))
-(def trrs-hole-depth 10)
-
-(def trrs-hole (->> (union (cylinder trrs-radius trrs-hole-depth)
-                           (->> (cube trrs-diameter (+ trrs-radius 5) trrs-hole-depth)
-                                (translate [0 (/ (+ trrs-radius 5) 2) 0])))
-                    (rotate (/ π 2) [1 0 0])
-                    (translate [0 (+ (/ mount-height 2) 4) (- trrs-radius)])
-                    (with-fn 50)))
-
-(def trrs-hole-just-circle
-  (->> (cylinder trrs-radius trrs-hole-depth)
-       (rotate (/ π 2) [1 0 0])
-       (translate [0 (+ (/ mount-height 2) 4) (- trrs-radius)])
-       (with-fn 50)
-       (key-place 1/2 0)))
-
-(def trrs-box-hole (->> (cube 14 14 7 )
-                        (translate [0 1 -3.5])))
-
-
-(def trrs-cutout
-  (->> (union trrs-hole
-              trrs-box-hole)
-       (key-place 1/2 0)))
-
-(def teensy-pcb-thickness 1.6)
+(def teensy2-length 53)
+(def teensy-pcb-thickness 1.6)
 (def teensy-offset-height 5)

-(def teensy-pcb (->> (cube 18 30.5 teensy-pcb-thickness)
-                     (translate [0 0 (+ (/ teensy-pcb-thickness -2) (- teensy-offset-height))])
-                     (key-place 1/2 3/2)
-                     (color [1 0 0])))
-
-(def teensy-support
-  (difference
-   (union
-    (->> (cube 3 3 9)
-         (translate [0 0 -2])
-         (key-place 1/2 3/2)
-         (color [0 1 0]))
-    (hull (->> (cube 3 6 9)
-               (translate [0 0 -2])
-               (key-place 1/2 2)
-               (color [0 0 1]))
-          (->> (cube 3 3 (+ teensy-pcb-thickness 3))
-               (translate [0 (/ 30.5 -2) (+ (- teensy-offset-height)
-                                            #_(/ (+ teensy-pcb-thickness 3) -2)
-                                            )])
-               (key-place 1/2 3/2)
-               (color [0 0 1]))))
-   teensy-pcb
-   (->> (cube 18 30.5 teensy-pcb-thickness)
-        (translate [0 1.5 (+ (/ teensy-pcb-thickness -2) (- teensy-offset-height) -1)])
-        (key-place 1/2 3/2)
-        (color [1 0 0]))))
+(def teensy-holder
+    (on-wall-place 0 20
+      (translate [-5 0 0]
+        (union
+          (->> (cube 3 (* 1.2 teensy2-length) (+ 6 teensy-width))
+               (translate [-1.5 -30 0]))
+          (->> (cube teensy-pcb-thickness (* 1.2 teensy2-length) 3)
+               (translate [(/ teensy-pcb-thickness 2) -30 (- -1.5 (/ teensy-width 2))]))
+          (->> (cube 4 (* 1.2 teensy2-length) 4)
+               (translate [(+ 2 teensy-pcb-thickness) -30 (-  -1 (/ teensy-width 2))]))
+          (->> (cube teensy-pcb-thickness (* 0.2 teensy2-length) 3)
+               (translate [(/ teensy-pcb-thickness 2) (+ (* 0.5 teensy2-length) -30) (+ 1.5 (/ teensy-width 2))]))
+          (->> (cube 4 (* 0.2 teensy2-length) 4)
+               (translate [(+ 2 teensy-pcb-thickness) (+ (* 0.5 teensy2-length) -30) (+  1 (/ teensy-width 2))]))
+           ))))

 (def usb-cutout
   (let [hole-height 6.2
@@ -1171,71 +500,25 @@
     (->> (hull side-cylinder
                (mirror [-1 0 0] side-cylinder))
          (rotate (/ π 2) [1 0 0])
-         (translate [0 (/ teensy-length 2) (- side-radius)])
-         (translate [0 0 (- 1)])
-         (translate [0 0 (- teensy-offset-height)])
-         (key-place 1/2 3/2))))
-
-;;;;;;;;;;;;;;;;;;
-;; Final Export ;;
-;;;;;;;;;;;;;;;;;;
-
-(def dactyl-bottom-right
-  (difference
-   (union
-    teensy-cover
-    (difference
-     bottom-plate
-     (hull teensy-cover)
-     new-case
-     teensy-cover
-     trrs-cutout
-     (->> (cube 1000 1000 10) (translate [0 0 -5]))
-     screw-holes))
-   usb-cutout))
-
-(def dactyl-bottom-left
-  (mirror [-1 0 0]
-          (union
-           io-exp-cover
-           (difference
-            bottom-plate
-            (hull io-exp-cover)
-            new-case
-            io-exp-cover
-            trrs-cutout
-            (->> (cube 1000 1000 10) (translate [0 0 -5]))
-            screw-holes))))
-
-(def dactyl-top-right
-  (difference
-   (union key-holes
-          connectors
-          thumb
-          new-case
-          teensy-support)
-   trrs-hole-just-circle
-   screw-holes))
-
-(def dactyl-top-left
-  (mirror [-1 0 0]
-          (difference
-           (union key-holes
-                  connectors
-                  thumb
-                  new-case)
-           trrs-hole-just-circle
-           screw-holes)))
-
-(spit "things/dactyl-top-right.scad"
-      (write-scad dactyl-top-right))
-
-(spit "things/dactyl-bottom-right.scad"
-      (write-scad dactyl-bottom-right))
-
-(spit "things/dactyl-top-left.scad"
-      (write-scad dactyl-top-left))
-
-(spit "things/dactyl-bottom-left.scad"
-      (write-scad dactyl-bottom-left))
-
+         (rotate (/ π 2) [0 1 0])
+         (on-wall-place 0 20))))
+
+;; teensy info
+; base width - 18
+; height - 1.45
+;
+
+(spit "things/right.scad"
+      (write-scad (union
+                   key-holes
+                   connectors
+                   thumb
+                   thumb-connectors
+                   (difference case-walls rj9-space usb-cutout)
+                   rj9-holder
+                   (if (= nrows 4) teensy-holder)
+                  ;  thumbcaps
+                  ;  caps
+                   )))
+
+


Problem added - Merging with Function

Problem added - Merging with Function

--- src/foreclojure/data_set.clj
+++ src/foreclojure/data_set.clj
@@ -714,9 +714,20 @@
            :description "Clojure only has one non-stack-consuming looping construct: recur.  Either a function or a loop can be used as the recursion point.  Either way, recur rebinds the bindings of the recursion point to the values it is passed.  Recur must be called from the tail-position, and calling it elsewhere will result in an error."
            :tags ["elementary" "recursion"]
            :tests ["(= __\n  (loop [x 5\n         result []]\n    (if (> x 0)\n      (recur (dec x) (conj result (+ 2 x)))\n      result)))"]})
+
+      (insert! :problems
+          {:_id 69
+           :title "Merge with Function"
+           :times-solved 0
+           :restricted ["merge-with"]
+           :description "Write a function which takes a function f and a variable number of maps.  Your function should return a map that consists of the rest of the maps conj-ed onto the first.  If a key occurs in more than one map, the new value should be calculated by applying f to each of the two original values."
+           :tags ["medium" "core-functions"]
+           :tests ["(= (__ * {:a 2, :b 3, :c 4} {:a 2} {:b 2} {:c 5})\n   {:a 4, :b 6, :c 20})"
+                   "(= (__ - {1 10, 2 20} {1 3, 2 10, 3 15})\n   {1 7, 2 10, 3 15})"
+                   "(= (__ concat {:a [3], :b [6]} {:a [4 5], :c [8 9]} {:b [7]})\n   {:a [3 4 5], :b [6 7], :c [8 9]})"]})

       (insert! :problems
-           {:_id 69
+           {:_id 70
             :title "Power Set"
             :times-solved 0
             :description "A power set is the set of all subsets of a given set. Given a list, produce a set of sublists while preserving the order of elements."


plugging the hole with trying to move back when no space is available

--- src/cartagena/console.clj
+++ src/cartagena/console.clj
@@ -50,10 +50,11 @@
           draw-pile (:draw-pile game-state)
           discard-pile (:discard-pile game-state)
           updated-state (engine/move-back player from-space board draw-pile discard-pile)]
-      (assoc game-state :board (:board updated-state)
-                        :draw-pile (:draw-pile updated-state)
-                        :discard-pile (:discard-pile updated-state)
-                        :players (conj (remove #{player} (:players game-state)) (:player updated-state))))))
+      (when updated-state
+        (assoc game-state :board (:board updated-state)
+                          :draw-pile (:draw-pile updated-state)
+                          :discard-pile (:discard-pile updated-state)
+                          :players (conj (remove #{player} (:players game-state)) (:player updated-state)))))))

 (defn no-action
   "Takes no active action; returns the game state as-is"
@@ -65,13 +66,17 @@
   "Acts out the selected action by gathering more input and calling appropriate functions"
   [action-fn game-state]
   (let [updated-game-state (action-fn game-state)]
-    (if (engine/game-over? (:board updated-game-state))
-      (end-game updated-game-state)
-      (let [updated-player-state (engine/update-current-player (:actions-remaining updated-game-state)
-                                                               (:current-player updated-game-state)
-                                                               (:player-order updated-game-state))]
-        (prompt-action (assoc updated-game-state :actions-remaining (:actions-remaining updated-player-state)
-                                                 :current-player (:current-player updated-player-state)))))))
+    (if (nil? updated-game-state)                           ;; nil indicates the action was invalid
+      (do
+        (println "Action was invalid!  Please try again.")
+        (prompt-action game-state))
+      (if (engine/game-over? (:board updated-game-state))
+        (end-game updated-game-state)
+        (let [updated-player-state (engine/update-current-player (:actions-remaining updated-game-state)
+                                                                 (:current-player updated-game-state)
+                                                                 (:player-order updated-game-state))]
+          (prompt-action (assoc updated-game-state :actions-remaining (:actions-remaining updated-player-state)
+                                                   :current-player (:current-player updated-player-state))))))))

 (defn display-board [game-state]
   (clojure.pprint/pprint (:board game-state)))


Added test for seal/unseal

Added test for seal/unseal

--- test/compojure/crypto.clj
+++ test/compojure/crypto.clj
@@ -61,3 +61,7 @@
     (is (= (decrypt *secret-key* algorithm param
                     (encrypt *secret-key* algorithm param message))
            message))))
+
+(deftest test-seal-unseal
+  (is (= (unseal (seal "Foobar"))
+         "Foobar")))


fix for default variables value

fix for default variables value

--- src/graphql_clj/executor.clj
+++ src/graphql_clj/executor.clj
@@ -109,27 +109,32 @@
   (let [required-var-names (->> (remove :default-value variable-definitions) (map :name) (map str) set)
         default-vars (->> (filter :default-value variable-definitions)
                           (map (fn [var-def]
-                                 [(:name var-def) (get-in var-def [:default-value :value])]))
+                                 [(str (:name var-def))
+                                  (get-in var-def [:default-value :value])]))
                           (into {}))
         input-var-names    (set (map key vars))
         missing-var-names  (set/difference required-var-names input-var-names)
         variables (merge default-vars vars)]
+    (println "vars: %s.%n" vars)
     (printf "variable-definitions: %s.%n" variable-definitions)
     (printf "required-vars:%s.%n" required-var-names)
     (printf "input-vars:%s.%n" input-var-names)
     (printf "missing-vars:%s.%n" missing-var-names)
     (printf "default-vars: %s.%n" default-vars)
     (printf "guard-missing-vars: variables: %s.%n" variables)
-    (map (fn erorr-msg [name] {:message (format "Missing input variables (%s)." name)}) missing-var-names)))
+    [(map (fn erorr-msg [name] {:message (format "Missing input variables (%s)." name)}) missing-var-names)
+     variables]))

 (defn- execute-statement [{:keys [selection-set variable-definitions] :as statement} {:keys [variables] :as state}]
-  (let [errors (guard-missing-vars variable-definitions variables)]
+  (let [[errors updated-variables] (guard-missing-vars variable-definitions variables)]
+    (println "updated-variables: " updated-variables)
     (if (seq errors)
       [errors nil]
-      [nil (execute-fields selection-set state 'QueryRoot :root)])))
+      [nil (execute-fields selection-set (assoc state :variables updated-variables) 'QueryRoot :root)])))

 (defn- execute-document
   [document state]
+  (println "execute-document: state:" state)
   (let [results (map #(execute-statement % state) document)
         errors (->> results
                     (filter first)


Problem added - Split by Type

Problem added - Split by Type

--- src/foreclojure/data_set.clj
+++ src/foreclojure/data_set.clj
@@ -501,4 +501,14 @@
             :tags ["easy" "seqs" "core-functions"]
             :tests ["(= (__ 3 [1 2 3 4 5 6]) [[1 2 3] [4 5 6]])"
 		    "(= (__ 1 [:a :b :c :d]) [[:a] [:b :c :d]])"
-                    "(= (__ 2 [[1 2] [3 4] [5 6]]) [[[1 2] [3 4]] [[5 6]]])"]})))+                    "(= (__ 2 [[1 2] [3 4] [5 6]]) [[[1 2] [3 4]] [[5 6]]])"]})
+
+       (insert! :problems
+           {:_id 50
+            :title "Split by Type"
+            :times-solved 0
+            :description "Write a function which takes a sequence consisting of items with different types and splits them up into a set of homogeneous sub-sequences. The internal order of each sub-sequence should be maintained, but the sub-sequences themselves can be returned in any order (this is why 'set' is used in the test cases)."
+            :tags ["medium" "seqs"]
+            :tests ["(= (set (__ [1 :a 2 :b 3 :c])) #{[1 2 3] [:a :b :c]})"
+		    "(= (set (__ [:a \"foo\"  \"bar\" :b])) #{[:a :b] [\"foo\" \"bar\"]})"
+                    "(= (set (__ [[1 2] :a [3 4] 5 6 :b])) #{[[1 2] [3 4]] [:a :b] [5 6]})"]})))


fix argument value

fix argument value

--- src/graphql_clj/executor.clj
+++ src/graphql_clj/executor.clj
@@ -12,7 +12,7 @@
   (fn [result {:keys [argument-name value variable-name] :as argument}]
     (cond
       ;; Argument has value
-      (contains? argument value) (assoc result [argument-name value]) ; Do not use value direclty, since argument value could be null
+      (contains? argument :value) (assoc result argument-name value) ; Do not use value direclty, since argument value could be null
       ;; Argument has value from variable
       (and variable-name (contains? variables variable-name)) (assoc result argument-name (get variables variable-name))
       :default result)))


Encode ns-qualified symbols in a consistent way

--- src/cheshire/generate.clj
+++ src/cheshire/generate.clj
@@ -71,7 +71,11 @@
                             (str ns "/" (name obj))
                             (name obj)))
     UUID (write-string ^JsonGenerator jg (.toString obj))
-    Symbol (write-string ^JsonGenerator jg (.toString obj))
+    Symbol (write-string ^JsonGenerator jg (if-let [sym (resolve obj)]
+                                             (str (:ns (meta sym))
+                                                  "/"
+                                                  (:name (meta sym)))
+                                             (.toString obj )))
     Boolean (.writeBoolean ^JsonGenerator jg ^Boolean obj)
     Date (let [sdf (doto (SimpleDateFormat. date-format)
                      (.setTimeZone (SimpleTimeZone. 0 "UTC")))]


Remove resource leak from `cljs.analyzer/parse-ns`

Change `cljs.analyzer/forms-seq` so that it takes an optional third parameter
`return-reader?`. If `true` return a vector where the second element is the
reader. In `cljs.analyzer/parse-ns` close the reader at the end of the loop.

--- src/clj/cljs/analyzer.clj
+++ src/clj/cljs/analyzer.clj
@@ -19,7 +19,7 @@
             [clojure.tools.reader.reader-types :as readers]
             [clojure.edn :as edn])
   (:import java.lang.StringBuilder
-           java.io.File
+           [java.io File Reader PushbackReader]
            java.net.URL
            [cljs.tagged_literals JSValue]))

@@ -1654,26 +1654,29 @@
 `clojure.java.io/reader` can produce a `java.io.Reader`. Optionally accepts a [filename]
 argument, which the reader will use in any emitted errors."
   ([f] (forms-seq f (source-path f)))
-  ([f filename]
-     (let [rdr (io/reader f)
-           pbr (readers/indexing-push-back-reader
-                (java.io.PushbackReader. rdr) 1 filename)
-           data-readers tags/*cljs-data-readers*
-           forms-seq*
-           (fn forms-seq* []
-             (lazy-seq
+  ([f filename] (forms-seq f filename false))
+  ([f filename return-reader?]
+    (let [rdr (io/reader f)
+          pbr (readers/indexing-push-back-reader
+                (PushbackReader. rdr) 1 filename)
+          data-readers tags/*cljs-data-readers*
+          forms-seq*
+          (fn forms-seq* []
+            (lazy-seq
               (let [eof-sentinel (Object.)
                     form (binding [*ns* (create-ns *cljs-ns*)
                                    reader/*data-readers* data-readers
                                    reader/*alias-map*
                                    (apply merge
-                                          ((juxt :requires :require-macros)
-                                           (get-namespace *cljs-ns*)))]
+                                     ((juxt :requires :require-macros)
+                                       (get-namespace *cljs-ns*)))]
                            (reader/read pbr nil eof-sentinel))]
                 (if (identical? form eof-sentinel)
                   (.close rdr)
                   (cons form (forms-seq*))))))]
-       (forms-seq*))))
+      (if (true? return-reader?)
+        [(forms-seq*) rdr]
+        (forms-seq*)))))

 (defn parse-ns
   ([src] (parse-ns src nil nil))
@@ -1684,13 +1687,14 @@
             ret
             (binding [*cljs-ns* 'cljs.user
                       *analyze-deps* (or (:analyze-deps opts) false)]
-              (loop [forms (forms-seq src)]
+              (loop [[forms rdr] (forms-seq src (source-path src) true)]
                 (if (seq forms)
                   (let [env (empty-env)
                         ast (no-warn (analyze env (first forms) nil opts))]
                     (if (= (:op ast) :ns)
                       (let [ns-name (:name ast)
                             deps    (merge (:uses ast) (:requires ast))]
+                        (.close ^Reader rdr)
                         (merge
                           {:ns (or ns-name 'cljs.user)
                            :provides [ns-name]


disable CLJS-941 again

disable CLJS-941 again

--- src/clj/cljs/analyzer.clj
+++ src/clj/cljs/analyzer.clj
@@ -45,7 +45,7 @@
    :undeclared-ns true
    :undeclared-ns-form true
    :redef true
-   :redef-in-file true
+   :redef-in-file false
    :dynamic true
    :fn-var true
    :fn-arity true


CLJS-885: relax type inference around numbers

--- src/clj/cljs/analyzer.clj
+++ src/clj/cljs/analyzer.clj
@@ -1341,7 +1341,7 @@
                              ;; when functions like first won't return nil, so variadic
                              ;; numeric functions like cljs.core/< would produce a spurious
                              ;; warning without this - David
-                             (and (set? t) (set/subset? t '#{any number nil clj-nil}))))
+                             (and (set? t) (or (contains? t 'number) (contains? t 'any)))))
                        types)
              (warning :invalid-arithmetic env
                {:js-op (-> form meta :js-op)


Finish warn on use of undeclared var. Refs #32

--- src/clj/cljs/compiler.clj
+++ src/clj/cljs/compiler.clj
@@ -13,8 +13,6 @@
   (:require [clojure.java.io :as io]
             [clojure.string :as string]))

-(def ^:dynamic *warn-on-undeclared* false)
-
 (declare resolve-var)
 (require 'cljs.core)

@@ -28,6 +26,7 @@

 (def ^:dynamic *cljs-ns* 'cljs.user)
 (def ^:dynamic *cljs-verbose* false)
+(def ^:dynamic *cljs-warn-on-undeclared* false)

 (defn munge [s]
   (let [ms (clojure.lang.Compiler/munge (str s))
@@ -50,9 +49,53 @@
 goog.require = function(rule){Packages.clojure.lang.RT[\"var\"](\"cljs.compiler\",\"goog-require\").invoke(goog.global.cljs_javascript_engine, rule);}
 ")

+(defn confirm-var-exists [env prefix suffix]
+  (when *cljs-warn-on-undeclared*
+    (let [crnt-ns (-> env :ns :name)]
+      (when (= prefix crnt-ns)
+        (when-not (-> @namespaces crnt-ns :defs suffix)
+          (binding [*out* *err*]
+            (println
+              (str "WARNING: Use of undeclared Var " prefix "/" suffix
+                   (when (:line env)
+                     (str " at line " (:line env)))))))))))
+
 (defn resolve-ns-alias [env name]
   (let [sym (symbol name)]
     (get (:requires (:ns env)) sym sym)))
+
+(defn resolve-existing-var [env sym]
+  (let [s (str sym)
+        lb (-> env :locals sym)
+        nm
+        (cond
+         lb (:name lb)
+
+         (namespace sym)
+         (let [ns (namespace sym)
+               ns (if (= "clojure.core" ns) "cljs.core" ns)
+               full-ns (resolve-ns-alias env ns)]
+           (confirm-var-exists env full-ns (symbol (name sym)))
+           (symbol (str full-ns "." (munge (name sym)))))
+
+         (.contains s ".")
+         (munge (let [idx (.indexOf s ".")
+                      prefix (symbol (subs s 0 idx))
+                      suffix (subs s idx)
+                      lb (-> env :locals prefix)]
+                  (if lb
+                    (symbol (str (:name lb) suffix))
+                    (do
+                      (confirm-var-exists env prefix (symbol suffix))
+                      sym))))
+
+         :else
+         (let [full-ns (if (get (:defs (@namespaces 'cljs.core)) sym)
+                         'cljs.core
+                         (-> env :ns :name))]
+           (confirm-var-exists env full-ns sym)
+           (munge (symbol (str full-ns "." (munge (name sym)))))))]
+    {:name nm}))

 (defn resolve-var [env sym]
   (let [s (str sym)
@@ -82,19 +125,6 @@
                            (-> env :ns :name))
                          "." (munge (name sym))))))]
     {:name nm}))
-
-(defn confirm-var [env varname]
-  (when *warn-on-undeclared*
-    (let [v (name (:name varname))
-          crnt-ns (-> env :ns :name)
-          li (.lastIndexOf v ".")
-          prefix (subs v 0 (max 0 li))]
-      (when (= prefix (name crnt-ns))
-        (let [suffix (subs v (inc li))]
-          (when-not (-> @namespaces crnt-ns :defs (get (symbol suffix)))
-            (binding [*out* *err*]
-              (println "WARNING: Use of undeclared Var" v)))))))
-  varname)

 (defn- comma-sep [xs]
   (apply str (interpose "," xs)))
@@ -659,7 +689,7 @@
                      (if (= -1 idx)
                        (list s)
                        (let [end (.indexOf s "}" idx)
-                             inner (:name (confirm-var env (resolve-var env (symbol (subs s (+ 2 idx) end)))))]
+                             inner (:name (resolve-existing-var env (symbol (subs s (+ 2 idx) end))))]
                          (cons (subs s 0 idx) (cons inner (interp (subs s (inc end)))))))))]
       {:env env :op :js :code (apply str (interp form))})))

@@ -678,7 +708,7 @@
         lb (-> env :locals sym)]
     (if lb
       (assoc ret :op :var :info lb)
-      (assoc ret :op :var :info (confirm-var env (resolve-var env sym))))))
+      (assoc ret :op :var :info (resolve-existing-var env sym)))))

 (defn get-expander [sym env]
   (let [mvar
@@ -711,14 +741,15 @@

 (defn analyze-seq
   [env form name]
-  (let [op (first form)]
-    (assert (not (nil? op)) "Can't call nil")
-    (let [mform (macroexpand-1 env form)]
-      (if (identical? form mform)
-        (if (specials op)
-          (parse op env form name)
-          (parse-invoke env form))
-        (analyze env mform name)))))
+  (let [env (assoc env :line (-> form meta :line))]
+    (let [op (first form)]
+      (assert (not (nil? op)) "Can't call nil")
+      (let [mform (macroexpand-1 env form)]
+        (if (identical? form mform)
+          (if (specials op)
+            (parse op env form name)
+            (parse-invoke env form))
+          (analyze env mform name))))))

 (declare analyze-wrap-meta)

@@ -854,10 +885,11 @@

 (defn repl
   "Note - repl will reload core.cljs every time, even if supplied old repl-env"
-  [repl-env & {:keys [verbose]}]
+  [repl-env & {:keys [verbose warn-on-undeclared]}]
   (prn "Type: " :cljs/quit " to quit")
   (binding [*cljs-ns* 'cljs.user
-            *cljs-verbose* verbose]
+            *cljs-verbose* verbose
+            *cljs-warn-on-undeclared* warn-on-undeclared]
     (let [env {:context :statement :locals {}}]
       (load-file repl-env "cljs/core.cljs")
       (eval1 repl-env (assoc env :ns (@namespaces *cljs-ns*))
@@ -931,6 +963,8 @@
 (comp/repl repl-env)
 ;having problems?, try verbose mode
 (comp/repl repl-env :verbose true)
+;don't forget to check for uses of undeclared vars
+(comp/repl repl-env :warn-on-undeclared true)

 (test-stuff)
 (+ 1 2 3)


Removed :children key from the ast and added children multimethod instead

--- src/clj/cljs/compiler.clj
+++ src/clj/cljs/compiler.clj
@@ -347,7 +347,7 @@
     (emits "cljs.core.with_meta(" expr "," meta ")")))

 (defmethod emit :map
-  [{:keys [children env simple-keys? keys vals]}]
+  [{:keys [env simple-keys? keys vals]}]
   (emit-wrap env
     (emits "cljs.core.PersistentHashMap.fromArrays(["
            (comma-sep keys)
@@ -356,16 +356,16 @@
            "])")))

 (defmethod emit :vector
-  [{:keys [children env]}]
+  [{:keys [items env]}]
   (emit-wrap env
     (emits "cljs.core.PersistentVector.fromArray(["
-           (comma-sep children) "])")))
+           (comma-sep items) "])")))

 (defmethod emit :set
-  [{:keys [children env]}]
+  [{:keys [items env]}]
   (emit-wrap env
     (emits "cljs.core.set(["
-           (comma-sep children) "])")))
+           (comma-sep items) "])")))

 (defmethod emit :constant
   [{:keys [form env]}]
@@ -755,14 +755,14 @@
   `(binding [*recur-frames* (cons nil *recur-frames*)] ~@body))

 (defn analyze-block
-  "returns {:statements .. :ret .. :children ..}"
+  "returns {:statements .. :ret ..}"
   [env exprs]
   (let [statements (disallowing-recur
                      (seq (map #(analyze (assoc env :context :statement) %) (butlast exprs))))
         ret (if (<= (count exprs) 1)
               (analyze env (first exprs))
               (analyze (assoc env :context (if (= :statement (:context env)) :statement :return)) (last exprs)))]
-    {:statements statements :ret ret :children (vec (cons ret statements))}))
+    {:statements statements :ret ret}))

 (defmulti parse (fn [op & rest] op))

@@ -773,15 +773,13 @@
         else-expr (analyze env else)]
     {:env env :op :if :form form
      :test test-expr :then then-expr :else else-expr
-     :children [test-expr then-expr else-expr]
      :unchecked @*unchecked-if*}))

 (defmethod parse 'throw
   [op env [_ throw :as form] name]
   (let [throw-expr (disallowing-recur (analyze (assoc env :context :expr) throw))]
     {:env env :op :throw :form form
-     :throw throw-expr
-     :children [throw-expr]}))
+     :throw throw-expr}))

 (defmethod parse 'try*
   [op env [_ & body :as form] name]
@@ -815,8 +813,7 @@
      :try try
      :finally finally
      :name mname
-     :catch catch
-     :children [try {:name mname} catch finally]}))
+     :catch catch}))

 (defmethod parse 'def
   [op env form name]
@@ -875,7 +872,6 @@
               :name name :doc doc :init init-expr}
              (when tag {:tag tag})
              (when dynamic {:dynamic true})
-             (when init-expr {:children [init-expr]})
              (when export-as {:export export-as})))))

 (defn- analyze-fn-method [env locals meth]
@@ -900,8 +896,9 @@
          recur-frame {:names (vec (map munge params)) :flag (atom nil)}
          block (binding [*recur-frames* (cons recur-frame *recur-frames*)]
                  (analyze-block (assoc env :context :return :locals locals) body))]
-
-     (merge {:env env :variadic variadic :params (map munge params) :max-fixed-arity fixed-arity :gthis gthis :recurs @(:flag recur-frame)} block))))
+     (merge {:env env :variadic variadic :params (map munge params) :max-fixed-arity fixed-arity
+             :gthis gthis :recurs @(:flag recur-frame)}
+            block))))

 (defmethod parse 'fn*
   [op env [_ & args] name]
@@ -950,14 +947,14 @@
                         (next bindings))))
              [bes env])))
         recur-frame (when is-loop {:names (vec (map :name bes)) :flag (atom nil)})
-        {:keys [statements ret children]}
+        {:keys [statements ret]}
         (binding [*recur-frames* (if recur-frame (cons recur-frame *recur-frames*) *recur-frames*)
                   *loop-lets* (cond
                                is-loop (or *loop-lets* ())
                                *loop-lets* (cons {:names (vec (map :name bes))} *loop-lets*))]
           (analyze-block (assoc env :context (if (= :expr context) :return context)) exprs))]
     {:env encl-env :op :let :loop is-loop
-     :bindings bes :statements statements :ret ret :form form :children (into [children] (map :init bes))}))
+     :bindings bes :statements statements :ret ret :form form}))

 (defmethod parse 'let*
   [op encl-env form _]
@@ -988,7 +985,7 @@
    (let [enve (assoc env :context :expr)
          ctorexpr (analyze enve ctor)
          argexprs (vec (map #(analyze enve %) args))]
-     {:env env :op :new :ctor ctorexpr :args argexprs :children (conj argexprs ctorexpr)})))
+     {:env env :op :new :ctor ctorexpr :args argexprs})))

 (defmethod parse 'set!
   [_ env [_ target val alt] _]
@@ -1022,8 +1019,7 @@
        (assert targetexpr "set! target must be a field or a symbol naming a var")
        (cond
         (= targetexpr ::set-unchecked-if) {:env env :op :no-op}
-        :else {:env env :op :set! :target targetexpr
-               :val valexpr :children [targetexpr valexpr]})))))
+        :else {:env env :op :set! :target targetexpr :val valexpr})))))

 (defmethod parse 'ns
   [_ env [_ name & args] _]
@@ -1168,14 +1164,13 @@
   (disallowing-recur
    (let [{:keys [dot-action target method field args]} (build-dot-form [target field member+])
          enve        (assoc env :context :expr)
-         targetexpr  (analyze enve target)
-         children    [enve]]
+         targetexpr  (analyze enve target)]
      (case dot-action
-           ::access {:env env :op :dot :children children
+           ::access {:env env :op :dot
                      :target targetexpr
                      :field field}
            ::call   (let [argexprs (map #(analyze enve %) args)]
-                      {:env env :op :dot :children (into children argexprs)
+                      {:env env :op :dot
                        :target targetexpr
                        :method method
                        :args argexprs})))))
@@ -1193,7 +1188,7 @@
                        (cons (subs s 0 idx) (seg (subs s (inc end))))))))
            enve (assoc env :context :expr)
            argexprs (vec (map #(analyze enve %) args))]
-       {:env env :op :js :segs (seg jsform) :args argexprs :children argexprs
+       {:env env :op :js :segs (seg jsform) :args argexprs
         :tag (-> form meta :tag) :form form}))
     (let [interp (fn interp [^String s]
                    (let [idx (.indexOf s "~{")]
@@ -1220,7 +1215,7 @@
            (warning env
              (str "WARNING: Wrong number of args (" argc ") passed to " name)))))
      {:env env :op :invoke :f fexpr :args argexprs
-      :children (conj argexprs fexpr) :tag (-> fexpr :info :tag)})))
+      :tag (-> fexpr :info :tag)})))

 (defn analyze-symbol
   "Finds the var associated with sym"
@@ -1287,7 +1282,7 @@
                              (keys form))
         ks (disallowing-recur (vec (map #(analyze expr-env % name) (keys form))))
         vs (disallowing-recur (vec (map #(analyze expr-env % name) (vals form))))]
-    (analyze-wrap-meta {:op :map :env env :form form :children (vec (concat ks vs))
+    (analyze-wrap-meta {:op :map :env env :form form
                         :keys ks :vals vs :simple-keys? simple-keys?}
                        name)))

@@ -1295,13 +1290,13 @@
   [env form name]
   (let [expr-env (assoc env :context :expr)
         items (disallowing-recur (vec (map #(analyze expr-env % name) form)))]
-    (analyze-wrap-meta {:op :vector :env env :form form :children items} name)))
+    (analyze-wrap-meta {:op :vector :env env :form form :items items} name)))

 (defn analyze-set
   [env form name]
   (let [expr-env (assoc env :context :expr)
         items (disallowing-recur (vec (map #(analyze expr-env % name) form)))]
-    (analyze-wrap-meta {:op :set :env env :form form :children items} name)))
+    (analyze-wrap-meta {:op :set :env env :form form :items items} name)))

 (defn analyze-wrap-meta [expr name]
   (let [form (:form expr)]
@@ -1309,7 +1304,7 @@
       (let [env (:env expr) ; take on expr's context ourselves
             expr (assoc-in expr [:env :context] :expr) ; change expr to :expr
             meta-expr (analyze-map (:env expr) (meta form) name)]
-        {:op :meta :env env :form form :children [meta-expr expr]
+        {:op :meta :env env :form form
          :meta meta-expr :expr expr})
       expr)))

@@ -1317,9 +1312,7 @@
   "Given an environment, a map containing {:locals (mapping of names to bindings), :context
   (one of :statement, :expr, :return), :ns (a symbol naming the
   compilation ns)}, and form, returns an expression object (a map
-  containing at least :form, :op and :env keys). If expr has any (immediately)
-  nested exprs, must have :children [exprs...] entry. This will
-  facilitate code walking without knowing the details of the op set."
+  containing at least :form, :op and :env keys)."
   ([env form] (analyze env form nil))
   ([env form name]
      (let [form (if (instance? clojure.lang.LazySeq form)
@@ -1490,6 +1483,106 @@
                  ns-info (compile-file cljs-file output-file)]
              (recur (rest cljs-files) (conj output-files (assoc ns-info :file-name (.getPath output-file)))))
            output-files)))))
+
+(defn- expr-obj? [obj]
+  (contains? obj :op))
+
+(defmulti children
+  "Returns the children [exprs..] of an expression object. This will
+   facilitate code walking without knowing the details of the op set."
+  :op)
+
+(defmethod children :if [ast]
+  {:post [(every? expr-obj? %)]}
+  [(:test ast) (:then ast) (:else ast)])
+
+(defmethod children :throw [ast]
+  {:post [(every? expr-obj? %)]}
+  [(:throw ast)])
+
+(defn- block-children [block]
+  {:post [(every? expr-obj? %)]}
+  (let [statements (when-let [statements (:statements block)]
+                     (vec statements))
+        ret (when-let [ret (:ret block)]
+              [ret])
+        children (into statements ret)]
+    (when-not (empty? children)
+      children)))
+
+(defmethod children :try* [ast]
+  {:post [(every? expr-obj? %)]}
+  (vec (mapcat block-children
+               [(:try ast)
+                (:catch ast)
+                (:finally ast)])))
+
+(defmethod children :def [ast]
+  {:post [(every? expr-obj? %)]}
+  (when-let [init (:init ast)]
+    [init]))
+
+(defmethod children :fn [ast]
+  {:post [(every? expr-obj? %)]}
+  (vec (mapcat block-children (:methods ast))))
+
+(defmethod children :do [ast]
+  {:post [(every? expr-obj? %)]}
+  (block-children ast))
+
+(defmethod children :let [ast]
+  {:post [(every? expr-obj? %)]}
+  (let [inits (vec (map :init (:bindings ast)))]
+    (into inits
+          (block-children ast))))
+
+(defmethod children :recur [ast]
+  {:post [(every? expr-obj? %)]}
+  (:exprs ast))
+
+(defmethod children :new [ast]
+  {:post [(every? expr-obj? %)]}
+  (into [(:ctor ast)]
+        (:args ast)))
+
+(defmethod children :set! [ast]
+  {:post [(every? expr-obj? %)]}
+  [(:target ast)
+   (:val ast)])
+
+(defmethod children :dot [ast]
+  {:post [(every? expr-obj? %)]}
+  (into [(:target ast)]
+        (:args ast)))
+
+(defmethod children :js [ast]
+  {:post [(every? expr-obj? %)]}
+  (vec (:args ast)))
+
+(defmethod children :invoke [ast]
+  {:post [(every? expr-obj? %)]}
+  (into [(:f ast)]
+        (:args ast)))
+
+(defmethod children :map [ast]
+  {:post [(every? expr-obj? %)]}
+  (vec (interleave (:keys ast) (:vals ast))))
+
+(defmethod children :vector [ast]
+  {:post [(every? expr-obj? %)]}
+  (:items ast))
+
+(defmethod children :set [ast]
+  {:post [(every? expr-obj? %)]}
+  (:items ast))
+
+(defmethod children :meta [ast]
+  {:post [(every? expr-obj? %)]}
+  [(:meta ast) (:expr ast)])
+
+(defmethod children :default [ast]
+  {:pre [(expr-obj? ast)]}
+  nil)

 (comment
   ;; compile-root


* src/cljs/cljs/reader.cljs: CLJS-85: fix read-string behavior for keywords, disallow the same bad keyword forms as Clojure

--- src/cljs/cljs/reader.cljs
+++ src/cljs/cljs/reader.cljs
@@ -95,6 +95,7 @@
 (def int-pattern (re-pattern "([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)(N)?"))
 (def ratio-pattern (re-pattern "([-+]?[0-9]+)/([0-9]+)"))
 (def float-pattern (re-pattern "([-+]?[0-9]+(\\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?"))
+(def symbol-pattern (re-pattern "[:]?([^0-9/].*/)?([^0-9/][^/]*)"))

 (defn- match-int
   [s]
@@ -252,11 +253,16 @@

 (defn read-keyword
   [reader initch]
-  (let [token (read-token reader (read-char reader))]
-    (if (gstring/contains token "/")
-      (keyword (subs token 0 (.indexOf token "/"))
-               (subs token (inc (.indexOf token "/")) (.length token)))
-      (keyword token))))
+  (let [token (read-token reader (read-char reader))
+        [token ns name] (re-matches symbol-pattern token)]
+    (if (or (and (not (undefined? ns))
+                 (identical? (. ns (substring (- (.length ns) 2) (.length ns))) ":/"))
+            (identical? (aget name (dec (.length name))) ":")
+            (not (== (.indexOf token "::" 1) -1)))
+      (reader-error reader "Invalid token: " token)
+      (if (not (undefined? ns))
+        (keyword (.substring ns 0 (.indexOf ns "/")) name)
+        (keyword token)))))

 (defn desugar-meta
   [f]