Apply offsets to rest of known parameters

--- src/mininova_web_ui/params.cljs
+++ src/mininova_web_ui/params.cljs
@@ -67,13 +67,13 @@

 (def params
   {:voice/polyphony-mode {:cc 3 :in [0 4] :enum ["Mono" "Mono AG" "Poly 1" "Poly 2" "Mono 2"] :offset 34}
-   :voice/portamento-rate {:cc 5 :in [0 127]}
-   :voice/pre-glide {:cc 9 :in [52 76] :out [-12 12]}
-   :voice/portamento-mode {:cc 12 :in [0 1] :enum ["Expo" "Linear"]}
+   :voice/portamento-rate {:cc 5 :in [0 127] :offset 35}
+   :voice/pre-glide {:cc 9 :in [52 76] :out [-12 12] :offset 36}
+   :voice/portamento-mode {:cc 12 :in [0 1] :enum ["Expo" "Linear"] :offset 37}
    ;; FIXME: Handle this range properly
    :voice/keyboard-octave {:cc 13 :in [124 4] :out [-4 4] :offset 0}
-   :voice/unison {:cc 14 :in [0 4] :enum ["Off" 1 2 3 4]}
-   :voice/unison-detune {:cc 15 :in [0 127]}
+   :voice/unison {:cc 14 :in [0 4] :enum ["Off" 1 2 3 4] :offset 39}
+   :voice/unison-detune {:cc 15 :in [0 127] :offset 40}

    :midi/modulation {:cc 1 :in [0 127] :offset 0}
    :midi/breath-controller {:cc 2 :in [0 127] :offset 0}
@@ -136,16 +136,16 @@
    :osc-3/cents {:cc 49 :in [0 127] :out [-64 63] :offset 74}
    :osc-3/pitch-bend {:cc 50 :in [52 76] :out [-12 12] :offset 75}

-   :mixer/wet-level {:cc 8 :in [0 127]}
-   :mixer/osc-1-level {:cc 51 :in [0 127]}
-   :mixer/osc-2-level {:cc 52 :in [0 127]}
-   :mixer/osc-3-level {:cc 53 :in [0 127]}
-   :mixer/ring-mod-13-level {:cc 54 :in [0 127]}
-   :mixer/ring-mod-23-level {:cc 55 :in [0 127]}
-   :mixer/noise-level {:cc 56 :in [0 127]}
-   :mixer/noise-colour {:cc 57 :in [0 3] :enum ["White" "High" "Band" "HiBand"]}
-   :mixer/pre-fx-level {:cc 58 :in [52 82] :out [-12 18]}
-   :mixer/post-fx-level {:cc 59 :in [52 82] :out [-12 18]}
+   :mixer/wet-level {:cc 8 :in [0 127] :offset 85}
+   :mixer/osc-1-level {:cc 51 :in [0 127] :offset 76}
+   :mixer/osc-2-level {:cc 52 :in [0 127] :offset 77}
+   :mixer/osc-3-level {:cc 53 :in [0 127] :offset 78}
+   :mixer/ring-mod-13-level {:cc 54 :in [0 127] :offset 79}
+   :mixer/ring-mod-23-level {:cc 55 :in [0 127] :offset 80}
+   :mixer/noise-level {:cc 56 :in [0 127] :offset 81}
+   :mixer/noise-colour {:cc 57 :in [0 3] :enum ["White" "High" "Band" "HiBand"] :offset 82}
+   :mixer/pre-fx-level {:cc 58 :in [52 82] :out [-12 18] :offset 83}
+   :mixer/post-fx-level {:cc 59 :in [52 82] :out [-12 18] :offset 84}

    :filter/routing {:cc 60 :in [0 5] :enum ["Bypass" "Single" "Series" "Parallel" "Parallal" "Drum"] :offset 86}
    :filter/balance {:cc 61 :in [0 127] :out [-64 63] :offset 87}
@@ -182,7 +182,7 @@
    :animate-7/hold {:cc [60 6] :in [0 127] :offset 0}
    :animate-8/hold {:cc [60 7] :in [0 127] :offset 0}

-   :env/track-centre {:cc 106 :in [0 127]}
+   :env/track-centre {:cc 106 :in [0 127] :offset 113}

    :env-1/sustain {:cc 70 :in [0 127] :offset 118}
    :env-1/release {:cc 72 :in [0 127] :offset 119}
@@ -321,167 +321,168 @@
    :lfo-3/common-sync {:cc [0 122] :in [36 37] :enum ["Normal" "Common"] :offset 225}
    :lfo-3/delay-trigger {:cc [0 122] :in [38 39] :enum ["Single" "Multi"] :offset 225}
    ;; NOTE: Docs say :in [4 7] but thats lfo-2/fade-mode
-   :lfo-3/fade-mode {:cc [1 123] :in [8 11] :enum ["Fade In" "Fade Out" "Gate In" "Gate Out"]}
-
-   :fx-pan/position {:cc 10 :in [0 127] :out [-64 63]}
-   :fx-pan/rate {:cc 88 :in [0 127]}
-   :fx-pan/sync {:cc 89 :in [0 35] :enum sync-enum}
-   :fx-pan/mod-depth {:cc 90 :in [0 127]}
-
-   :fx/routing {:cc [0 97] :in [0 7]} ;; TODO: Enum
-   :fx/feedback {:cc [0 98] :in [0 127]}
-
-   :fx-1/level {:cc 91 :in [0 127]}
-   :fx-1/select {:cc [0 99] :in [0 14] :enum fx-select-enum}
-
-   :fx-2/level {:cc 92 :in [0 127]}
-   :fx-2/select {:cc [0 100] :in [0 14] :enum fx-select-enum}
-
-   :fx-3/level {:cc 93 :in [0 127]}
-   :fx-3/select {:cc [0 101] :in [0 14] :enum fx-select-enum}
-
-   :fx-4/level {:cc 94 :in [0 127]}
-   :fx-5/level {:cc 95 :in [0 127]}
-
-   :fx-4/select {:cc [0 102] :in [0 14] :enum fx-select-enum}
-   :fx-5/select {:cc [0 103] :in [0 14] :enum fx-select-enum}
-
-   :equaliser/bass-frequency {:cc [0 104] :in [0 127]}
-   :equaliser/bass-level {:cc [0 105] :in [0 127] :out [-64 63]}
-   :equaliser/mid-frequency {:cc [0 106] :in [0 127]}
-   :equaliser/mid-level {:cc [0 107] :in [0 127] :out [-64 63]}
-   :equaliser/treble-frequency {:cc [0 108] :in [0 127]}
-   :equaliser/treble-level {:cc [0 109] :in [0 127] :out [-64 63]}
-
-   :compressor-1/ratio {:cc [0 110] :in [0 127]}
-   :compressor-1/treshold {:cc [0 111] :in [0 60] :out [-60 0]}
-   :compressor-1/attack {:cc [0 112] :in [0 127]}
-   :compressor-1/release {:cc [0 113] :in [0 127]}
-   :compressor-1/hold {:cc [0 114] :in [0 127]}
-   :compressor-1/gain {:cc [0 115] :in [0 127]}
-
-   :compressor-2/ratio {:cc [0 116] :in [0 127]}
-   :compressor-2/treshold {:cc [0 117] :in [0 60] :out [-60 0]}
-   :compressor-2/attack {:cc [0 118] :in [0 127]}
-   :compressor-2/release {:cc [0 119] :in [0 127]}
-   :compressor-2/hold {:cc [0 120] :in [0 127]}
-   :compressor-2/gain {:cc [0 121] :in [0 127]}
+   :lfo-3/fade-mode {:cc [1 123] :in [8 11] :enum ["Fade In" "Fade Out" "Gate In" "Gate Out"] :offset 379}
+
+   :fx-pan/position {:cc 10 :in [0 127] :out [-64 63] :offset 105}
+   :fx-pan/rate {:cc 88 :in [0 127] :offset 106}
+   :fx-pan/sync {:cc 89 :in [0 35] :enum sync-enum :offset 107}
+   :fx-pan/mod-depth {:cc 90 :in [0 127] :offset 108}
+
+   :fx/routing {:cc [0 97] :in [0 7] :offset 226} ;; TODO: Enum
+   :fx/feedback {:cc [0 98] :in [0 127] :offset 227}
+
+   :fx-1/level {:cc 91 :in [0 127] :offset 233}
+   :fx-1/select {:cc [0 99] :in [0 14] :enum fx-select-enum :offset 228}
+
+   :fx-2/level {:cc 92 :in [0 127] :offset 234}
+   :fx-2/select {:cc [0 100] :in [0 14] :enum fx-select-enum :offset 229}
+
+   :fx-3/level {:cc 93 :in [0 127] :offset 235}
+   :fx-3/select {:cc [0 101] :in [0 14] :enum fx-select-enum :offset 230}
+
+   :fx-4/level {:cc 94 :in [0 127] :offset 236}
+   :fx-4/select {:cc [0 102] :in [0 14] :enum fx-select-enum :offset 231}
+
+   :fx-5/level {:cc 95 :in [0 127] :offset 237}
+   :fx-5/select {:cc [0 103] :in [0 14] :enum fx-select-enum :offset 232}
+
+   :equaliser/bass-frequency {:cc [0 104] :in [0 127] :offset 238}
+   :equaliser/bass-level {:cc [0 105] :in [0 127] :out [-64 63] :offset 239}
+   :equaliser/mid-frequency {:cc [0 106] :in [0 127] :offset 240}
+   :equaliser/mid-level {:cc [0 107] :in [0 127] :out [-64 63] :offset 241}
+   :equaliser/treble-frequency {:cc [0 108] :in [0 127] :offset 242}
+   :equaliser/treble-level {:cc [0 109] :in [0 127] :out [-64 63] :offset 243}
+
+   :compressor-1/ratio {:cc [0 110] :in [0 127] :offset 244}
+   :compressor-1/treshold {:cc [0 111] :in [0 60] :out [-60 0] :offset 245}
+   :compressor-1/attack {:cc [0 112] :in [0 127] :offset 246}
+   :compressor-1/release {:cc [0 113] :in [0 127] :offset 247}
+   :compressor-1/hold {:cc [0 114] :in [0 127] :offset 248}
+   :compressor-1/gain {:cc [0 115] :in [0 127] :offset 249}
+
+   :compressor-2/ratio {:cc [0 116] :in [0 127] :offset 250}
+   :compressor-2/treshold {:cc [0 117] :in [0 60] :out [-60 0] :offset 251}
+   :compressor-2/attack {:cc [0 118] :in [0 127] :offset 252}
+   :compressor-2/release {:cc [0 119] :in [0 127] :offset 253}
+   :compressor-2/hold {:cc [0 120] :in [0 127] :offset 254}
+   :compressor-2/gain {:cc [0 121] :in [0 127] :offset 255}

    :distortion-1/type {:cc [1 0] :in [0 6] :enum ["Diode" "Valve" "Clipper" "XOver" "Rectify" "BitsDown" "RateDown"] :offset 256}
    :distortion-1/compensation {:cc [1 1] :in [0 127] :offset 257}
-   :distortion-1/level {:cc [1 2] :in [52 82] :out [-12 18]}
-
-   :distortion-2/type {:cc [1 3] :in [0 6] :enum ["Diode" "Valve" "Clipper" "XOver" "Rectify" "BitsDown" "RateDown"]}
-   :distortion-2/compensation {:cc [1 4] :in [0 127]}
-   :distortion-2/level {:cc [1 5] :in [52 82] :out [-12 18]}
-
-   :delay-1/time {:cc [1 6] :in [0 127]}
-   :delay-1/time-sync {:cc [1 7] :in [0 35]} ;; TODO: Enum
-   :delay-1/feedback {:cc [1 8] :in [0 127]}
-   :delay-1/width {:cc [1 9] :in [0 127]}
-   :delay-1/lr-ratio {:cc [1 10] :in [0 12]} ;; TODO: Enum
-   :delay-1/slew-rate {:cc [1 11] :in [0 127]}
-
-   :delay-2/time {:cc [1 12] :in [0 127]}
-   :delay-2/time-sync {:cc [1 13] :in [0 35]} ;; TODO: Enum
-   :delay-2/feedback {:cc [1 14] :in [0 127]}
-   :delay-2/width {:cc [1 15] :in [0 127]}
-   :delay-2/lr-ratio {:cc [1 16] :in [0 12]} ;; TODO: Enum
-   :delay-2/slew-rate {:cc [1 17] :in [0 127]}
-
-   :reverb-1/type {:cc [1 18] :in [0 5] :enum ["Chamber" "SmlRoom" "Lrgroom" "SmlHall" "LrgHall" "GrtHall"]}
-   :reverb-1/decay {:cc [1 19] :in [0 127]}
-   :reverb-1/damping {:cc [1 20] :in [0 127]}
-
-   :reverb-2/type {:cc [1 21] :in [0 5] :enum ["Chamber" "SmlRoom" "Lrgroom" "SmlHall" "LrgHall" "GrtHall"]}
-   :reverb-2/decay {:cc [1 22] :in [0 127]}
-   :reverb-2/damping {:cc [1 23] :in [0 127]}
-
-   :chorus-1/type {:cc [1 24] :in [0 1] :enum ["Phaser" "Chorus"]}
-   :chorus-1/rate {:cc [1 25] :in [0 127]}
-   :chorus-1/rate-sync {:cc [1 26] :in [0 35]} ;; TODO: Enum
-   :chorus-1/feedback {:cc [1 27] :in [0 127] :out [-64 63]}
-   :chorus-1/mod-depth {:cc [1 28] :in [0 127]}
-   :chorus-1/delay {:cc [1 29] :in [0 127]}
-
-   :chorus-2/type {:cc [1 30] :in [0 1] :enum ["Phaser" "Chorus"]}
-   :chorus-2/rate {:cc [1 31] :in [0 127]}
+   :distortion-1/level {:cc [1 2] :in [52 82] :out [-12 18] :offset 258}
+
+   :distortion-2/type {:cc [1 3] :in [0 6] :enum ["Diode" "Valve" "Clipper" "XOver" "Rectify" "BitsDown" "RateDown"] :offset 259}
+   :distortion-2/compensation {:cc [1 4] :in [0 127] :offset 260}
+   :distortion-2/level {:cc [1 5] :in [52 82] :out [-12 18] :offset 261}
+
+   :delay-1/time {:cc [1 6] :in [0 127] :offset 262}
+   :delay-1/time-sync {:cc [1 7] :in [0 35] :offset 263} ;; TODO: Enum
+   :delay-1/feedback {:cc [1 8] :in [0 127] :offset 264}
+   :delay-1/width {:cc [1 9] :in [0 127] :offset 265}
+   :delay-1/lr-ratio {:cc [1 10] :in [0 12] :offset 266} ;; TODO: Enum
+   :delay-1/slew-rate {:cc [1 11] :in [0 127] :offset 267}
+
+   :delay-2/time {:cc [1 12] :in [0 127] :offset 268}
+   :delay-2/time-sync {:cc [1 13] :in [0 35] :offset 269} ;; TODO: Enum
+   :delay-2/feedback {:cc [1 14] :in [0 127] :offset 270}
+   :delay-2/width {:cc [1 15] :in [0 127] :offset 271}
+   :delay-2/lr-ratio {:cc [1 16] :in [0 12] :offset 272} ;; TODO: Enum
+   :delay-2/slew-rate {:cc [1 17] :in [0 127] :offset 273}
+
+   :reverb-1/type {:cc [1 18] :in [0 5] :enum ["Chamber" "SmlRoom" "Lrgroom" "SmlHall" "LrgHall" "GrtHall"] :offset 274}
+   :reverb-1/decay {:cc [1 19] :in [0 127] :offset 275}
+   :reverb-1/damping {:cc [1 20] :in [0 127] :offset 276}
+
+   :reverb-2/type {:cc [1 21] :in [0 5] :enum ["Chamber" "SmlRoom" "Lrgroom" "SmlHall" "LrgHall" "GrtHall"] :offset 277}
+   :reverb-2/decay {:cc [1 22] :in [0 127] :offset 278}
+   :reverb-2/damping {:cc [1 23] :in [0 127] :offset 279}
+
+   :chorus-1/type {:cc [1 24] :in [0 1] :enum ["Phaser" "Chorus"] :offset 280}
+   :chorus-1/rate {:cc [1 25] :in [0 127] :offset 281}
+   :chorus-1/rate-sync {:cc [1 26] :in [0 35] :offset 282} ;; TODO: Enum
+   :chorus-1/feedback {:cc [1 27] :in [0 127] :out [-64 63] :offset 283}
+   :chorus-1/mod-depth {:cc [1 28] :in [0 127] :offset 284}
+   :chorus-1/delay {:cc [1 29] :in [0 127] :offset 285}
+
+   :chorus-2/type {:cc [1 30] :in [0 1] :enum ["Phaser" "Chorus"] :offset 286}
+   :chorus-2/rate {:cc [1 31] :in [0 127] :offset 287}
    :chorus-2/rate-sync {:cc [1 32] :in [0 35] :offset 288} ;; TODO: Enum
    :chorus-2/feedback {:cc [1 33] :in [0 127] :out [-64 63] :offset 289}
-   :chorus-2/mod-depth {:cc [1 34] :in [0 127]}
-   :chorus-2/delay {:cc [1 35] :in [0 127]}
-
-   :chorus-3/type {:cc [1 36] :in [0 1] :enum ["Phaser" "Chorus"]}
-   :chorus-3/rate {:cc [1 37] :in [0 127]}
-   :chorus-3/rate-sync {:cc [1 38] :in [0 35]} ;; TODO: Enum
-   :chorus-3/feedback {:cc [1 39] :in [0 127] :out [-64 63]}
-   :chorus-3/mod-depth {:cc [1 40] :in [0 127]}
-   :chorus-3/delay {:cc [1 41] :in [0 127]}
-
-   :chorus-4/type {:cc [1 42] :in [0 1] :enum ["Phaser" "Chorus"]}
-   :chorus-4/rate {:cc [1 43] :in [0 127]}
-   :chorus-4/rate-sync {:cc [1 44] :in [0 35]} ;; TODO: Enum
-   :chorus-4/feedback {:cc [1 45] :in [0 127] :out [-64 63]}
-   :chorus-4/mod-depth {:cc [1 46] :in [0 127]}
-   :chorus-4/delay {:cc [1 47] :in [0 127]}
+   :chorus-2/mod-depth {:cc [1 34] :in [0 127] :offset 290}
+   :chorus-2/delay {:cc [1 35] :in [0 127] :offset 291}
+
+   :chorus-3/type {:cc [1 36] :in [0 1] :enum ["Phaser" "Chorus"] :offset 292}
+   :chorus-3/rate {:cc [1 37] :in [0 127] :offset 293}
+   :chorus-3/rate-sync {:cc [1 38] :in [0 35] :offset 294} ;; TODO: Enum
+   :chorus-3/feedback {:cc [1 39] :in [0 127] :out [-64 63] :offset 295}
+   :chorus-3/mod-depth {:cc [1 40] :in [0 127] :offset 296}
+   :chorus-3/delay {:cc [1 41] :in [0 127] :offset 297}
+
+   :chorus-4/type {:cc [1 42] :in [0 1] :enum ["Phaser" "Chorus"] :offset 298}
+   :chorus-4/rate {:cc [1 43] :in [0 127] :offset 299}
+   :chorus-4/rate-sync {:cc [1 44] :in [0 35] :offset 300} ;; TODO: Enum
+   :chorus-4/feedback {:cc [1 45] :in [0 127] :out [-64 63] :offset 301}
+   :chorus-4/mod-depth {:cc [1 46] :in [0 127] :offset 302}
+   :chorus-4/delay {:cc [1 47] :in [0 127] :offset 303}

    :gator/on {:cc [0 122] :in [52 53] :enum ["Off" "On"]}
-   :gator/key-sync {:cc [0 122] :in [54 55] :enum ["FreeRun" "KeySync"]}
-   :gator/key-latch {:cc [0 122] :in [56 57] :enum ["LatchOff" "LatchOn"]}
+   :gator/key-sync {:cc [0 122] :in [54 55] :enum ["FreeRun" "KeySync"] :offset 304}
+   :gator/key-latch {:cc [0 122] :in [56 57] :enum ["LatchOff" "LatchOn"] :offset 304}
    :gator/rate-sync {:cc [1 49] :in [0 35]} ;; TODO: Enum
    :gator/mode {:cc [1 50] :in [0 5] :enum ["Mono16" "MonoAlt1" "MonoAlt2" "Stereo16" "SterAlt" "SterAlt2"]}
-   :gator/edge-slew {:cc [1 52] :in [0 127]}
-   :gator/hold {:cc [1 53] :in [0 127]}
+   :gator/edge-slew {:cc [1 52] :in [0 127] :offset 308}
+   :gator/hold {:cc [1 53] :in [0 127] :offset 309}
    :gator/lr-delay {:cc [1 54] :in [0 127] :out [-64 63]}
-   :gator/level-1 {:cc [5 0] :in [0 7]}
-   :gator/level-2 {:cc [5 1] :in [0 7]}
-   :gator/level-3 {:cc [5 2] :in [0 7]}
-   :gator/level-4 {:cc [5 3] :in [0 7]}
-   :gator/level-5 {:cc [5 4] :in [0 7]}
-   :gator/level-6 {:cc [5 5] :in [0 7]}
-   :gator/level-7 {:cc [5 6] :in [0 7]}
-   :gator/level-8 {:cc [5 7] :in [0 7]}
-   :gator/level-9 {:cc [5 8] :in [0 7]}
-   :gator/level-10 {:cc [5 9] :in [0 7]}
-   :gator/level-11 {:cc [5 10] :in [0 7]}
-   :gator/level-12 {:cc [5 11] :in [0 7]}
-   :gator/level-13 {:cc [5 12] :in [0 7]}
-   :gator/level-14 {:cc [5 13] :in [0 7]}
-   :gator/level-15 {:cc [5 14] :in [0 7]}
-   :gator/level-16 {:cc [5 15] :in [0 7]}
-   :gator/level-17 {:cc [5 16] :in [0 7]}
-   :gator/level-18 {:cc [5 17] :in [0 7]}
-   :gator/level-19 {:cc [5 18] :in [0 7]}
-   :gator/level-20 {:cc [5 19] :in [0 7]}
-   :gator/level-21 {:cc [5 20] :in [0 7]}
-   :gator/level-22 {:cc [5 21] :in [0 7]}
-   :gator/level-23 {:cc [5 22] :in [0 7]}
-   :gator/level-24 {:cc [5 23] :in [0 7]}
-   :gator/level-25 {:cc [5 24] :in [0 7]}
-   :gator/level-26 {:cc [5 25] :in [0 7]}
-   :gator/level-27 {:cc [5 26] :in [0 7]}
-   :gator/level-28 {:cc [5 27] :in [0 7]}
-   :gator/level-29 {:cc [5 28] :in [0 7]}
+   :gator/level-1 {:cc [5 0] :in [0 7] :offset 451}
+   :gator/level-2 {:cc [5 1] :in [0 7] :offset 452}
+   :gator/level-3 {:cc [5 2] :in [0 7] :offset 453}
+   :gator/level-4 {:cc [5 3] :in [0 7] :offset 454}
+   :gator/level-5 {:cc [5 4] :in [0 7] :offset 455}
+   :gator/level-6 {:cc [5 5] :in [0 7] :offset 456}
+   :gator/level-7 {:cc [5 6] :in [0 7] :offset 457}
+   :gator/level-8 {:cc [5 7] :in [0 7] :offset 458}
+   :gator/level-9 {:cc [5 8] :in [0 7] :offset 459}
+   :gator/level-10 {:cc [5 9] :in [0 7] :offset 460}
+   :gator/level-11 {:cc [5 10] :in [0 7] :offset 461}
+   :gator/level-12 {:cc [5 11] :in [0 7] :offset 462}
+   :gator/level-13 {:cc [5 12] :in [0 7] :offset 463}
+   :gator/level-14 {:cc [5 13] :in [0 7] :offset 464}
+   :gator/level-15 {:cc [5 14] :in [0 7] :offset 465}
+   :gator/level-16 {:cc [5 15] :in [0 7] :offset 466}
+   :gator/level-17 {:cc [5 16] :in [0 7] :offset 467}
+   :gator/level-18 {:cc [5 17] :in [0 7] :offset 468}
+   :gator/level-19 {:cc [5 18] :in [0 7] :offset 469}
+   :gator/level-20 {:cc [5 19] :in [0 7] :offset 470}
+   :gator/level-21 {:cc [5 20] :in [0 7] :offset 471}
+   :gator/level-22 {:cc [5 21] :in [0 7] :offset 472}
+   :gator/level-23 {:cc [5 22] :in [0 7] :offset 473}
+   :gator/level-24 {:cc [5 23] :in [0 7] :offset 474}
+   :gator/level-25 {:cc [5 24] :in [0 7] :offset 475}
+   :gator/level-26 {:cc [5 25] :in [0 7] :offset 476}
+   :gator/level-27 {:cc [5 26] :in [0 7] :offset 477}
+   :gator/level-28 {:cc [5 27] :in [0 7] :offset 478}
+   :gator/level-29 {:cc [5 28] :in [0 7] :offset 479}
    :gator/level-30 {:cc [5 29] :in [0 7] :offset 480}
-   :gator/level-31 {:cc [5 30] :in [0 7]}
-   :gator/level-32 {:cc [5 31] :in [0 7] :offset 481}
-
-   :vocoder/on {:cc [0 122] :in [58 59] :enum ["Off" "On"]}
-   :vocoder/sibilance-type {:cc [0 122] :in [60 61] :enum ["HiPass" "Noise"]}
+   :gator/level-31 {:cc [5 30] :in [0 7] :offset 481}
+   :gator/level-32 {:cc [5 31] :in [0 7] :offset 482}
+
+   ;; TODO: Encoding
+   :vocoder/on {:cc [0 122] :in [58 59] :enum ["Off" "On"] :offset 311}
+   :vocoder/sibilance-type {:cc [0 122] :in [60 61] :enum ["HiPass" "Noise"] :offset 311}
    :vocoder/freeze {:cc [0 122] :in [62 63] :enum ["UnFreeze" "Freeze"]}
-   :vocoder/all-max {:cc [0 122] :in [64 65] :enum ["AllMax Off" "AllMax On"]}
-   :vocoder/vocoder-input {:cc [0 122] :in [66 67] :enum ["Audio In" "VTOutput"]}
-   :vocoder/width {:cc [1 57] :in [0 127]}
-   :vocoder/sibilance {:cc [1 58] :in [0 127]}
-   :vocoder/spec-shift {:cc [1 59] :in [0 127] :out [-64 63]}
-   :vocoder/spec-spread {:cc [1 60] :in [0 127] :out [-64 63]}
-   :vocoder/level {:cc [1 71] :in [0 127]}
-   :vocoder/carrier-level {:cc [1 72] :in [0 127]}
-   :vocoder/modulator-level {:cc [1 73] :in [0 127]}
-   :vocoder/resonance {:cc [1 74] :in [0 127]}
-   :vocoder/decay {:cc [1 75] :in [0 127]}
-   :vocoder/gate-treshold {:cc [1 76] :in [0 96] :out [-96 0]}
-   :vocoder/gate-release {:cc [1 77] :in [0 127]}
+   :vocoder/all-max {:cc [0 122] :in [64 65] :enum ["AllMax Off" "AllMax On"] :offset 311}
+   :vocoder/vocoder-input {:cc [0 122] :in [66 67] :enum ["Audio In" "VTOutput"] :offset 311}
+   :vocoder/width {:cc [1 57] :in [0 127] :offset 313}
+   :vocoder/sibilance {:cc [1 58] :in [0 127] :offset 314}
+   :vocoder/spec-shift {:cc [1 59] :in [0 127] :out [-64 63] :offset 315}
+   :vocoder/spec-spread {:cc [1 60] :in [0 127] :out [-64 63] :offset 316}
+   :vocoder/level {:cc [1 71] :in [0 127] :offset 327}
+   :vocoder/carrier-level {:cc [1 72] :in [0 127] :offset 328}
+   :vocoder/modulator-level {:cc [1 73] :in [0 127] :offset 329}
+   :vocoder/resonance {:cc [1 74] :in [0 127] :offset 330}
+   :vocoder/decay {:cc [1 75] :in [0 127] :offset 331}
+   :vocoder/gate-treshold {:cc [1 76] :in [0 96] :out [-96 0] :offset 332}
+   :vocoder/gate-release {:cc [1 77] :in [0 127] :offset 333}
    :vocoder/spectrum-level-1 {:cc [6 0] :in [0 127] :offset 0}
    :vocoder/spectrum-level-2 {:cc [6 1] :in [0 127] :offset 0}
    :vocoder/spectrum-level-3 {:cc [6 2] :in [0 127] :offset 0}
@@ -516,8 +517,8 @@
    :vocoder/spectrum-level-32 {:cc [6 31] :in [0 127] :offset 0}
    :vocoder/spectrum-resample {:cc [6 32] :in [1 1] :offset 0}

-   :chorder/transpose {:cc [1 78] :in [53 75] :out [-11 11]}
-   :chorder/on {:cc [1 79] :in [0 1] :enum ["Off" "On"]}
+   :chorder/transpose {:cc [1 78] :in [53 75] :out [-11 11] :offset 334}
+   :chorder/on {:cc [1 79] :in [0 1] :enum ["Off" "On"] :offset 335}
    ;; FIXME: Hangs
    :chorder/chorder-count {:cc [7 16] :in [0 10] :offset 0}
    ;; FIXME: is it 0-127, 0,127 or 0-1?
@@ -531,28 +532,24 @@
    :chorder/chorder-key-9 {:cc [7 24] :in [0 127] :offset 0}
    :chorder/chorder-key-10 {:cc [7 25] :in [0 127] :offset 0}

-   :vocal-tune/shift {:cc [1 80] :in [40 88] :out [-24 24]}
-   :vocal-tune/bend {:cc [1 81] :in [40 88] :out [-24 24]}
-   ;; NOTE: Collides with mod-matrix-9/source-1 (0-18) ?! doesn't collide with (0-11) in lfo-n/fade-mode
-   :vocal-tune/mode {:cc [1 123] :in [16 19] :enum ["Off" "Scale Correction" "KBCtrl" "Pitch"]}
-   ;; NOTE: Doesn't collide with (0-11) in lfo-n/fade-mode or (16-19)
-   :vocal-tune/insert {:cc [1 123] :in [25 27] :enum ["PreFilter" "PostFilter" "PreFx"]}
-   :vocal-tune/scale-type {:cc [2 56] :in [0 5] :enum ["Played" "Chromatic" "Major" "NatMinor" "HarMinor" "MelMinor"]}
-   :vocal-tune/scale-key {:cc [2 57] :in [0 11] :enum ["C" "C#" "D" "D#" "E" "F" "F#" "G" "G#" "A" "A#" "B"]}
-   :vocal-tune/correction-time {:cc [2 58] :in [0 127]}
-   :vocal-tune/level {:cc [2 59] :in [0 127]}
-   :vocal-tune/vibrato {:cc [2 60] :in [0 127]}
-   :vocal-tune/vibrato-mod-wheel {:cc [2 61] :in [0 127]}
-   :vocal-tune/vibrato-rate {:cc [2 62] :in [0 127]}
-
-   ;; TODO: Figure out the encoding @ 317
-   ;; FIXME: Modifying either `on` or `key-latch` changes both in the store because they share
-   ;; the `cc`. Make `::ui/control` action smarter about this
+   :vocal-tune/shift {:cc [1 80] :in [40 88] :out [-24 24] :offset 336}
+   :vocal-tune/bend {:cc [1 81] :in [40 88] :out [-24 24] :offset 337}
+   ;; FIXME: Encoding
+   :vocal-tune/mode {:cc [0 123] :in [16 19] :enum ["Off" "Scale Correction" "KBCtrl" "Pitch"] :offset 439}
+   :vocal-tune/insert {:cc [0 123] :in [25 27] :enum ["PreFilter" "PostFilter" "PreFx"] :offset 439}
+   :vocal-tune/scale-type {:cc [2 56] :in [0 5] :enum ["Played" "Chromatic" "Major" "NatMinor" "HarMinor" "MelMinor"] :offset 440}
+   :vocal-tune/scale-key {:cc [2 57] :in [0 11] :enum ["C" "C#" "D" "D#" "E" "F" "F#" "G" "G#" "A" "A#" "B"] :offset 441}
+   :vocal-tune/correction-time {:cc [2 58] :in [0 127] :offset 442}
+   :vocal-tune/level {:cc [2 59] :in [0 127] :offset 443}
+   :vocal-tune/vibrato {:cc [2 60] :in [0 127] :offset 444}
+   :vocal-tune/vibrato-mod-wheel {:cc [2 61] :in [0 127] :offset 445}
+   :vocal-tune/vibrato-rate {:cc [2 62] :in [0 127] :offset 446}
+
+   ;; FIXME: Encoding
    :arp/on {:cc [0 122] :in [46 47] :enum ["Off" "On"] :offset 317}
    :arp/key-latch {:cc [0 122] :in [50 51] :enum ["Latch Off" "Latch On"] :offset 317}
    :arp/octaves {:cc [1 62] :in [0 3] :out [1 4] :offset 318}
    :arp/rate-sync {:cc [1 63] :in [0 18] :enum arp-pattern-enum :offset 319}
-   ;; FIXME: This was detected at 320 AND 325?
    :arp/gate {:cc [1 64] :in [1 127] :offset 320}
    :arp/mode {:cc [1 65] :in [0 6] :enum ["Up" "Down" "UpDown" "UpDown2" "Played" "Random" "Chord"] :offset 321}
    :arp/pattern {:cc [1 66] :in [0 18] :enum arp-pattern-enum :offset 322}
@@ -561,9 +558,8 @@
    ;; :arp/mini-nova {:cc [127 127] :in [0 1] :offset 0}
    :arp/length {:cc [60 40] :in [2 8] :offset 325}

-   ;; FIXME: step 1 was detected at 325?!
    ;; TODO: Figure out the encoding @ 326
-   :arp-1/step {:cc [60 32], :in [0 1], :offset 326},
+   :arp-1/step {:cc [60 32], :in [0 1], :offset 325},
    :arp-2/step {:cc [60 33], :in [0 1], :offset 326},
    :arp-3/step {:cc [60 34], :in [0 1], :offset 326},
    :arp-4/step {:cc [60 35], :in [0 1], :offset 326},
@@ -572,126 +568,126 @@
    :arp-7/step {:cc [60 38], :in [0 1], :offset 326},
    :arp-8/step {:cc [60 39], :in [0 1], :offset 326},

-   :mod-matrix-1/source-1 {:cc [1 83] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-1/source-2 {:cc [1 84] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-1/anim-trigger {:cc [1 85] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-1/depth {:cc [1 86] :in [0 127] :out [-64 63]}
-   :mod-matrix-1/destination {:cc [1 87] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-2/source-1 {:cc [1 88] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-2/source-2 {:cc [1 89] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-2/anim-trigger {:cc [1 90] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-2/depth {:cc [1 91] :in [0 127] :out [-64 63]}
-   :mod-matrix-2/destination {:cc [1 92] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-3/source-1 {:cc [1 93] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-3/source-2 {:cc [1 94] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-3/anim-trigger {:cc [1 95] :in [0 8] :enum anim-trigger-enum}
+   :mod-matrix-1/source-1 {:cc [1 83] :in [0 18] :enum mod-matrix-source-enum :offset 339}
+   :mod-matrix-1/source-2 {:cc [1 84] :in [0 18] :enum mod-matrix-source-enum :offset 340}
+   :mod-matrix-1/anim-trigger {:cc [1 85] :in [0 8] :enum anim-trigger-enum :offset 341}
+   :mod-matrix-1/depth {:cc [1 86] :in [0 127] :out [-64 63] :offset 342}
+   :mod-matrix-1/destination {:cc [1 87] :in [0 69] :offset 343} ;; TODO: Enum
+
+   :mod-matrix-2/source-1 {:cc [1 88] :in [0 18] :enum mod-matrix-source-enum :offset 344}
+   :mod-matrix-2/source-2 {:cc [1 89] :in [0 18] :enum mod-matrix-source-enum :offset 345}
+   :mod-matrix-2/anim-trigger {:cc [1 90] :in [0 8] :enum anim-trigger-enum :offset 346}
+   :mod-matrix-2/depth {:cc [1 91] :in [0 127] :out [-64 63] :offset 347}
+   :mod-matrix-2/destination {:cc [1 92] :in [0 69] :offset 348} ;; TODO: Enum
+
+   :mod-matrix-3/source-1 {:cc [1 93] :in [0 18] :enum mod-matrix-source-enum :offset 349}
+   :mod-matrix-3/source-2 {:cc [1 94] :in [0 18] :enum mod-matrix-source-enum :offset 350}
+   :mod-matrix-3/anim-trigger {:cc [1 95] :in [0 8] :enum anim-trigger-enum :offset 351}
    :mod-matrix-3/depth {:cc [1 96] :in [0 127] :out [-64 63] :offset 352}
    :mod-matrix-3/destination {:cc [1 97] :in [0 69] :offset 353} ;; TODO: Enum

-   :mod-matrix-4/source-1 {:cc [1 98] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-4/source-2 {:cc [1 99] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-4/anim-trigger {:cc [1 100] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-4/depth {:cc [1 101] :in [0 127] :out [-64 63]}
-   :mod-matrix-4/destination {:cc [1 102] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-5/source-1 {:cc [1 103] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-5/source-2 {:cc [1 104] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-5/anim-trigger {:cc [1 105] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-5/depth {:cc [1 106] :in [0 127] :out [-64 63]}
-   :mod-matrix-5/destination {:cc [1 107] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-6/source-1 {:cc [1 108] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-6/source-2 {:cc [1 109] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-6/anim-trigger {:cc [1 110] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-6/depth {:cc [1 111] :in [0 127] :out [-64 63]}
-   :mod-matrix-6/destination {:cc [1 112] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-7/source-1 {:cc [1 113] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-7/source-2 {:cc [1 114] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-7/anim-trigger {:cc [1 115] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-7/depth {:cc [1 116] :in [0 127] :out [-64 63]}
-   :mod-matrix-7/destination {:cc [1 117] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-8/source-1 {:cc [1 118] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-8/source-2 {:cc [1 119] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-8/anim-trigger {:cc [1 120] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-8/depth {:cc [1 121] :in [0 127] :out [-64 63]}
-   :mod-matrix-8/destination {:cc [1 122] :in [0 69]} ;; TODO: Enum
+   :mod-matrix-4/source-1 {:cc [1 98] :in [0 18] :enum mod-matrix-source-enum :offset 354}
+   :mod-matrix-4/source-2 {:cc [1 99] :in [0 18] :enum mod-matrix-source-enum :offset 355}
+   :mod-matrix-4/anim-trigger {:cc [1 100] :in [0 8] :enum anim-trigger-enum :offset 356}
+   :mod-matrix-4/depth {:cc [1 101] :in [0 127] :out [-64 63] :offset 357}
+   :mod-matrix-4/destination {:cc [1 102] :in [0 69] :offset 358} ;; TODO: Enum
+
+   :mod-matrix-5/source-1 {:cc [1 103] :in [0 18] :enum mod-matrix-source-enum :offset 359}
+   :mod-matrix-5/source-2 {:cc [1 104] :in [0 18] :enum mod-matrix-source-enum :offset 360}
+   :mod-matrix-5/anim-trigger {:cc [1 105] :in [0 8] :enum anim-trigger-enum :offset 361}
+   :mod-matrix-5/depth {:cc [1 106] :in [0 127] :out [-64 63] :offset 362}
+   :mod-matrix-5/destination {:cc [1 107] :in [0 69] :offset 363} ;; TODO: Enum
+
+   :mod-matrix-6/source-1 {:cc [1 108] :in [0 18] :enum mod-matrix-source-enum :offset 364}
+   :mod-matrix-6/source-2 {:cc [1 109] :in [0 18] :enum mod-matrix-source-enum :offset 365}
+   :mod-matrix-6/anim-trigger {:cc [1 110] :in [0 8] :enum anim-trigger-enum :offset 366}
+   :mod-matrix-6/depth {:cc [1 111] :in [0 127] :out [-64 63] :offset 367}
+   :mod-matrix-6/destination {:cc [1 112] :in [0 69] :offset 368} ;; TODO: Enum
+
+   :mod-matrix-7/source-1 {:cc [1 113] :in [0 18] :enum mod-matrix-source-enum :offset 369}
+   :mod-matrix-7/source-2 {:cc [1 114] :in [0 18] :enum mod-matrix-source-enum :offset 370}
+   :mod-matrix-7/anim-trigger {:cc [1 115] :in [0 8] :enum anim-trigger-enum :offset 371}
+   :mod-matrix-7/depth {:cc [1 116] :in [0 127] :out [-64 63] :offset 372}
+   :mod-matrix-7/destination {:cc [1 117] :in [0 69] :offset 373} ;; TODO: Enum
+
+   :mod-matrix-8/source-1 {:cc [1 118] :in [0 18] :enum mod-matrix-source-enum :offset 374}
+   :mod-matrix-8/source-2 {:cc [1 119] :in [0 18] :enum mod-matrix-source-enum :offset 375}
+   :mod-matrix-8/anim-trigger {:cc [1 120] :in [0 8] :enum anim-trigger-enum :offset 376}
+   :mod-matrix-8/depth {:cc [1 121] :in [0 127] :out [-64 63] :offset 377}
+   :mod-matrix-8/destination {:cc [1 122] :in [0 69] :offset 378} ;; TODO: Enum

    ;; FIXME: Does this really collide with lfo-n/fade-mode?!
-   :mod-matrix-9/source-1 {:cc [1 123] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-9/source-2 {:cc [1 124] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-9/anim-trigger {:cc [1 125] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-9/depth {:cc [1 126] :in [0 127] :out [-64 63]}
-   :mod-matrix-9/destination {:cc [1 127] :in [0 69]} ;; TODO: Enum
+   :mod-matrix-9/source-1 {:cc [1 123] :in [0 18] :enum mod-matrix-source-enum :offset 379}
+   :mod-matrix-9/source-2 {:cc [1 124] :in [0 18] :enum mod-matrix-source-enum :offset 380}
+   :mod-matrix-9/anim-trigger {:cc [1 125] :in [0 8] :enum anim-trigger-enum :offset 381}
+   :mod-matrix-9/depth {:cc [1 126] :in [0 127] :out [-64 63] :offset 382}
+   :mod-matrix-9/destination {:cc [1 127] :in [0 69] :offset 383} ;; TODO: Enum

    :mod-matrix-10/source-1 {:cc [2 0] :in [0 18] :enum mod-matrix-source-enum :offset 384}
    :mod-matrix-10/source-2 {:cc [2 1] :in [0 18] :enum mod-matrix-source-enum :offset 385}
-   :mod-matrix-10/anim-trigger {:cc [2 2] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-10/depth {:cc [2 3] :in [0 127] :out [-64 63]}
-   :mod-matrix-10/destination {:cc [2 4] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-11/source-1 {:cc [2 5] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-11/source-2 {:cc [2 6] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-11/anim-trigger {:cc [2 7] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-11/depth {:cc [2 8] :in [0 127] :out [-64 63]}
-   :mod-matrix-11/destination {:cc [2 9] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-12/source-1 {:cc [2 10] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-12/source-2 {:cc [2 11] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-12/anim-trigger {:cc [2 12] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-12/depth {:cc [2 13] :in [0 127] :out [-64 63]}
-   :mod-matrix-12/destination {:cc [2 14] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-13/source-1 {:cc [2 15] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-13/source-2 {:cc [2 16] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-13/anim-trigger {:cc [2 17] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-13/depth {:cc [2 18] :in [0 127] :out [-64 63]}
-   :mod-matrix-13/destination {:cc [2 19] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-14/source-1 {:cc [2 20] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-14/source-2 {:cc [2 21] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-14/anim-trigger {:cc [2 22] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-14/depth {:cc [2 23] :in [0 127] :out [-64 63]}
-   :mod-matrix-14/destination {:cc [2 24] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-15/source-1 {:cc [2 25] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-15/source-2 {:cc [2 26] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-15/anim-trigger {:cc [2 27] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-15/depth {:cc [2 28] :in [0 127] :out [-64 63]}
-   :mod-matrix-15/destination {:cc [2 29] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-16/source-1 {:cc [2 30] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-16/source-2 {:cc [2 31] :in [0 18] :enum mod-matrix-source-enum}
+   :mod-matrix-10/anim-trigger {:cc [2 2] :in [0 8] :enum anim-trigger-enum :offset 386}
+   :mod-matrix-10/depth {:cc [2 3] :in [0 127] :out [-64 63] :offset 387}
+   :mod-matrix-10/destination {:cc [2 4] :in [0 69] :offset 388} ;; TODO: Enum
+
+   :mod-matrix-11/source-1 {:cc [2 5] :in [0 18] :enum mod-matrix-source-enum :offset 389}
+   :mod-matrix-11/source-2 {:cc [2 6] :in [0 18] :enum mod-matrix-source-enum :offset 390}
+   :mod-matrix-11/anim-trigger {:cc [2 7] :in [0 8] :enum anim-trigger-enum :offset 391}
+   :mod-matrix-11/depth {:cc [2 8] :in [0 127] :out [-64 63] :offset 392}
+   :mod-matrix-11/destination {:cc [2 9] :in [0 69] :offset 393} ;; TODO: Enum
+
+   :mod-matrix-12/source-1 {:cc [2 10] :in [0 18] :enum mod-matrix-source-enum :offset 394}
+   :mod-matrix-12/source-2 {:cc [2 11] :in [0 18] :enum mod-matrix-source-enum :offset 395}
+   :mod-matrix-12/anim-trigger {:cc [2 12] :in [0 8] :enum anim-trigger-enum :offset 396}
+   :mod-matrix-12/depth {:cc [2 13] :in [0 127] :out [-64 63] :offset 397}
+   :mod-matrix-12/destination {:cc [2 14] :in [0 69] :offset 398} ;; TODO: Enum
+
+   :mod-matrix-13/source-1 {:cc [2 15] :in [0 18] :enum mod-matrix-source-enum :offset 399}
+   :mod-matrix-13/source-2 {:cc [2 16] :in [0 18] :enum mod-matrix-source-enum :offset 400}
+   :mod-matrix-13/anim-trigger {:cc [2 17] :in [0 8] :enum anim-trigger-enum :offset 401}
+   :mod-matrix-13/depth {:cc [2 18] :in [0 127] :out [-64 63] :offset 402}
+   :mod-matrix-13/destination {:cc [2 19] :in [0 69] :offset 403} ;; TODO: Enum
+
+   :mod-matrix-14/source-1 {:cc [2 20] :in [0 18] :enum mod-matrix-source-enum :offset 404}
+   :mod-matrix-14/source-2 {:cc [2 21] :in [0 18] :enum mod-matrix-source-enum :offset 405}
+   :mod-matrix-14/anim-trigger {:cc [2 22] :in [0 8] :enum anim-trigger-enum :offset 406}
+   :mod-matrix-14/depth {:cc [2 23] :in [0 127] :out [-64 63] :offset 407}
+   :mod-matrix-14/destination {:cc [2 24] :in [0 69] :offset 408} ;; TODO: Enum
+
+   :mod-matrix-15/source-1 {:cc [2 25] :in [0 18] :enum mod-matrix-source-enum :offset 409}
+   :mod-matrix-15/source-2 {:cc [2 26] :in [0 18] :enum mod-matrix-source-enum :offset 410}
+   :mod-matrix-15/anim-trigger {:cc [2 27] :in [0 8] :enum anim-trigger-enum :offset 411}
+   :mod-matrix-15/depth {:cc [2 28] :in [0 127] :out [-64 63] :offset 412}
+   :mod-matrix-15/destination {:cc [2 29] :in [0 69] :offset 413} ;; TODO: Enum
+
+   :mod-matrix-16/source-1 {:cc [2 30] :in [0 18] :enum mod-matrix-source-enum :offset 414}
+   :mod-matrix-16/source-2 {:cc [2 31] :in [0 18] :enum mod-matrix-source-enum :offset 415}
    :mod-matrix-16/anim-trigger {:cc [2 32] :in [0 8] :enum anim-trigger-enum :offset 416}
    :mod-matrix-16/depth {:cc [2 33] :in [0 127] :out [-64 63] :offset 417}
-   :mod-matrix-16/destination {:cc [2 34] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-17/source-1 {:cc [2 35] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-17/source-2 {:cc [2 36] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-17/anim-trigger {:cc [2 37] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-17/depth {:cc [2 38] :in [0 127] :out [-64 63]}
-   :mod-matrix-17/destination {:cc [2 39] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-18/source-1 {:cc [2 40] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-18/source-2 {:cc [2 41] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-18/anim-trigger {:cc [2 42] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-18/depth {:cc [2 43] :in [0 127] :out [-64 63]}
-   :mod-matrix-18/destination {:cc [2 44] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-19/source-1 {:cc [2 45] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-19/source-2 {:cc [2 46] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-19/anim-trigger {:cc [2 47] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-19/depth {:cc [2 48] :in [0 127] :out [-64 63]}
-   :mod-matrix-19/destination {:cc [2 49] :in [0 69]} ;; TODO: Enum
-
-   :mod-matrix-20/source-1 {:cc [2 50] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-20/source-2 {:cc [2 51] :in [0 18] :enum mod-matrix-source-enum}
-   :mod-matrix-20/anim-trigger {:cc [2 52] :in [0 8] :enum anim-trigger-enum}
-   :mod-matrix-20/depth {:cc [2 53] :in [0 127] :out [-64 63]}
-   :mod-matrix-20/destination {:cc [2 54] :in [0 69]} ;; TODO: Enum
+   :mod-matrix-16/destination {:cc [2 34] :in [0 69] :offset 418} ;; TODO: Enum
+
+   :mod-matrix-17/source-1 {:cc [2 35] :in [0 18] :enum mod-matrix-source-enum :offset 419}
+   :mod-matrix-17/source-2 {:cc [2 36] :in [0 18] :enum mod-matrix-source-enum :offset 420}
+   :mod-matrix-17/anim-trigger {:cc [2 37] :in [0 8] :enum anim-trigger-enum :offset 421}
+   :mod-matrix-17/depth {:cc [2 38] :in [0 127] :out [-64 63] :offset 422}
+   :mod-matrix-17/destination {:cc [2 39] :in [0 69] :offset 423} ;; TODO: Enum
+
+   :mod-matrix-18/source-1 {:cc [2 40] :in [0 18] :enum mod-matrix-source-enum :offset 424}
+   :mod-matrix-18/source-2 {:cc [2 41] :in [0 18] :enum mod-matrix-source-enum :offset 425}
+   :mod-matrix-18/anim-trigger {:cc [2 42] :in [0 8] :enum anim-trigger-enum :offset 426}
+   :mod-matrix-18/depth {:cc [2 43] :in [0 127] :out [-64 63] :offset 427}
+   :mod-matrix-18/destination {:cc [2 44] :in [0 69] :offset 428} ;; TODO: Enum
+
+   :mod-matrix-19/source-1 {:cc [2 45] :in [0 18] :enum mod-matrix-source-enum :offset 429}
+   :mod-matrix-19/source-2 {:cc [2 46] :in [0 18] :enum mod-matrix-source-enum :offset 430}
+   :mod-matrix-19/anim-trigger {:cc [2 47] :in [0 8] :enum anim-trigger-enum :offset 431}
+   :mod-matrix-19/depth {:cc [2 48] :in [0 127] :out [-64 63] :offset 432}
+   :mod-matrix-19/destination {:cc [2 49] :in [0 69] :offset 433} ;; TODO: Enum
+
+   :mod-matrix-20/source-1 {:cc [2 50] :in [0 18] :enum mod-matrix-source-enum :offset 434}
+   :mod-matrix-20/source-2 {:cc [2 51] :in [0 18] :enum mod-matrix-source-enum :offset 435}
+   :mod-matrix-20/anim-trigger {:cc [2 52] :in [0 8] :enum anim-trigger-enum :offset 436}
+   :mod-matrix-20/depth {:cc [2 53] :in [0 127] :out [-64 63] :offset 437}
+   :mod-matrix-20/destination {:cc [2 54] :in [0 69] :offset 438} ;; TODO: Enum

    :tweaks/assignment-1 {:cc [4 0] :in [0 125] :offset 0} ;; TODO: Enum
    :tweaks/assignment-2 {:cc [4 1] :in [0 125] :offset 0} ;; TODO: Enum


Add io.aviso.rook.async/timed-out?

Add io.aviso.rook.async/timed-out?

Previously added to toolchest.

--- src/io/aviso/rook/async.clj
+++ src/io/aviso/rook/async.clj
@@ -25,7 +25,7 @@
     The delegated handler should be invoked inside a [[safe-go]] block, so that the result from the handler
     can be obtained without blocking."
   (:require io.aviso.rook.internals
-            [clojure.core.async :refer [chan go >! <! <!! >!! thread put! take! close!]]
+            [clojure.core.async :as async :refer [chan go >! <! <!! >!! thread put! take! close!]]
             [io.aviso.toolchest.exceptions :refer [to-message]]
             ring.middleware.params
             ring.middleware.keyword-params
@@ -127,3 +127,13 @@
                    (fn [response]
                      (put! response-ch (rv/ensure-matching-response response (:function metadata) responses))))
             response-ch))))))
+
+(defn timed-out?
+  "Checks if timeout-ch is closed. ATTN: if applied to a non-timeout
+  channel, will consume and discard a single value from the channel's
+  buffer if there is one."
+  [timeout-ch]
+  (let [sentinel-ch (doto (async/chan 1)
+                      (async/>!! :sentinel))
+        [_ ch] (async/alts!! [timeout-ch sentinel-ch] :priority true)]
+    (identical? ch timeout-ch)))


gotry block

gotry block

--- src/name_bazaar/server/api.cljs
+++ src/name_bazaar/server/api.cljs
@@ -16,27 +16,32 @@
       (select-keys [:path :ip :protocol :method :params :hostname :httpVersion :headers :url])))

 (api-server/reg-get!
- "/offerings"
- (fn [req res]
-   (let [parsed-req (trim-request (aget req "parsed"))]
-     (logging/info "Received request" {:request parsed-req} ::get-offerings)
-     (gotry
-      (if-let [database (state/db)]
-        (send-json! res (<! (db/search-offerings database (api-server/sanitized-query-params req))))
-        (-> res
-            (api-server/status 503)
-            (api-server/send "Service unavailiable")))))))
+  "/offerings"
+  (fn [req res]
+    (let [parsed-req (trim-request (aget req "parsed"))]
+      (logging/info "Received request" {:request parsed-req} ::get-offerings)
+      (gotry
+       (if-let [database (state/db)]
+         (send-json! res (<! (db/search-offerings database (api-server/sanitized-query-params req))))
+         (do
+           (logging/warn "Database is not initialized" ::get-offering-requests)
+           (-> res
+               (api-server/status 503)
+               (api-server/send "Service unavailiable"))))))))

 (api-server/reg-get!
- "/offering-requests"
- (fn [req res]
-   (let [parsed-req (trim-request (aget req "parsed"))]
-     (logging/info "Received request" {:request parsed-req} ::get-offering-requests)
-     (if-let [database (state/db)]
-       (send-json! res (<! (db/search-offering-requests (state/db) (api-server/sanitized-query-params req))))
-       (-> res
-           (api-server/status 503)
-           (api-server/send "Service unavailiable"))))))
+   "/offering-requests"
+   (fn [req res]
+     (let [parsed-req (trim-request (aget req "parsed"))]
+       (logging/info "Received request" {:request parsed-req} ::get-offering-requests)
+       (gotry
+        (if-let [database (state/db)]
+          (send-json! res (<! (db/search-offering-requests (state/db) (api-server/sanitized-query-params req))))
+          (do
+            (logging/warn "Database is not initialized" ::get-offering-requests)
+            (-> res
+                (api-server/status 503)
+                (api-server/send "Service unavailiable"))))))))

 (api-server/reg-route! :get
                        "/config/:key"


x1000 floor price

x1000 floor price

--- src/s7p/master/web.clj
+++ src/s7p/master/web.clj
@@ -125,7 +125,7 @@
     (let [req      {:req
                     {:id         (id-gen)
                      :site       (line 0)
-                     :floorPrice (if (= "NA" fp) nil (Integer. fp))
+                     :floorPrice (if (= "NA" fp) nil (* 1000 (Integer. fp)))
                      :device     (line 2)
                      :user       (line 3)
                      :test       @testing}


Decrease default heartbeat period, increase pub/sub timeouts.

--- src/onyx/information_model.cljc
+++ src/onyx/information_model.cljc
@@ -1055,7 +1055,7 @@
             {:doc "Number of ms an idle peer should wait before sending a heartbeat message, and checking whether other peers are alive. This should be smaller than `:onyx.peer/subscriber-liveness-timeout-ms` and `:onyx.peer/publisher-liveness-timeout-ms`."
              :type :integer
              :unit :millisecond
-             :default 5000
+             :default 1000
              :optional? true
              :added "0.10.0"}

@@ -1102,7 +1102,7 @@
             {:doc "Number of ms between heartbeats before a subscriber is determined to be dead."
              :type :integer
              :unit :millisecond
-             :default 10000
+             :default 20000
              :optional? true
              :added "0.10.0"}

@@ -1110,7 +1110,7 @@
             {:doc "Number of ms between heartbeats before a publisher is determined to be dead."
              :type :integer
              :unit :millisecond
-             :default 10000
+             :default 20000
              :optional? true
              :added "0.10.0"}


Add min-peer == max-peer restriction to information model

--- src/onyx/information_model.cljc
+++ src/onyx/information_model.cljc
@@ -196,7 +196,7 @@
              :type :keyword
              :choices [:kill :continue :recover]
              :tags [:aggregation :grouping :windows]
-             :restrictions ["`:onyx/min-peers` or `:onyx/n-peers` must also be defined for this catalog entry. If `:recover` is used, then `:onyx/max-peers` or `:onyx/n-peers`` must also be defined. "]
+             :restrictions ["`:onyx/min-peers` or `:onyx/n-peers` must also be defined for this catalog entry. If `:recover` is used, then `:onyx/max-peers` must be equal to `:onyx/min-peers`. "]
              :optionally-allowed-when ["`:onyx/type` is set to `:function` or `:output`"
                                        "`:onyx/group-by-key` or `:onyx/group-by-fn` is set."]
              :added "0.8.0"}


Removing the first

Removing the first

--- src/posthere/cljs/posthere.cljs
+++ src/posthere/cljs/posthere.cljs
@@ -78,7 +78,7 @@

 (defn header-table [result]
   (let [headers (js->clj (.-headers result))]
-    (.log js/console (first (keys headers)))
+    (.log js/console (keys headers))
     (reduce [] #(conj %1 (row-for %2 (get headers %2)) (keys headers)))))

 (hiccups/defhtml result-headers [result]


Cleaned up deployment library fileset.

Cleaned up deployment library fileset.

--- src/leiningen/appengine_prepare.clj
+++ src/leiningen/appengine_prepare.clj
@@ -34,7 +34,7 @@
                  (lancet/fileset
                   {:dir lib-dir
                    :includes "*"
-                   :excludes "dev,appengine*,servlet-api*,swank-clojure*,jetty*"}))
+                   :excludes "dev"}))
     (lancet/copy {:todir (.getPath target-lib-dir)}
                  (lancet/fileset
                   {:dir lib-dev-dir


revert some changes

revert some changes

--- src/om_bootstrap/nav.cljs
+++ src/om_bootstrap/nav.cljs
@@ -89,6 +89,7 @@
    [_]
    (let [{:keys [opts children]} (om/get-props owner)
          [bs props] (t/separate Nav opts {:bs-class "nav"})
+         classes {:navbar-collapse (:collapsible? bs)}
          ul-props {:ref "ul"
                    :class (d/class-set
                            (merge (t/bs-class-set bs)
@@ -100,7 +101,8 @@
      (if (and (:navbar? bs)
               (not (:collapsible? bs)))
        (d/ul (u/merge-props props ul-props) children)
-       (d/nav props (d/ul ul-props children))))))
+       (d/nav (u/merge-props props {:class (d/class-set classes)})
+              (d/ul ul-props children))))))

 (sm/defn nav :- t/Component
   [opts :- Nav & children]
@@ -128,10 +130,10 @@

 (defn render-toggle-button [owner bs]
   (let [handle-toggle (fn []
-                        (om/set-state! owner [:changing?] true)
                         (when-let [f (:on-toggle bs)]
-                          (f))
-                        (om/set-state! owner [:changing?] false)
+                          (om/set-state! owner [:changing?] true)
+                          (f)
+                          (om/set-state! owner [:changing?] false))
                         (om/update-state! owner [:nav-open?] not))
         tb (u/clone-with-props (:toggle-button bs)
                                {:class "navbar-toggle"
@@ -167,15 +169,14 @@
       (u/clone-with-props child prop-fn))))

 (defn render-navbar-child [owner child bs]
-  (let [nav-open? (om/get-state owner :nav-open?)
-        changing? (om/get-state owner :changing?)
+  (let [changing? (om/get-state owner :changing?)
         f (fn [props]
             (let [opts (:opts props)
                   collapsible? (when (:toggle-nav-key bs)
                                  (= (:key opts) (:toggle-nav-key bs)))
                   expanded? (and collapsible?
                                  (or (:nav-expanded? bs)
-                                     nav-open?))
+                                     (om/get-state owner :nav-open?)))
                   collapsed? (not expanded?)
                   base {:navbar? true
                         :class (d/class-set {:navbar-collapse collapsible?
@@ -211,10 +212,6 @@
              (when (or (:brand bs)
                        (:toggle-button bs)
                        (:toggle-nav-key bs))
-               ;;TODO: Think about `render-header`, and if brand and
-               ;;toggle button are the only things that would ever go
-               ;;in there. What if someone wants a brand, and some
-               ;;text?
                (render-header owner bs))
              (map #(render-navbar-child owner % bs) children))))))


Extract synth-tiles from build-tile

Extract synth-tiles from build-tile

This is to push the rand that pick the new tile number to the outside.

--- src/literate_2048/core.cljs
+++ src/literate_2048/core.cljs
@@ -350,12 +350,15 @@
 (defn build-tile
   "Returns a map with :val associated to val and :key to an unique keyword. If
    no val is supplied, it defaults to 2 most of the time but it might default to
-   4, also the key :new is mapped to true. Alternatively, when applied to two
-   tiles x and y, the result is the same as calling it with the sum of the tiles
-   :val and associng the key :src to a vector containing x and y."
+   4, also the key :new is mapped to true."
   ([] (assoc (build-tile (if (< (rand) 0.8) 2 4)) :new true))
-  ([val] {:val val :key (keyword (gensym ""))})
-  ([x y] (assoc (build-tile (+ (:val x) (:val y))) :src [x y])))
+  ([val] {:val val :key (keyword (gensym ""))}))
+
+(defn synth-tiles
+  "Builds a tile with the sum of the :val of x and y and assocs the
+  key :src to a vector containing x and y."
+  [x y]
+  (assoc (build-tile (+ (:val x) (:val y))) :src [x y]))

 ;; Before going any further, an implementation of the ITile protocol, presented
 ;; in section 'Tile synthesis', must be provided. The synthesis of two tiles
@@ -368,7 +371,7 @@
   (-synth? [this] (not= (:val this) 2048))
   (-synth [this other]
     (when (= (:val this) (:val other))
-      (build-tile this other))))
+      (synth-tiles this other))))

 ;; Apart from taking place in the computer's memory, all the events need to be
 ;; shown on the screen. We'll break every move in two phases, slide and reveal,


missing type hint

missing type hint

--- src/main/clojure/cljs/compiler.cljc
+++ src/main/clojure/cljs/compiler.cljc
@@ -171,7 +171,7 @@
      (nil? x) nil
      #?(:clj (map? x) :cljs (ana/cljs-map? x)) (emit x)
      #?(:clj (seq? x) :cljs (ana/cljs-seq? x)) (apply emits x)
-     #?(:clj (fn? x) :cljs (goog/isFunction x)) (x)
+     #?(:clj (fn? x) :cljs ^boolean (goog/isFunction x)) (x)
      :else (let [s (print-str x)]
              (when-not (nil? *source-map-data*)
                (swap! *source-map-data*


Work on frame grab code

Work on frame grab code

--- src/main/clojure/telegenic/core.clj
+++ src/main/clojure/telegenic/core.clj
@@ -1,3 +1,21 @@
 (ns telegenic.core
-  (:import [org.jcodec.api FrameGrab]))
+  (:import [org.jcodec.api FrameGrab])
+  (:import [java.io File])
+  (:import [java.awt.image BufferedImage])
+  (:import [org.jcodec.common.model Picture])
+  )

+(set! *warn-on-reflection* true)
+(set! *unchecked-math* true)
+
+(defprotocol PGetFrame
+  (get-frame [video frame-number]))
+
+(extend-protocol PGetFrame
+  String
+    (get-frame [s frame-number] (get-frame (File. s) frame-number))
+  File
+    (get-frame [file frame-number]
+      (let [^Picture nf (FrameGrab/getNativeFrame file (int frame-number))
+            bi (.toBufferedImage nf)]
+        bi)))


detecting search_type has to be before search for sr cmd to work

--- src/semtag_web/client/main.cljs
+++ src/semtag_web/client/main.cljs
@@ -172,14 +172,14 @@
       #(jq/after $text-field (view/generate-datalist %))
       :alert-fn console-error)

+    (when-let [search-type (util/param-value "search_type")]
+          (jq/attr
+            ($ (str "input[value=" search-type "]"))
+            :checked
+            true))
     (when-let [query (util/param-value "query")]
       (jq/val $text-field query)
-      (search-and-update-page))
-    (when-let [search-type (util/param-value "search_type")]
-      (jq/attr
-        ($ (str "input[value=" search-type "]"))
-        :checked
-        true))))
+      (search-and-update-page))))

 (defn ^:export entity-add []
   (home)


Refactor to share code between resumes

Refactor to share code between resumes

--- src/tomato/handler.clj
+++ src/tomato/handler.clj
@@ -41,20 +41,24 @@
         (send-m (str (:mode state) " 잠시 중단 되었습니다")))
       (send-m "중단할 세션이 없습니다"))))

-(defn handle-resume-session []
-  (let [state (get-state)]
-    (if (session-paused? state)
-      (let [elapsed (:elapsed state)
-            mode ((:mode state) modes)
-            during (- (:during mode) elapsed)]

-        (swap! state-atom assoc
-               :timer (set-timeout #(goto-x (:next mode)) during)
-               :interval (remaining-each-10s #(:message-id (get-state))))
-        (tomato.s3/reset! "state" {:mode    (:mode state)
-                                   :started (- (current-time) elapsed)})
-        (send-m "세션을 다시 시작합니다"))
-      (send-m "다시 시작할 세션이 없습니다"))))
+(defn resume [mode elapsed]
+  (let [remained (- (:during mode) elapsed)]
+
+    (swap! state-atom assoc
+           :timer (set-timeout #(goto-x (:next mode)) remained)
+           :interval (remaining-each-10s #(get-state)))
+    (send-m "세션을 다시 시작합니다")))
+
+
+(defn handle-resume-session [state]
+  (if-not (session-paused? state)
+    (send-m "다시 시작할 세션이 없습니다")
+    (let [elapsed (:elapsed state)
+          mode ((:mode state) modes)]
+      (resume mode elapsed)
+      (tomato.s3/reset! "state" {:mode    (:mode state)
+                                 :started (- (current-time) elapsed)}))))

 (defhandler bot-api
             (command "go" [] (handle-start-session))
@@ -62,17 +66,9 @@
             (command "count" [] (handle-send-counted @counted))
             (command "cancel" [] (handle-cancel-session))
             (command "pause" [] (handle-pause-session))
-            (command "resume" [] (handle-resume-session)))
+            (command "resume" [] (handle-resume-session (get-state))))

 (def channel (atom nil))
-
-(defn resume [mode elapsed]
-  (let [remained (- (:during mode) elapsed)]
-
-    (swap! state-atom assoc
-           :timer (set-timeout #(goto-x (:next mode)) remained)
-           :interval (remaining-each-10s #(:message-id (get-state))))
-    (send-m "세션을 다시 시작합니다")))

 (defn start []
   (do (reset! channel (p/start (config/get :token) bot-api))


remove dead code

remove dead code

--- modules/reitit-core/src/reitit/coercion.cljc
+++ modules/reitit-core/src/reitit/coercion.cljc
@@ -27,13 +27,6 @@

 (defn error? [x]
   (instance? CoercionError x))
-
-;;
-;; api-docs
-;;
-
-#_(defn get-apidocs [coercion spec info]
-    (protocol/get-apidocs coercion spec info))

 ;;
 ;; coercer


Scroll to the end of the chat

Scroll to the end of the chat

--- src/mobile_patient/screen/chat.cljs
+++ src/mobile_patient/screen/chat.cljs
@@ -119,15 +119,18 @@

 (defn ChatScreen [_]
   (let [this (r/current-component)
-        input (atom nil)]
+        input (atom nil)
+        lv (atom nil)]
     (fn [_]
       (let [messages (subscribe [:messages])
             source (map #(r/atom %) @messages)]
         [ui/view {:style {:flex 1
                           :background-color "#f4f4f4"}}
          [ui/list-view {:style {:flex 1}
-                        :enableEmptySections true
+                        :enableEmptySections true
+                        :on-content-size-change #(some-> @lv .scrollToEnd)
                         :dataSource (.cloneWithRows ds (clj->js source))
+                        :ref #(reset! lv %)
                         :render-row (fn [row]
                                       (r/create-element
                                        chat-message-row-comp


:sparkles: Minor improvement on http client.

--- backend/src/uxbox/util/http.clj
+++ backend/src/uxbox/util/http.clj
@@ -20,5 +20,7 @@
     (http/get url nil opts')))

 (defn send!
-  [req]
-  (http/send req {:client @default-client :as :string}))
+  ([req]
+   (http/send req {:client @default-client :as :string}))
+  ([req opts]
+   (http/send req (merge {:client @default-client :as :string} opts))))


init es by default

init es by default

--- data/celestial/fixtures/populate.clj
+++ data/celestial/fixtures/populate.clj
@@ -64,9 +64,8 @@
   ([] (re-initlize false))
   ([clear-es]
    (c/initilize-puny)
-   (when clear-es
-     (es/clear)
-     (es/initialize))
+   (when clear-es (es/clear))
+   (es/initialize)
    (red/clear-all)))

 (defn populate-all


Fix regression: argument info was not extracted.

--- src/cli4clj/cli.clj
+++ src/cli4clj/cli.clj
@@ -430,8 +430,7 @@
   (let []
     `(let [~'__options (atom {})
            ~'__alt-scroll-wrtr (atom nil)
-           user-options# ~user-options
-           options-with-args-info# (add-args-info user-options#)
+           options-with-args-info# (add-args-info-m ~user-options)
            options# (assoc
                       (get-cli-opts options-with-args-info#)
                       :calling-ns ~*ns*)]


Fix artifact download in case of basic auth or broken Go setup

--- scripts/gosync.clj
+++ scripts/gosync.clj
@@ -143,6 +143,11 @@
       (list (:url file-node))
       [])))

+(defn replace-host-part-for-basic-auth [url]
+  ;; Replace host part with go url supplied by user
+  ;; Also works around broken Go domain setup
+  (clojure.string/replace url #"https?://[^/]+/go" go-url))
+
 (defn xml-artifacts-for-job-run [{pipeline-name :pipelineName
                                   pipeline-run :pipelineRun
                                   stage-name :stageName
@@ -150,7 +155,8 @@
                                   job-name :jobName}]
   (let [artifacts-url (format "/files/%s/%s/%s/%s/%s.json" pipeline-name pipeline-run stage-name stage-run job-name)
         file-tree (get-json artifacts-url)]
-    (mapcat filter-xml-files file-tree)))
+    (map replace-host-part-for-basic-auth
+         (mapcat filter-xml-files file-tree))))

 (defn augment-job-instance-with-junit-xml [job-instance]
   (if-let [xml-file-url (first (xml-artifacts-for-job-run job-instance))]


load_all.clj: added www.content-pages

load_all.clj: added www.content-pages

--- src/org/altlaw/load_all.clj
+++ src/org/altlaw/load_all.clj
@@ -16,4 +16,5 @@
    org.altlaw.util.zip

    org.altlaw.www.render
+   org.altlaw.www.content-pages
 ))


refactor extracotrs spec

refactor extracotrs spec

--- src/synthesis_crawlers/core.clj
+++ src/synthesis_crawlers/core.clj
@@ -30,7 +30,7 @@
 (s/def ::container-extractor string?)
 (s/def ::complete-attr-extractor (s/map-of keyword? string?))
 (s/def ::text string?)
-(s/def ::extractors (s/map-of ::container-extractor ::attr-extractor))
+(s/def ::extractor (s/map-of ::container-extractor ::attr-extractor))
 (s/def ::complete-extractor (s/map-of ::container-extractor
                                       ::complete-attr-extractor))
 (defn build-selector [attribute container-expr attr-expr]
@@ -49,7 +49,7 @@
   (select-keys attr-extractors (filter #(get attr-extractors %)  (keys attr-extractors))))

 (s/fdef build-selectors
-        :ars (s/cat :extractors ::extractors))
+        :ars (s/cat :extractors ::extractor))
 (defn build-selectors
   [extractors]
   (let [built (for [[container attr-extractors] extractors
@@ -60,7 +60,7 @@
             (map first (map seq built)))))

 (s/fdef extract
-        :args (s/cat :text ::text :extractors ::extractors)
+        :args (s/cat :text ::text :extractors ::extractor)
         :ret (s/map-of keyword? set?))
 (defn extract
   [text extractors]


remove comment

remove comment

--- src/synthesis_crawlers/core.clj
+++ src/synthesis_crawlers/core.clj
@@ -27,7 +27,6 @@
   [extractor crawled-set]
   (crawled-set extractor))

-;; TODO return nil if it failed to access the specifined url
 (defn get-page
   "gets the specified web page and return its body"
   [url]
@@ -109,6 +108,9 @@
   [url root-url pattern to-be-crawled crawled-pages]
   (lazy-seq
     (cons
-      (let [matched-links  (filter some? (map #(let [found (re-seq pattern %)] (when found (first found))) (extract-links root-url (get-page url))))]
-        matched-links)
+      (let [matched-links  (filter some? (map #(let [found (re-seq pattern %)] (when found (first found))) (extract-links root-url (get-page url))))
+            uncrawled-links (filter #(not (crawled-pages %)) matched-links)]
+        uncrawled-links)
       nil)))
+
+#_(filter #(#{2} %)  [2 45 5])


Some refactoring to make code clearer.

Some refactoring to make code clearer.

--- src/vacation2/main.clj
+++ src/vacation2/main.clj
@@ -72,6 +72,9 @@
                      :n-relations    (:relations options)
                      :n-queries      (:queries options)}]
         (log "options: " options)
+        (when (not= (rem (:n-reservations options) (:n-customers options)) 0)
+          (println "WARNING: number of reservations is not divisible by number"
+            "of customers."))
         options)
       nil)))

@@ -145,6 +148,13 @@

 ; MAIN

+(defn- log-data [{:keys [reservations cars flights rooms]}]
+  "Write `data` to log."
+  (log "reservations:" reservations)
+  (log "cars:" cars)
+  (log "flights:" flights)
+  (log "rooms:" rooms))
+
 (defn -main [& args]
   "Main function. `args` should be a list of command line arguments."
   (when-let [options (parse-args args)]
@@ -155,20 +165,12 @@
             (map #(spawn customer-behavior % data options) (range n-customers))
           done-promises
             (repeatedly n-reservations promise)]
-      (when (not= (rem n-reservations n-customers) 0)
-        (println "WARNING: number of reservations is not divisible by number"
-          "of customers."))
-      (log "reservations:" reservations)
-      (log "cars:" cars)
-      (log "flights:" flights)
-      (log "rooms:" rooms)
-      (doseq [[customer reservation done?] (zip (cycle customer-actors) reservations done-promises)]
+      (log-data data)
+      (doseq [[customer reservation done?]
+                (zip (cycle customer-actors) reservations done-promises)]
         (send customer reservation done?))
       (doseq [done? done-promises]
         (deref done?))
-      (log "reservations:" reservations)
-      (log "cars:" cars)
-      (log "flights:" flights)
-      (log "rooms:" rooms)))
+      (log-data data)))
   (Thread/sleep 1000) ; XXX
   (shutdown-agents))


introduce ring.middleware.stacktrace/wrap-stacktrace-log.

wrap-stacktrace-log logs formatted stacktraces to *err* and then rethrows. wrap-stacktrace now uses this to augment the returned web response. The previous web-only behavior is available with wrap-stacktrace-web.

--- ring-devel/src/ring/middleware/stacktrace.clj
+++ ring-devel/src/ring/middleware/stacktrace.clj
@@ -1,9 +1,20 @@
 (ns ring.middleware.stacktrace
-  "Catch exceptions and render a stacktrace for debugging."
+  "Catch exceptions and render web and log stacktraces for debugging."
   (:use (hiccup core page-helpers)
         (clj-stacktrace core repl)
         (clojure.contrib [def :only (defvar-)])
         ring.util.response))
+
+(defn wrap-stacktrace-log
+  "Wrap an app such that exceptions are logged to *err* and then rethrown."
+  [app]
+  (fn [req]
+    (try
+      (app req)
+      (catch Exception e
+        (let [msg (str "Exception: " (pst-str e))]
+          (.println *err* msg)
+          (throw e))))))

 (declare css)

@@ -50,15 +61,23 @@
       (js-ex-response e)
       (html-ex-response e))))

-(defn wrap-stacktrace
-  "Wrap an app such that exceptions thrown within the wrapped app are caught
-  and a helpful debugging response is returned."
+(defn wrap-stacktrace-web
+  "Wrap an app such that exceptions are caught and a helpful debugging response
+   is returned."
   [app]
   (fn [req]
     (try
       (app req)
       (catch Exception e
         (ex-response req e)))))
+
+(defn wrap-stacktrace
+  "Wrap an app such that exceptions are caught, a corresponding stacktrace is
+  logged to *err*, and a helpful debugging web response is returned."
+  [app]
+  (-> app
+    wrap-stacktrace-log
+    wrap-stacktrace-web))

 (defvar- css "
 /*


Refactored wrap-stacktrace a little, updated doctype, improved docstrings

--- ring-devel/src/ring/middleware/stacktrace.clj
+++ ring-devel/src/ring/middleware/stacktrace.clj
@@ -7,88 +7,84 @@
         ring.util.response))

 (defn wrap-stacktrace-log
-  "Wrap an app such that exceptions are logged to *err* and then rethrown."
-  [app]
-  (fn [req]
+  "Wrap a handler such that exceptions are logged to *err* and then rethrown."
+  [handler]
+  (fn [request]
     (try
-      (app req)
-      (catch Exception e
-        (let [msg (str "Exception: " (pst-str e))]
+      (handler request)
+      (catch Exception ex
+        (let [msg (str "Exception: " (pst-str ex))]
           (.println *err* msg)
-          (throw e))))))
+          (throw ex))))))

 (declare css)
-
-(defn- js-ex-response [e]
-  (-> (response (pst-str e))
-    (status 500)
-    (content-type "text/javascript")))

 (defn- elem-partial [elem]
   (if (:clojure elem)
     [:tr
-      [:td.source (h (source-str         elem))]
+      [:td.source (h (source-str elem))]
       [:td.method (h (clojure-method-str elem))]]
     [:tr
-      [:td.source (h (source-str      elem))]
+      [:td.source (h (source-str elem))]
       [:td.method (h (java-method-str elem))]]))

-(defn- exception-partial [e]
-  (let [e-seq    (iterate :cause (parse-exception e))
-        e-parsed (first e-seq)
-        causes   (rest e-seq)]
-    (cons [:div#content
-            [:h3.info (h (str e))]
-            [:table.trace [:tbody
-              (map elem-partial (:trace-elems e-parsed))]]]
-          (for [cause (take-while #(not (nil? %)) causes)]
-            [:div
-              [:h3.info (h (str "Caused by: " (.getName (:class cause)) " " (:message cause)))]
-              [:table.trace [:tbody
-                (map elem-partial (:trimmed-elems cause))]]]))))
-
-(defn- html-ex-view [e]
-  (html
-    (doctype :xhtml-transitional)
-    [:html {:xmlns "http://www.w3.org/1999/xhtml"}
+(defn- html-exception [ex]
+  (let [ex-seq    (iterate :cause (parse-exception ex))
+        exception (first ex-seq)
+        causes    (rest ex-seq)]
+    (html5
       [:head
-        [:meta {:http-equiv "Content-Type" :content "text/html;charset=utf-8"}]
         [:title "Ring: Stacktrace"]
         [:style {:type "text/css"} css]]
       [:body
-        (exception-partial e)]]))
+        [:div#exception
+          [:h3.info (h (str ex))]
+          [:table.trace
+            [:tbody (map elem-partial (:trace-elems exception))]]]
+        (for [cause causes :while cause]
+          [:div#causes
+           [:h3.info "Caused by: "
+                    (h (.getName (:class cause))) " "
+                    (h (:message cause))]
+           [:table.trace
+             [:tbody (map elem-partial (:trimmed-elems cause))]]])])))

-(defn- html-ex-response [e]
-  (-> (response (html-ex-view e))
-    (status 500)
-    (content-type "text/html")))
+(defn- js-ex-response [e]
+  (-> (response (pst-str e))
+      (status 500)
+      (content-type "text/javascript")))
+
+(defn- html-ex-response [ex]
+  (-> (response (html-exception ex))
+      (status 500)
+      (content-type "text/html")))

 (defn- ex-response
   "Returns a response showing debugging information about the exception.
   Currently supports delegation to either js or html exception views."
-  [req e]
+  [req ex]
   (let [accept (get-in req [:headers "accept"])]
     (if (and accept (re-find #"^text/javascript" accept))
-      (js-ex-response e)
-      (html-ex-response e))))
+      (js-ex-response ex)
+      (html-ex-response ex))))

 (defn wrap-stacktrace-web
-  "Wrap an app such that exceptions are caught and a helpful debugging response
-   is returned."
-  [app]
-  (fn [req]
+  "Wrap a handler such that exceptions are caught and a helpful debugging
+   response is returned."
+  [handler]
+  (fn [request]
     (try
-      (app req)
-      (catch Exception e
-        (ex-response req e)))))
+      (handler request)
+      (catch Exception ex
+        (ex-response request ex)))))

 (defn wrap-stacktrace
-  "Wrap an app such that exceptions are caught, a corresponding stacktrace is
+  "Wrap a handler such that exceptions are caught, a corresponding stacktrace is
   logged to *err*, and a helpful debugging web response is returned."
-  [app]
-  (-> app
-    wrap-stacktrace-log
-    wrap-stacktrace-web))
+  [handler]
+  (-> handler
+      wrap-stacktrace-log
+      wrap-stacktrace-web))

 (def ^{:private true} css "
 /*


ignore rel=nofollow links

ignore rel=nofollow links

--- src/crawler/dom.clj
+++ src/crawler/dom.clj
@@ -265,9 +265,15 @@
         a-tags-w-hrefs (filter
                         ; the node must have a href
                         (fn [a-tag]
-                          (-> a-tag
-                              (.getAttributes)
-                              (.getNamedItem "href")))
+                          (and (-> a-tag
+                                   (.getAttributes)
+                                   (.getNamedItem "href"))
+                               (try (not= (-> a-tag
+                                              (.getAttributes)
+                                              (.getNamedItem "rel")
+                                              (.getValue))
+                                          "nofollow")
+                                    (catch NullPointerException e true))))
                         a-tags)

         xpaths-a-tags  (map #(-> % xpath-to-node first) a-tags-w-hrefs)


A simple method to str an abbv form of a ticket - useful for printing [:14]

--- src/ttt/core.cljs
+++ src/ttt/core.cljs
@@ -326,6 +326,11 @@
          res (write-ticket-file ticket-file (f t-file-map ticket))
          _ (unlock!)]
      res)))
+
+(defn str-ticket
+  "A basic single-line str for a ticket; suitable to print"
+  [t]
+  (str (:id t) " [" (:type t) " :: " (:points t) " points] - " (:summary t)))

 ;; Git interactions
 ;; -----------------


almost there

almost there

--- src/ysmiraak/lang2.clj
+++ src/ysmiraak/lang2.clj
@@ -15,67 +15,59 @@
 ;; vars = set var
 ;; args = vec var

-;; term = form | var | val
+;; term =  val | form
 ;; form = expr & vars
-;; expr = beta | forall
+;; expr =  var | beta | forall
 ;;
-;; expr are always wrapped in form
-;; vars only reduces during evaluation
+;; expr must be wrapped in form, otherwise it is treated as val
+;; binding a var to a form changes everything
 ;;
 ;; val    => val
-;; var    => val | var
-;; form   => form | var | val
-;; beta   => form | beta | var | val
-;; forall => forall
-
+;; var    => val | form *
+;; form   => val | form
+;; beta   => val | form *
+;; forall => form forall
+
+(defrecord Form   [expr vars])    (defn form?   [x] (instance?  Form   x))
 (defrecord Var    [name])         (defn var?    [x] (instance?  Var    x))
-(defrecord Form   [expr vars])    (defn form?   [x] (instance?  Form   x))
 (defrecord Beta   [sexp])         (defn beta?   [x] (instance?  Beta   x))
 (defrecord Forall [term args])    (defn forall? [x] (instance?  Forall x))
 (defprotocol Expr)                (defn expr?   [x] (satisfies? Expr   x))
-(extend-protocol Expr Beta Forall)
+(extend-protocol Expr Var Beta Forall)

 (defprotocol Term
   "

-  fv
-
   ev

   - substitutes all keys in expr to vals in env (: map var val)
   - beta reduces a term whose expr has a Forall as head

   "
-  (fv [this])
-  (ev [this env]))
+  (ev [this vars env]))

 (extend-protocol Term

+  Form
+  ;; - val if its content reduces to val
+  ;; - form * with newly collected free vars
+  ;; todo guard from ev
+  (ev [{:keys [expr vars]} vars env]
+    (ev expr (reduce disj vars (keys env)) env))
+
   Var
-  (fv [this] #{this})
-  (ev [this env] (env this this))
-
-  Form
-  (fv [this] (:vars this))
-  (ev [{:keys [expr vars]} env]
-    (let [;; evaluates expr if necessary
-          term (if (some vars (keys env)) (ev expr env) expr)
-          vars (if (form? term) (:vars term) (reduce disj vars (keys env)))
-          term (if (form? term) (:expr term) term)
-          ;; now term is not a form
-          term (if (and (beta? term) (empty? vars))
-                 (as-> (:sexp term) [head & body]
-                   (apply head body))
-                 term)]
-      (if (expr? term)
-        (Form. term vars)
-        term)))
+  ;; - val
+  ;; - form *
+  (ev [this _ env] (env this this))

   Beta
-  (ev [this env]
-    (as-> (:sexp this) [head & body :as sexp]
-      ;; evalutes sexp if necessary
-      (cond->> sexp (seq env) (map #(ev % env)))
+  ;; - val
+  ;; - form *
+  (ev [{sexp :sexp} vars env]
+    (let [;; evalutes sexp if necessary
+          ;; env (select-keys env vars)
+          [head & body :as sexp] (cond->> sexp (seq env) (map #(ev % vars env)))
+          vars (reduce disj vars (keys env))]
       (if (and (form? head) (forall? (:expr head)))
         (let [{:keys [expr vars]} head
               {:keys [term args]} expr
@@ -83,33 +75,35 @@
               num (count body)]
           (case (compare (count args) num)
             ;; curry
-            1 (-> (ev term env)
+            1 (-> (ev term vars env)
                   (Forall. (subvec args num))
                   (Form. (reduce disj vars (keys env))))
             ;; beta-reduce
-            0 (as-> (ev term env) term
+            0 (as-> (ev term vars env) term
                 (if (expr? term)
                   (Form. term (reduce disj vars (keys env)))
                   term))
             (throw (ex-info "arity error" {:args args :vals body}))))
-        (Beta. sexp))))
+        (if (seq vars)
+          (Form. (Beta. sexp) vars)
+          (apply head body)))))

   Forall
-  (ev [{:keys [term args]} env]
+  ;; - form forall
+  (ev [{:keys [term args]} vars env]
     (let [env  (reduce dissoc env args) ; evalutes term if necessary
-          term (cond-> term (seq env) (ev env))]
-      (if (and (form? term) (forall? (:expr term)))
-        (as-> (:expr term) expr ; uncurries
-          (assoc expr :args (into args (:args expr))))
-        (Forall. term args))))
-
-  Object
-  (fv [this] #{})
-  (ev [this env] this)
-
-  nil
-  (fv [this] #{})
-  (ev [this env] this))
+          term (cond-> term (seq env) (ev vars env))]
+      (if (form? term)
+        (if (forall? (:expr term))
+          ;; uncurries
+          (as-> term [{{:keys [term args']} :expr vars :vars}]
+            (Form. (Forall. term (into args args'))
+                   (reduce disj vars args)))
+          (Form. (Forall. term args) (reduce disj (:vars term) args)))
+        (Form. (Forall. term args) #{}))))
+
+  Object (ev [this _ _] this)
+  nil    (ev [this _ _] this))

 (defn ?%
   "takes a term and interleaving var-terms and values, (partially)
@@ -127,24 +121,22 @@

   "
   [term & {:as env}]
-  (ev term env))
+  (ev term #{} env))

 (defn ?
   "funcall, the counit of product-exponential adjunction"
   ([& terms]
-   (as-> (ev (Beta. terms) {}) term
-     (if (beta? term)
-       (ev (Form. term (apply clojure.set/union (map fv terms))) {})
-       term)))
+   (let [terms (for [t terms] (if (var? t) (Form. t #{t}) t))
+         vars (apply clojure.set/union (map :vars (filter form? terms)))]
+     (ev (Beta. terms) vars {})))
   ([]))

 (defn %
   "forall"
   ([term & args] ; currently args can only be vars
-   (-> (Forall. term (vec args))
-       (ev {})
-       (Form. (reduce disj (if (form? term) (:vars term) #{}) args))
-       (ev {})))
+   (ev (Forall. term (vec args))
+       (reduce disj (if (form? term) (:vars term) #{}) args)
+       {}))
   ([term] term))

 (defn !
@@ -240,4 +232,5 @@
   )

 ;; todo
+;; - fix (keys env)
 ;; - test how to replace var using env


debug lines showing duplicated go blocks

--- frontend/src/leftover/core.cljs
+++ frontend/src/leftover/core.cljs
@@ -1,6 +1,7 @@
 (ns leftover.core
   (:require-macros  [cljs.core.async.macros :refer  [go]])
   (:require
+    [goog.string :as gs]
     [leftover.net :as net]
     [leftover.ui :as ui]
     [leftover.util :as util]
@@ -43,14 +44,15 @@

 ; handle events from the server
 (go
-  (loop []
-    ; (util/log "getting more data")
-    (let [json (<! (net/GET (str base-url "/conn/foo/" unique-id)))
-          cleaned (util/json->clj json)]
-      ; (util/log (clj->js cleaned))
-      (if (seq cleaned)
-        (swap! app-state assoc :data cleaned)))
-    (recur)))
+  (let [uniq-id-go (util/random-string 32)]
+    (loop []
+      (util/log (gs/format "getting more data (cid: %s) (goid: %s)" unique-id uniq-id-go))
+      (let [json (<! (net/GET (str base-url "/conn/foo/" unique-id)))
+            cleaned (util/json->clj json)]
+        ; (util/log (clj->js cleaned))
+        (if (seq cleaned)
+          (swap! app-state assoc :data cleaned)))
+      (recur))))

 ; call for initial data, up to 5 seconds
 (go


Properly redirect to login when unauthorized response is received.

--- frontend/src/uxbox/main/ui.cljs
+++ frontend/src/uxbox/main/ui.cljs
@@ -13,7 +13,7 @@
             [uxbox.main.state :as st]
             [uxbox.main.data.projects :as dp]
             [uxbox.main.data.users :as udu]
-            [uxbox.main.data.auth :as dauth]
+            [uxbox.main.data.auth :refer [logout]]
             [uxbox.main.data.messages :as dmsg]
             [uxbox.main.ui.loader :refer (loader)]
             [uxbox.main.ui.lightbox :refer (lightbox)]
@@ -51,13 +51,13 @@
 (defn- on-error
   "A default error handler."
   [{:keys [status] :as error}]
+  (js/console.log "on-error:" (pr-str error))
   (cond
     ;; Unauthorized or Auth timeout
     (and (:status error)
-         (:payload error)
          (or (= (:status error) 403)
              (= (:status error) 419)))
-    (rs/emit! (dauth/logout))
+    (rs/emit! (logout))

     ;; Conflict
     (= status 412)


Hopefully a better fix for Issue #173.

Hopefully a better fix for Issue #173.

--- src/zprint/zprint.cljc
+++ src/zprint/zprint.cljc
@@ -2313,14 +2313,9 @@
                    ;   (next flow-result)
                    ;   flow-result)
                    ;
-                   ; It wouuld be interesting to figure out how this
-                   ; happened originally.  But it is vitally
-                   ; necessary unless good-enough is changed to
-                   ; alter the numbers.  Which might be the better
-                   ; approach, since we are ignoring one line here.
-                   (if (and (not pair-seq) (> (count flow-result) 1))
-                     (next flow-result)
-                     flow-result))])))
+                   ; Now we do a similar thing -- as long as flow-result
+                   ; has more than one thing, below when we call good-enough.
+                   flow-result)])))
          [flow flow-lines] (when flow (zat options flow)) ; PT
          _ (log-lines options
                       "fzprint-hang-remaining: hanging:"
@@ -2340,13 +2335,32 @@
          hanging
          (concat-no-nil [[" " :none :whitespace 10]] hanging))
        (when flow-lines
-         (if (good-enough? caller
-                           options
-                           fn-style
-                           hang-count
-                           (- hindent findent)
-                           hanging-lines
-                           flow-lines)
+         (if (good-enough?
+               caller
+               options
+               fn-style
+               hang-count
+               (- hindent findent)
+               hanging-lines
+               ; If we have more than one line in the flow
+               ; and we didn't have any constant pairs,
+               ; then decrease the line count for the flow.
+               ; This seems to be necessary based on the results,
+               ; but it can't be done in good-enough in all cases,
+               ; because it breaks lots of stuff.  This was
+               ; previously done above, in the call to style-lines,
+               ; where we just skipped the first line.  That
+               ; seems like a bad idea, so we now just create
+               ; a new flow-lines to cover this situation.
+               ; This was provoked by Issue #173 where we lost
+               ; code when there was only one thing in flow-result,
+               ; and we skipped that thing, causing style-lines
+               ; to return nil and the whole thing disappeared.
+               (if (and (not pair-seq) (> (first flow-lines) 1))
+                 [(dec (first flow-lines)) (second flow-lines)
+                  (nth flow-lines 2)]
+                 flow-lines)
+               #_flow-lines)
            ; If hanging starts with a newline, don't put a blank at the
            ; end of the previous line.
            (if (first-nl? hanging)