;;   Copyright (c) Dragan Djuric. All rights reserved.
;;   The use and distribution terms for this software are covered by the
;;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) or later
;;   which can be found in the file LICENSE at the root of this distribution.
;;   By using this software in any fashion, you are agreeing to be bound by
;;   the terms of this license.
;;   You must not remove this notice, or any other, from this software.

(defproject uncomplicate/bayadera "0.3.0-SNAPSHOT"
  :description "Bayesian Inference and Probabilistic Machine Learning Library for Clojure"
  :author "Dragan Djuric"
  :url "http://github.com/uncomplicate/bayadera"
  :scm {:name "git"
        :url "https://github.com/uncomplicate/bayadera"}
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.9.0"]
                 [uncomplicate/commons "0.6.0"]
                 [uncomplicate/fluokitten "0.9.0"]
                 [uncomplicate/clojurecl "0.10.3"]
                 [uncomplicate/clojurecuda "0.5.2"]
                 [uncomplicate/neanderthal "0.21.0-SNAPSHOT"]
                 [org.apache.commons/commons-math3 "3.6.1"]
                 [quil "2.7.1"]]

  :codox {:src-dir-uri "http://github.com/uncomplicate/bayadera/blob/master"
          :src-linenum-anchor-prefix "L"
          :output-dir "docs/codox"}

  :profiles {:dev {:dependencies [[midje "1.9.2"]]
                   :plugins [[lein-midje "3.2.1"]
                             [codox "0.10.3"]]
                   :global-vars {*warn-on-reflection* true
                                 *unchecked-math* :warn-on-boxed
                                 *print-length* 16}
                   :jvm-opts ^:replace ["-Dclojure.compiler.direct-linking=true"
                                        "-XX:MaxDirectMemorySize=16g" "-XX:+UseLargePages"
                                        "-Duncomplicate.cudadevrt=/usr/local/cuda/lib64/libcudadevrt.a"
                                        #_"--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED"]}}

  :javac-options ["-target" "1.8" "-source" "1.8" "-Xlint:-options"]
  :source-paths ["src/clojure" "src/device"]
  :resource-paths ["src/device"]
  :test-paths ["test" "test/clojure"])

;;   Copyright (c) Dragan Djuric. All rights reserved.
;;   The use and distribution terms for this software are covered by the
;;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) or later
;;   which can be found in the file LICENSE at the root of this distribution.
;;   By using this software in any fashion, you are agreeing to be bound by
;;   the terms of this license.
;;   You must not remove this notice, or any other, from this software.

(defproject uncomplicate/bayadera "0.3.0-SNAPSHOT"
  :description "Bayesian Inference and Probabilistic Machine Learning Library for Clojure"
  :author "Dragan Djuric"
  :url "http://github.com/uncomplicate/bayadera"
  :scm {:name "git"
        :url "https://github.com/uncomplicate/bayadera"}
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.10.0"]
                 [uncomplicate/commons "0.7.1"]
                 [uncomplicate/fluokitten "0.9.1"]
                 [uncomplicate/clojurecl "0.10.5"]
                 [uncomplicate/clojurecuda "0.6.1"]
                 [uncomplicate/neanderthal "0.21.0"]
                 [org.apache.commons/commons-math3 "3.6.1"]
                 [quil "2.8.0"]]

  :codox {:src-dir-uri "http://github.com/uncomplicate/bayadera/blob/master"
          :src-linenum-anchor-prefix "L"
          :output-dir "docs/codox"}

  :profiles {:dev {:dependencies [[midje "1.9.4"]]
                   :plugins [[lein-midje "3.2.1"]
                             [codox "0.10.3"]]
                   :global-vars {*warn-on-reflection* true
                                 *unchecked-math* :warn-on-boxed
                                 *print-length* 16}
                   :jvm-opts ^:replace ["-Dclojure.compiler.direct-linking=true"
                                        "-XX:MaxDirectMemorySize=16g" "-XX:+UseLargePages"
                                        "-Duncomplicate.cudadevrt=/usr/local/cuda/lib64/libcudadevrt.a"
                                        #_"--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED"]}}

  :javac-options ["-target" "1.8" "-source" "1.8" "-Xlint:-options"]
  :source-paths ["src/clojure" "src/device"]
  :resource-paths ["src/device"]
  :test-paths ["test" "test/clojure"])

Update to uncomplicate releases.

Update to uncomplicate releases.


(defproject compojure "1.3.3"
  :description "A concise routing library for Ring"
  :url "https://github.com/weavejester/compojure"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]
                 [org.clojure/tools.macro "0.1.5"]
                 [clout "2.1.2"]
                 [medley "0.5.5"]
                 [ring/ring-core "1.3.2"]
                 [ring/ring-codec "1.0.0"]]
  :plugins [[codox "0.8.10"]]
  :codox {:src-dir-uri "http://github.com/weavejester/compojure/blob/1.3.3/"
          :src-linenum-anchor-prefix "L"}
  :profiles
  {:dev {:jvm-opts ^:replace []
         :dependencies [[ring/ring-mock "0.2.0"]
                        [criterium "0.4.3"]
                        [javax.servlet/servlet-api "2.5"]]}
   :1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]}
   :1.7 {:dependencies [[org.clojure/clojure "1.7.0-beta2"]]}})

(defproject compojure "1.3.3"
  :description "A concise routing library for Ring"
  :url "https://github.com/weavejester/compojure"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]
                 [org.clojure/tools.macro "0.1.5"]
                 [clout "2.1.2"]
                 [medley "0.6.0"]
                 [ring/ring-core "1.3.2"]
                 [ring/ring-codec "1.0.0"]]
  :plugins [[codox "0.8.10"]]
  :codox {:src-dir-uri "http://github.com/weavejester/compojure/blob/1.3.3/"
          :src-linenum-anchor-prefix "L"}
  :profiles
  {:dev {:jvm-opts ^:replace []
         :dependencies [[ring/ring-mock "0.2.0"]
                        [criterium "0.4.3"]
                        [javax.servlet/servlet-api "2.5"]]}
   :1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]}
   :1.7 {:dependencies [[org.clojure/clojure "1.7.0-beta2"]]}})

Update Medley dependency to 0.6.0

Update Medley dependency to 0.6.0


(defproject cljam "0.2.0-SNAPSHOT"
  :description "A DNA Sequence Alignment/Map (SAM) library for Clojure"
  :url "https://github.com/chrovis/cljam"
  :license {:name "Apache License, Version 2.0"
            :url "http://www.apache.org/licenses/LICENSE-2.0.html"}
  :dependencies [[org.clojure/tools.logging "0.3.1"]
                 [org.clojure/tools.cli "0.3.5"]
                 [org.apache.commons/commons-compress "1.13"]
                 [me.raynes/fs "1.4.6"]
                 [clj-sub-command "0.3.0"]
                 [digest "1.4.5"]
                 [bgzf4j "0.1.0"]
                 [com.climate/claypoole "1.1.4"]
                 [camel-snake-kebab "0.4.0"]]
  :plugins [[lein-midje "3.2.1"]]
  :profiles {:dev {:dependencies [[org.clojure/clojure "1.8.0"]
                                  [midje "1.8.3" :exclusions [slingshot]]
                                  [cavia "0.3.0"]]
                   :plugins [[lein-bin "0.3.5"]
                             [lein-codox "0.10.2"]
                             [lein-marginalia "0.9.0"]]
                   :main cljam.main
                   :aot [cljam.main]
                   :global-vars {*warn-on-reflection* true}}
             :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]}
             :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]}
             :1.9 {:dependencies [[org.clojure/clojure "1.9.0-alpha14"]
                                  [midje "1.9.0-alpha6"]]}
             :uberjar {:main cljam.main
                       :aot :all}}
  :aliases {"docs" ["do" "codox" ["marg" "-d" "target/literate" "-m"]]}
  :bin {:name "cljam"}
  :codox {:namespaces [#"^cljam\.(?!cli)(?!lsb)(?!main)(?!util)[^\.]+$"]
          :output-path "target/docs"
          :source-uri "https://github.com/chrovis/cljam/blob/{version}/{filepath}#L{line}"}
  :repl-options {:init-ns user}
  :signing {:gpg-key "developer@xcoo.jp"})

(defproject cljam "0.2.0-SNAPSHOT"
  :description "A DNA Sequence Alignment/Map (SAM) library for Clojure"
  :url "https://github.com/chrovis/cljam"
  :license {:name "Apache License, Version 2.0"
            :url "http://www.apache.org/licenses/LICENSE-2.0.html"}
  :dependencies [[org.clojure/tools.logging "0.3.1"]
                 [org.clojure/tools.cli "0.3.5"]
                 [org.apache.commons/commons-compress "1.13"]
                 [me.raynes/fs "1.4.6"]
                 [clj-sub-command "0.3.0"]
                 [digest "1.4.5"]
                 [bgzf4j "0.1.0"]
                 [com.climate/claypoole "1.1.4"]
                 [camel-snake-kebab "0.4.0"]]
  :plugins [[lein-midje "3.2.1"]]
  :profiles {:dev {:dependencies [[org.clojure/clojure "1.8.0"]
                                  [midje "1.8.3" :exclusions [slingshot]]
                                  [cavia "0.3.1"]]
                   :plugins [[lein-bin "0.3.5"]
                             [lein-codox "0.10.3"]
                             [lein-marginalia "0.9.0"]]
                   :main cljam.main
                   :aot [cljam.main]
                   :global-vars {*warn-on-reflection* true}}
             :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]}
             :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]}
             :1.9 {:dependencies [[org.clojure/clojure "1.9.0-alpha14"]
                                  [midje "1.9.0-alpha6"]]}
             :uberjar {:main cljam.main
                       :aot :all}}
  :aliases {"docs" ["do" "codox" ["marg" "-d" "target/literate" "-m"]]}
  :bin {:name "cljam"}
  :codox {:namespaces [#"^cljam\.(?!cli)(?!lsb)(?!main)(?!util)[^\.]+$"]
          :output-path "target/docs"
          :source-uri "https://github.com/chrovis/cljam/blob/{version}/{filepath}#L{line}"}
  :repl-options {:init-ns user}
  :signing {:gpg-key "developer@xcoo.jp"})

Bump dependencies version up

Bump dependencies version up


(defproject hatnik.web "0.1.0-SNAPSHOT"
  :description "Web app for tracking library releases."
  :url "http://hatnik.com"
  :dependencies [; Clojure
                 [org.clojure/clojure "1.7.0"]
                 [ring "1.4.0"]
                 [compojure "1.3.4"]
                 [hiccup "1.0.5"]
                 [ring/ring-json "0.3.1"]
                 [clj-http "1.1.2"]
                 [tentacles "0.4.0"]
                 [com.taoensso/timbre "4.1.0-alpha1"]
                 [com.novemberain/monger "3.0.0-rc2"]
                 [ancient-clj "0.3.9"]
                 [com.draines/postal "1.11.3"]
                 [version-clj "0.1.2"]
                 [clojurewerkz/quartzite "2.0.0"]
                 [prismatic/schema "0.4.3"]
                 [com.stuartsierra/component "0.2.3"]
                 [me.raynes/fs "1.4.6"]
                 [com.googlecode.streamflyer/streamflyer-core "1.1.3"]
                 [commons-io "2.4"]

                 ; ClojureScript
                 [org.clojure/clojurescript "0.0-3308"]
                 [jayq "2.5.4"]
                 [org.omcljs/om "0.9.0"]]

  :plugins [[lein-cljsbuild "1.0.6"]]

  :main hatnik.system
  :source-paths ["src/clj" "target/gen/clj"]
  :test-paths ["test/clj"]

  :test-selectors {:selenium :selenium
                   :unit (complement :selenium)}

  :clean-targets ^{:protect false} ["resources/public/gen"
                                    "out"]

  :profiles
  {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
                        [ring-mock "0.1.5"]
                        [com.cemerick/piggieback "0.2.1"]
                        [org.seleniumhq.selenium/selenium-java "2.46.0"]
                        [org.seleniumhq.selenium/selenium-remote-driver "2.46.0"]
                        [org.seleniumhq.selenium/selenium-server "2.46.0"]]

         :plugins [[jonase/eastwood "0.2.1"]
                   [com.keminglabs/cljx "0.5.0" :exclusions [org.clojure/clojure]]]

         :cljsbuild
         {:builds
          [{:source-paths ["src/cljs" "dev/cljs" "target/gen/cljs"]
            :compiler
            {:output-to "resources/public/gen/js/hatnik.js"
             :output-dir "out"
             :main hatnik.web.client.app-init
             :optimizations :none
             :pretty-print true}}]
          }
         :cljx {:builds [{:source-paths ["src/cljx"]
                 :output-path "target/gen/clj"
                 :rules :clj}

                {:source-paths ["src/cljx"]
                 :output-path "target/gen/cljs"
                 :rules :cljs}]}}
   :release
   {:cljsbuild
    {:builds
     [{:source-paths ["src/cljs" "target/gen/cljs"]
       :compiler
       {:output-to "resources/public/gen/js/hatnik.js"
        :main hatnik.web.client.app-init
        :externs ["externs/jquery-1.9.js"
                  "externs/hatnik.js"]
        :optimizations :advanced
        :pretty-print false}}]
     }}})

(defproject hatnik.web "0.1.0-SNAPSHOT"
  :description "Web app for tracking library releases."
  :url "http://hatnik.com"
  :dependencies [; Clojure
                 [org.clojure/clojure "1.7.0"]
                 [ring "1.4.0"]
                 [compojure "1.3.4"]
                 [hiccup "1.0.5"]
                 [ring/ring-json "0.3.1"]
                 [clj-http "1.1.2"]
                 [tentacles "0.4.0"]
                 [com.taoensso/timbre "4.1.0-alpha2"]
                 [com.novemberain/monger "3.0.0-rc2"]
                 [ancient-clj "0.3.9"]
                 [com.draines/postal "1.11.3"]
                 [version-clj "0.1.2"]
                 [clojurewerkz/quartzite "2.0.0"]
                 [prismatic/schema "0.4.3"]
                 [com.stuartsierra/component "0.2.3"]
                 [me.raynes/fs "1.4.6"]
                 [com.googlecode.streamflyer/streamflyer-core "1.1.3"]
                 [commons-io "2.4"]

                 ; ClojureScript
                 [org.clojure/clojurescript "0.0-3308"]
                 [jayq "2.5.4"]
                 [org.omcljs/om "0.9.0"]]

  :plugins [[lein-cljsbuild "1.0.6"]]

  :main hatnik.system
  :source-paths ["src/clj" "target/gen/clj"]
  :test-paths ["test/clj"]

  :test-selectors {:selenium :selenium
                   :unit (complement :selenium)}

  :clean-targets ^{:protect false} ["resources/public/gen"
                                    "out"]

  :profiles
  {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
                        [ring-mock "0.1.5"]
                        [com.cemerick/piggieback "0.2.1"]
                        [org.seleniumhq.selenium/selenium-java "2.46.0"]
                        [org.seleniumhq.selenium/selenium-remote-driver "2.46.0"]
                        [org.seleniumhq.selenium/selenium-server "2.46.0"]]

         :plugins [[jonase/eastwood "0.2.1"]
                   [com.keminglabs/cljx "0.5.0" :exclusions [org.clojure/clojure]]]

         :cljsbuild
         {:builds
          [{:source-paths ["src/cljs" "dev/cljs" "target/gen/cljs"]
            :compiler
            {:output-to "resources/public/gen/js/hatnik.js"
             :output-dir "out"
             :main hatnik.web.client.app-init
             :optimizations :none
             :pretty-print true}}]
          }
         :cljx {:builds [{:source-paths ["src/cljx"]
                 :output-path "target/gen/clj"
                 :rules :clj}

                {:source-paths ["src/cljx"]
                 :output-path "target/gen/cljs"
                 :rules :cljs}]}}
   :release
   {:cljsbuild
    {:builds
     [{:source-paths ["src/cljs" "target/gen/cljs"]
       :compiler
       {:output-to "resources/public/gen/js/hatnik.js"
        :main hatnik.web.client.app-init
        :externs ["externs/jquery-1.9.js"
                  "externs/hatnik.js"]
        :optimizations :advanced
        :pretty-print false}}]
     }}})

Update com.taoensso/timbre to 4.1.0-alpha2


(defproject io.nervous/eulalie "0.3.2-SNAPSHOT"
  :description "Asynchronous, pure-Clojure AWS client"
  :url "https://github.com/nervous-systems/eulalie"
  :license {:name "Unlicense" :url "http://unlicense.org/UNLICENSE"}
  :scm {:name "git" :url "https://github.com/nervous-systems/eulalie"}
  :deploy-repositories [["clojars" {:creds :gpg}]]
  :signing {:gpg-key "moe@nervous.io"}
  :global-vars {*warn-on-reflection* true}
  :source-paths ["src" "test"]
  :dependencies
  [[org.clojure/clojure        "1.6.0"]
   [org.clojure/core.async     "0.1.346.0-17112a-alpha"]
   [org.clojure/tools.logging  "0.3.1"]
   [org.clojure/algo.generic   "0.1.2"]

   [camel-snake-kebab           "0.2.5"]

   [http-kit                   "2.1.18"]
   [com.cemerick/url           "0.1.1"]
   [cheshire                   "5.5.0"]
   [digest                     "1.4.4"]
   [clj-time                   "0.9.0"]

   [ch.qos.logback/logback-classic "1.1.2"]]
  :exclusions [[org.clojure/clojure]]

  :profiles {:dev
             {:dependencies
              [[com.amazonaws/aws-java-sdk "1.9.3"
                :exclusions [joda-time
                             commons-logging
                             fasterxml.jackson.core/jackson-core]]
               [org.slf4j/jcl-over-slf4j   "1.7.7"]]
              :source-paths ["src" "test"]
              :aot [eulalie.TestableAWS4Signer]}})

(defproject io.nervous/eulalie "0.3.2"
  :description "Asynchronous, pure-Clojure AWS client"
  :url "https://github.com/nervous-systems/eulalie"
  :license {:name "Unlicense" :url "http://unlicense.org/UNLICENSE"}
  :scm {:name "git" :url "https://github.com/nervous-systems/eulalie"}
  :deploy-repositories [["clojars" {:creds :gpg}]]
  :signing {:gpg-key "moe@nervous.io"}
  :global-vars {*warn-on-reflection* true}
  :source-paths ["src" "test"]
  :dependencies
  [[org.clojure/clojure        "1.6.0"]
   [org.clojure/core.async     "0.1.346.0-17112a-alpha"]
   [org.clojure/tools.logging  "0.3.1"]
   [org.clojure/algo.generic   "0.1.2"]

   [camel-snake-kebab           "0.2.5"]

   [http-kit                   "2.1.18"]
   [com.cemerick/url           "0.1.1"]
   [cheshire                   "5.5.0"]
   [digest                     "1.4.4"]
   [clj-time                   "0.9.0"]

   [ch.qos.logback/logback-classic "1.1.2"]]
  :exclusions [[org.clojure/clojure]]

  :profiles {:dev
             {:dependencies
              [[com.amazonaws/aws-java-sdk "1.9.3"
                :exclusions [joda-time
                             commons-logging
                             fasterxml.jackson.core/jackson-core]]
               [org.slf4j/jcl-over-slf4j   "1.7.7"]]
              :source-paths ["src" "test"]
              :aot [eulalie.TestableAWS4Signer]}})

bump to 0.3.2

bump to 0.3.2


(defproject funcool/promesa "1.0.0"
  :description "A promise library for ClojureScript"
  :url "https://github.com/funcool/promesa"
  :license {:name "BSD (2 Clause)"
            :url "http://opensource.org/licenses/BSD-2-Clause"}
  :dependencies [[org.clojure/clojure "1.8.0" :scope "provided"]
                 [org.clojure/clojurescript "1.7.228" :scope "provided"]
                 [funcool/cats "1.2.1" :scope "provided"]]
  :deploy-repositories {"releases" :clojars
                        "snapshots" :clojars}
  :source-paths ["src" "assets"]
  :test-paths ["test"]
  :jar-exclusions [#"\.swp|\.swo|user.clj"]
  :codeina {:sources ["src"]
            :reader :clojure
            :target "doc/dist/latest/api"}
  :plugins [[funcool/codeina "0.3.0"]
            [lein-ancient "0.6.7" :exclusions [org.clojure/tools.reader]]])

(defproject funcool/promesa "1.1.0"
  :description "A promise library for ClojureScript"
  :url "https://github.com/funcool/promesa"
  :license {:name "BSD (2 Clause)"
            :url "http://opensource.org/licenses/BSD-2-Clause"}
  :dependencies [[org.clojure/clojure "1.8.0" :scope "provided"]
                 [org.clojure/clojurescript "1.7.228" :scope "provided"]
                 [funcool/cats "1.2.1" :scope "provided"]]
  :deploy-repositories {"releases" :clojars
                        "snapshots" :clojars}
  :source-paths ["src" "assets"]
  :test-paths ["test"]
  :jar-exclusions [#"\.swp|\.swo|user.clj"]
  :codeina {:sources ["src"]
            :reader :clojure
            :target "doc/dist/latest/api"}
  :plugins [[funcool/codeina "0.3.0"]
            [lein-ancient "0.6.7" :exclusions [org.clojure/tools.reader]]])

Set version to 1.1.0

Set version to 1.1.0


;;--------------------------------------------------------------------------;;
;;                                                                          ;;
;;                A E R O B I O . H T S E Q . W G S E Q                     ;;
;;                                                                          ;;
;; Permission is hereby granted, free of charge, to any person obtaining    ;;
;; a copy of this software and associated documentation files (the          ;;
;; "Software"), to deal in the Software without restriction, including      ;;
;; without limitation the rights to use, copy, modify, merge, publish,      ;;
;; distribute, sublicense, and/or sell copies of the Software, and to       ;;
;; permit persons to whom the Software is furnished to do so, subject to    ;;
;; the following conditions:                                                ;;
;;                                                                          ;;
;; The above copyright notice and this permission notice shall be           ;;
;; included in all copies or substantial portions of the Software.          ;;
;;                                                                          ;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          ;;
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF       ;;
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                    ;;
;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE   ;;
;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION   ;;
;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION    ;;
;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.          ;;
;;                                                                          ;;
;; Author: Jon Anthony                                                      ;;
;;                                                                          ;;
;;--------------------------------------------------------------------------;;
;;

(ns aerobio.htseq.wgseq
  [:require
   [clojure.string :as cljstr]
   [clojure.data.csv :as csv]

   [aerial.fs :as fs]
   [aerial.utils.string :as str]
   [aerial.utils.coll :refer [vfold] :as coll]
   [aerial.utils.string :as str]
   [aerial.utils.io :refer [letio] :as io]

   [aerial.bio.utils.files :as bufiles]
   [aerial.bio.utils.filters :as fil]

   [aerobio.params :as pams]
   [aerobio.htseq.common :as cmn]
   [aerobio.pgmgraph :as pg]])

(defn filter-fastq
  [fastq & {:keys [baseqc% winsize info%  min-len sqc% marker pretrim outdir]
            :or {baseqc% 0.95, winsize 10, info% 0.9
                 min-len 40, sqc% 0.97 pretrim 11}}]
  (letio [[qc-ctpt ent-ctpt] (fil/qcscore-min-entropy baseqc% info% winsize)
          totcnt (volatile! 0)
          gdcnt (volatile! 0)
          lens (volatile! {})
          rec-chunk-size 10000

          f (fs/fullpath fastq)
          outdir (if outdir outdir (fs/dirname f))
          statf (->> f fs/basename (str/split #"\.") first
                     (#(str % "-qc" qc-ctpt "-stat.txt"))
                     (fs/join outdir))

          otfq (->> f fs/basename (str/split #"\.") first
                    (#(str % "-qc" qc-ctpt ".fastq.gz"))
                    (fs/join outdir))
          ot (io/open-streaming-gzip otfq :out)

          inf (if (not= (fs/ftype f) "gz")
                (clojure.java.io/reader f)
                (io/open-streaming-gzip f :in))]
    (loop [recs (bufiles/read-fqrecs inf rec-chunk-size)]
      (if (not (seq recs))
        (io/with-out-writer statf
          (prn {:run-params {:sqc% (* 100 sqc%)
                             :base-quality (* 100 baseqc%)
                             :window-size winsize
                             :info% (* 100 info%)
                             :min-len min-len}
                :good-cnt @gdcnt
                :total-cnt @totcnt
                :bad-cnt (- @totcnt @gdcnt)
                :percent-good (* 100 (double (/ @gdcnt @totcnt)))
                :len-dist @lens}))
        (let [xxx (vfold #(fil/seq-filter % :qc-ctpt qc-ctpt
                                          :winsize winsize
                                          :ent-ctpt ent-ctpt)
                         recs)
              xxx (vfold #(fil/trim-ends % pretrim min-len sqc% marker) xxx)]
          (doseq [[gcnt id gsq gqc qc%] xxx]
            (vswap! lens #(assoc % gcnt (inc (long (get % gcnt 0)))))
            (vswap! totcnt #(inc (long %)))
            (when (and (> gcnt min-len) (>= qc% sqc%))
              (vswap! gdcnt #(inc (long %)))
              (bufiles/write-fqrec
               ot [id gsq (str "+ " gcnt " " qc%) gqc])))
          (recur (bufiles/read-fqrecs inf rec-chunk-size)))))))

(defn split-filter-fastqs
  [eid]
  (let [fqbase (cmn/get-exp-info eid :fastq)
        fqs (fs/directory-files fqbase "fastq.gz")
        sample-dir (cmn/get-exp-info eid :samples)]
    (cmn/ensure-sample-dirs
     (cmn/get-exp-info eid :base)
     (cmn/get-exp-info eid :illumina-sample-xref))
    (doseq [fq fqs]
      (filter-fastq
       fq :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
       :outdir sample-dir))))

(defn get-comparison-files-
  ([eid]
   (get-comparison-files- eid "ComparisonSheet.csv"))
  ([eid comp-filename & _]
   (let [samps (cmn/get-exp-info eid :samples)
         outs  (cmn/get-exp-info eid :out)
         refbase (cmn/get-exp-info eid :refs)
         refxref (cmn/get-exp-info eid :ncbi-sample-xref)
         compvec (->> comp-filename
                      (fs/join (pams/get-params :nextseq-base) eid)
                      slurp csv/read-csv rest)
         quads (->> compvec
                    (map (fn[[samp ref]]
                           [(-> (fs/join samps (str samp "_*.fastq.gz"))
                                fs/glob
                                (->> (filter #(re-find ; glob bug!
                                               (re-pattern
                                                (str "/" samp)) %)))
                                sort)
                            (fs/join refbase (str (refxref ref) ".gbk"))
                            (fs/join outs samp)]))
                    (mapv #(vector % (fs/size (ffirst %))))
                    (sort-by second)
                    (mapv first))]
     (cmn/ensure-dirs outs)
     quads)))

(defmethod cmn/get-comparison-files :wgseq
  [_ & args]
  (apply get-comparison-files- args))

(defn run-wgseq-comparison
  "Run set of population and/or clones against reference seqs defined
  by experiement designated by eid (experiment id) and the input
  comparison sheet CSV comparison-file"
  [eid recipient comparison-file get-toolinfo template]
  (let [cfg (assoc-in template
                      [:nodes :ph2 :args]
                      [eid comparison-file :NA recipient])
        cfgjob (pg/future+ (cmn/flow-program cfg get-toolinfo :run true))]
    cfgjob))

(defmethod cmn/run-comparison :wgseq
  [_ eid recipient compfile get-toolinfo template]
  (run-wgseq-comparison
   eid recipient compfile get-toolinfo template))

(defmethod cmn/run-phase-2 :wgseq
  [_ eid recipient get-toolinfo template]
  (run-wgseq-comparison
   eid recipient "ComparisonSheet.csv" get-toolinfo template))

(comment

  (let [dirs (->> (get-comparison-files
                   :wgseq
                   "171202_NS500751_0065_AHYYG3BGX3"
                   "T4-D39nonclone-ComparisonSheet.csv")
                  (mapv last))
        old (fs/join (get-exp-info "171202_NS500751_0065_AHYYG3BGX3" :out)
                     "Old")]
    (fs/move dirs old))

  (fs/dodir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Raw/"
            #(fs/re-directory-files % "Day4N2*.fastq.gz")
            #(filter-fastq
              % :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
              :outdir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Filtered"))

  (fs/dodir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Raw/"
            #(fs/re-directory-files % "Day10*.gz")
            #(filter-fastq
              % :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
              :outdir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Filtered"))

  (fs/dodir "/data1/NextSeq/TVOLab/KarenWGS012816/Refs"
            #(fs/re-directory-files % "wt*.fastq.gz")
            #(filter-fastq
              % :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
              :outdir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Filtered"))

  (fs/dodir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Raw/"
            #(fs/re-directory-files % "wt*.fastq.gz")
            #(filter-fastq
              % :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
              :outdir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Filtered"))
)

;;--------------------------------------------------------------------------;;
;;                                                                          ;;
;;                A E R O B I O . H T S E Q . W G S E Q                     ;;
;;                                                                          ;;
;; Permission is hereby granted, free of charge, to any person obtaining    ;;
;; a copy of this software and associated documentation files (the          ;;
;; "Software"), to deal in the Software without restriction, including      ;;
;; without limitation the rights to use, copy, modify, merge, publish,      ;;
;; distribute, sublicense, and/or sell copies of the Software, and to       ;;
;; permit persons to whom the Software is furnished to do so, subject to    ;;
;; the following conditions:                                                ;;
;;                                                                          ;;
;; The above copyright notice and this permission notice shall be           ;;
;; included in all copies or substantial portions of the Software.          ;;
;;                                                                          ;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          ;;
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF       ;;
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                    ;;
;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE   ;;
;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION   ;;
;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION    ;;
;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.          ;;
;;                                                                          ;;
;; Author: Jon Anthony                                                      ;;
;;                                                                          ;;
;;--------------------------------------------------------------------------;;
;;

(ns aerobio.htseq.wgseq
  [:require
   [clojure.string :as cljstr]
   [clojure.data.csv :as csv]

   [aerial.fs :as fs]
   [aerial.utils.string :as str]
   [aerial.utils.coll :refer [vfold] :as coll]
   [aerial.utils.string :as str]
   [aerial.utils.io :refer [letio] :as io]

   [aerial.bio.utils.files :as bufiles]
   [aerial.bio.utils.filters :as fil]

   [aerobio.params :as pams]
   [aerobio.htseq.common :as cmn]
   [aerobio.pgmgraph :as pg]])

(defn filter-fastq
  [fastq & {:keys [baseqc% winsize info%  min-len sqc% marker pretrim outdir]
            :or {baseqc% 0.95, winsize 10, info% 0.9
                 min-len 40, sqc% 0.97 pretrim 11}}]
  (letio [[qc-ctpt ent-ctpt] (fil/qcscore-min-entropy baseqc% info% winsize)
          totcnt (volatile! 0)
          gdcnt (volatile! 0)
          lens (volatile! {})
          rec-chunk-size 10000

          f (fs/fullpath fastq)
          outdir (if outdir outdir (fs/dirname f))
          statf (->> f fs/basename (str/split #"\.") first
                     (#(str % "-qc" qc-ctpt "-stat.txt"))
                     (fs/join outdir))

          otfq (->> f fs/basename (str/split #"\.") first
                    (#(str % "-qc" qc-ctpt ".fastq.gz"))
                    (fs/join outdir))
          ot (io/open-streaming-gzip otfq :out)

          inf (if (not= (fs/ftype f) "gz")
                (clojure.java.io/reader f)
                (io/open-streaming-gzip f :in))]
    (loop [recs (bufiles/read-fqrecs inf rec-chunk-size)]
      (if (not (seq recs))
        (io/with-out-writer statf
          (prn {:run-params {:sqc% (* 100 sqc%)
                             :base-quality (* 100 baseqc%)
                             :window-size winsize
                             :info% (* 100 info%)
                             :min-len min-len}
                :good-cnt @gdcnt
                :total-cnt @totcnt
                :bad-cnt (- @totcnt @gdcnt)
                :percent-good (* 100 (double (/ @gdcnt @totcnt)))
                :len-dist @lens}))
        (let [xxx (vfold #(fil/seq-filter % :qc-ctpt qc-ctpt
                                          :winsize winsize
                                          :ent-ctpt ent-ctpt)
                         recs)
              xxx (vfold #(fil/trim-ends % pretrim min-len sqc% marker) xxx)]
          (doseq [[gcnt id gsq gqc qc%] xxx]
            (vswap! lens #(assoc % gcnt (inc (long (get % gcnt 0)))))
            (vswap! totcnt #(inc (long %)))
            (when (and (> gcnt min-len) (>= qc% sqc%))
              (vswap! gdcnt #(inc (long %)))
              (bufiles/write-fqrec
               ot [id gsq (str "+ " gcnt " " qc%) gqc])))
          (recur (bufiles/read-fqrecs inf rec-chunk-size)))))))

(defn split-filter-fastqs
  [eid]
  (let [fqbase (cmn/get-exp-info eid :fastq)
        fqs (fs/directory-files fqbase "fastq.gz")
        sample-dir (cmn/get-exp-info eid :samples)]
    (cmn/ensure-sample-dirs
     (cmn/get-exp-info eid :base)
     (cmn/get-exp-info eid :illumina-sample-xref))
    (doseq [fq fqs]
      (filter-fastq
       fq :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
       :outdir sample-dir))))

(defn get-comparison-files-
  ([eid]
   (get-comparison-files- eid "ComparisonSheet.csv"))
  ([eid comp-filename & _]
   (let [samps (cmn/get-exp-info eid :samples)
         outs  (cmn/get-exp-info eid :out)
         refbase (cmn/get-exp-info eid :refs)
         refxref (cmn/get-exp-info eid :ncbi-sample-xref)
         compvec (->> comp-filename
                      (fs/join (pams/get-params :nextseq-base) eid)
                      slurp csv/read-csv rest)
         quads (->> compvec
                    (map (fn[[samp ref]]
                           [(-> (fs/join samps (str samp "_*.fastq.gz"))
                                fs/glob
                                (->> (filter #(re-find ; glob bug!
                                               (re-pattern
                                                (str "/" samp)) %)))
                                sort)
                            (fs/join refbase (str (refxref ref) ".gbk"))
                            (fs/join outs samp)]))
                    (mapv #(vector % (fs/size (ffirst %))))
                    (sort-by second)
                    (mapv first))]
     (cmn/ensure-dirs outs)
     quads)))

(defmethod cmn/get-comparison-files :wgseq
  [_ & args]
  (apply get-comparison-files- args))

(defn run-wgseq-comparison
  "Run set of population and/or clones against reference seqs defined
  by experiement designated by eid (experiment id) and the input
  comparison sheet CSV comparison-file"
  [eid recipient comparison-file get-toolinfo template status-atom]
  (let [cfg (assoc-in template
                      [:nodes :ph2 :args]
                      [eid comparison-file :NA recipient])
        futs-vec (cmn/flow-program cfg get-toolinfo :run true)]
    (cmn/job-flow-node-results futs-vec status-atom)
    (@status-atom :done)))

(defmethod cmn/run-comparison :wgseq
  [_ eid recipient compfile get-toolinfo template status-atom]
  (run-wgseq-comparison
   eid recipient compfile get-toolinfo template status-atom))

(defmethod cmn/run-phase-2 :wgseq
  [_ eid recipient get-toolinfo template status-atom]
  (run-wgseq-comparison
   eid recipient "ComparisonSheet.csv" get-toolinfo template status-atom))

(comment

  (let [dirs (->> (get-comparison-files
                   :wgseq
                   "171202_NS500751_0065_AHYYG3BGX3"
                   "T4-D39nonclone-ComparisonSheet.csv")
                  (mapv last))
        old (fs/join (get-exp-info "171202_NS500751_0065_AHYYG3BGX3" :out)
                     "Old")]
    (fs/move dirs old))

  (fs/dodir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Raw/"
            #(fs/re-directory-files % "Day4N2*.fastq.gz")
            #(filter-fastq
              % :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
              :outdir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Filtered"))

  (fs/dodir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Raw/"
            #(fs/re-directory-files % "Day10*.gz")
            #(filter-fastq
              % :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
              :outdir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Filtered"))

  (fs/dodir "/data1/NextSeq/TVOLab/KarenWGS012816/Refs"
            #(fs/re-directory-files % "wt*.fastq.gz")
            #(filter-fastq
              % :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
              :outdir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Filtered"))

  (fs/dodir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Raw/"
            #(fs/re-directory-files % "wt*.fastq.gz")
            #(filter-fastq
              % :baseqc% 0.96 :sqc% 0.97 :marker "CTGTCTC"
              :outdir "/data1/NextSeq/TVOLab/KarenWGS012816/Fastq/Filtered"))
)

Refactor - add status atom support

Refactor - add status atom support


(ns babel.encyclopedia
  ^{:doc "real-world knowledge, expressed
as a map of implications"}
  (:refer-clojure)
  (:require
   [babel.exception :refer [exception]]
   #?(:cljs [babel.logjs :as log])
   #?(:clj [clojure.tools.logging :as log])
   [dag_unify.core :refer [strip-refs unify]]))

;; TODO: use clojure.core/isa? and clojure.core/derive where possible
;; in here, e.g.: (derive ::human ::animal)

(def encyc
  {
   {:activity true}  {:animate false
                      :artifact false
                      :consumable false
                      :part-of-human-body false}

   {:animate false}  {:human false
                      :pet false}

   {:animate true}   {:activity false
                      :artifact false
                      :living true
                      :mass false
                      :furniture false
                      :physical-object true
                      :part-of-human-body false
                      :drinkable false
                      :speakable false
                      :place false}

   {:artifact true}  {:animate false
                      :activity false
                      :living false
                      :physical-object true}

   {:buyable true}   {:human false
                      :part-of-human-body false}

   {:city true}      {:artifact true
                      :legible false
                      :place true}

   {:clothing true}  {:animate false
                      :artifact true
                      :consumable false
                      :place false
                      :physical-object true}
   {:consumable
    true}            {:activity false
                      :buyable true
                      :furniture false
                      :legible false
                      :human false
                      :part-of-human-body false
                      :pet false
                      :physical-object true
                      :place false
                      :speakable false}
   {:consumable
    false}           {:drinkable false
                      :edible false}

   {:drinkable true} {:consumable true
                      :edible false
                      :mass true}

   {:edible true}    {:consumable true
                      :drinkable false}

   {:event true}     {:buyable false
                      :physical-object false
                      :speakable false}

   {:furniture true} {:artifact true
                      :animate false
                      :buyable true
                      :consumable false
                      :legible false
                      :edible false
                      :place false
                      :speakable false}

   {:human true}     {:animate true
                      :buyable false
                      :consumable false
                      :legible false
                      :pet false
                      :part-of-human-body false
                      :physical-object true
                      :place false
                      :spec {:of {:human true}}}
   {:intelligent
    true}            {:animate true}

   {:living false}   {:animate false
                      :human false}

   {:living true}    {:artifact false
                      :place false}

   {:part-of-human-body
    true}            {:consumable false
                      :human false
                      :physical-object true}

   {:pet true}       {:animate true
                      :buyable true
                      :edible false
                      :human false
                      :spec {:of {:human true}}}

   {:physical-object
    false}           {:consumable false
                      :living false}
   {:physical-object
    true}            {:event false
                      :speakable false}

   {:place true}     {:activity false
                      :consumable false
                      :living false
                      :physical-object true
                      :speakable false
                      :spec {:of {:animate true}}}
   ;; some places could place additional
   ;; restrictions on owners (e.g. {:of {:human true}}).

   ;; <preds>
   {:pred :backpack} {:clothing true}

   {:pred :bag}      {:artifact true
                      :consumable false
                      :event false
                      :legible false
                      :place false
                      :spec {:of {:human true}}}

   {:pred :bicycle}  {:artifact true
                      :consumable false
                      :legible false
                      :place false
                      :spec {:of {:human true}}}

   {:pred :bread}    {:artifact true
                      :edible true}

   {:pred :car}      {:artifact true
                      :consumable false
                      :legible false
                      :place false}

   {:pred :coffee}   {:artifact true
                      :drinkable true}

   {:pred :espresso} {:artifact true
                      :drinkable true}

   {:pred :house}    {:artifact true
                      :city false
                      :consumable false
                      :place true
                      :legible false}

   {:pred :key}      {:animate false
                      :consumable false
                      :event false
                      :place false}

   {:pred :name}     {:physical-object false
                      :event false}

   {:pred :pizza}    {:artifact true
                      :edible true}

   {:pred :salad}    {:artifact true
                      :edible true}

   {:pred :shoe}     {:clothing true}

   {:pred :student}  {:human true}

   ;; The following inference rule is not
   ;; yet used, but intended as a way to integrate
   ;; verbs into the encyclopedia as we do with nouns.
   ;; Note the use of {:cat :verb} to distinguish this
   ;; from ..
   {:pred :study
    :cat :verb}  {:activity true
                  :subj {:human true}
                  :obj {:legible true}}

   ;; .. the next rule which applies to nouns only.
   {:pred :study
    :cat :noun}  {:place true}

   {:pred :vino}     {:artifact true
                      :drinkable true}
   ;; </preds>

   {:stupid true}    {:animate true}

   {:time true}      {:activity false
                      :living false
                      :place false}
   }
  )

;; {:aux false}: needed to prevent matching aux verbs because
;; they lack a {:pred} value.
(def verb-pred-defaults
  (map #(unify {:synsem {:aux false
                         :cat :verb}}
               {:synsem {:sem %}})

       [{:pred :abbracciare
         :active false
         :discrete false
         :obj {:animate true}
         :subj {:human true}}

        {:activity true
         :obj {:human true}
         :pred :aiutare}

        {:activity false
         :discrete false
         :pred :amare
         :subj {:human true}}

        {:pred :chat
         :subj {:human true}}

        {:pred :earn
         :subj {:human true}
         :obj {:human false}}

        {:pred :exit
         :subj {:animate true}}

        {:pred :get-dressed
         :subj {:human true}}

        {:pred :get-on
         :subj {:animate true}}

        {:pred :get-ready
         :subj {:human true}}

        {:pred :get-up
         :subj {:animate true}}

        {:pred :giocare
         :subj {:human true}
         :obj {:game true}}

        {:pred :go-out
         :subj {:animate true}}

        {:pred :go-upstairs
         :subj {:animate true}}

        {:pred :read
         :subj {:human true}
         :obj {:legible true}}

        {:pred :scold
         :subj {:human true}}

        {:pred :speak
         :subj {:human true}
         :obj {:speakable true}}

        {:pred :study
         :obj {:legible true}
         :subj {:human true}}

        {:pred :talk
         :subj {:human true}
         :obj {:speakable true}}

        {:pred :think
         :subj {:human true}}

        {:pred :vendere
         :subj {:human true}
         :obj {:human false}}

        {:pred :wake-up
         :subj {:animate true}}

        {:pred :wash
         :subj {:human true}}

        {:pred :win
         :subj {:human true}
         :obj {:human false}}

        {:pred :work-human
         :subj {:human true}}

        {:pred :work-nonhuman
         :subj {:human false}}

        {:pred :yell
         :subj {:human true}}]))

(defn null-sem-impl [input]
  "null sem-impl: simply return input."
  (log/trace (str "null-sem-impl:" (strip-refs input)))
  input)

(defn get-encyc [input k]
  (get encyc {k (get-in input [k])} {}))

(defn impl-list [input]
  (map (fn [kv]
         (let [k (first (first kv))]
           (get encyc {k (get-in input [k] :top)} {})))
       (keys encyc)))

(defn sem-impl [input & [original-input]]
  "expand input feature structures with semantic (really cultural) implicatures, e.g., if human, then not buyable or edible"
  (let [original-input (if original-input original-input
                           (do
                             (log/debug (str "original call of sem-impl: (" (get-in input [:pred]) ")" (strip-refs input)))
                             input))]
    (cond
      (keyword? input) input
      (empty? input) {}
      true
      (let [merged
            (unify input
                   (reduce unify (impl-list input)))]
        (log/debug (str "sem-impl so far: " merged))
        (if (not (= merged input)) ;; TODO: make this check more efficient: count how many rules were hit
          ;; rather than equality-check to see if merged has changed.
          (sem-impl merged original-input) ;; we've added some new information: more implications possible from that.

          ;; else, no more implications: done.
          (do
            (log/debug (str "sem-impl:" (strip-refs original-input) " -> " (strip-refs merged)))
            merged))))))

(ns babel.encyclopedia
  ^{:doc "real-world knowledge, expressed
as a map of implications"}
  (:refer-clojure)
  (:require
   [babel.exception :refer [exception]]
   #?(:cljs [babel.logjs :as log])
   #?(:clj [clojure.tools.logging :as log])
   [dag_unify.core :refer [strip-refs unify]]))

;; TODO: use clojure.core/isa? and clojure.core/derive where possible
;; in here, e.g.: (derive ::human ::animal)

(def encyc
  {
   {:activity true}  {:animate false
                      :artifact false
                      :consumable false
                      :part-of-human-body false}

   {:animate false}  {:human false
                      :pet false}

   {:animate true}   {:activity false
                      :artifact false
                      :living true
                      :mass false
                      :furniture false
                      :physical-object true
                      :part-of-human-body false
                      :drinkable false
                      :speakable false
                      :place false}

   {:artifact true}  {:animate false
                      :activity false
                      :living false
                      :physical-object true}

   {:buyable true}   {:human false
                      :part-of-human-body false}

   {:city true}      {:artifact true
                      :legible false
                      :place true}

   {:clothing true}  {:animate false
                      :artifact true
                      :consumable false
                      :place false
                      :physical-object true}
   {:consumable
    true}            {:activity false
                      :buyable true
                      :furniture false
                      :legible false
                      :human false
                      :part-of-human-body false
                      :pet false
                      :physical-object true
                      :place false
                      :speakable false}
   {:consumable
    false}           {:drinkable false
                      :edible false}

   {:drinkable true} {:consumable true
                      :edible false
                      :mass true}

   {:edible true}    {:consumable true
                      :drinkable false}

   {:event true}     {:buyable false
                      :physical-object false
                      :speakable false}

   {:furniture true} {:artifact true
                      :animate false
                      :buyable true
                      :consumable false
                      :legible false
                      :edible false
                      :place false
                      :speakable false}

   {:human true}     {:animate true
                      :buyable false
                      :consumable false
                      :legible false
                      :pet false
                      :part-of-human-body false
                      :physical-object true
                      :place false
                      :spec {:of {:human true}}}
   {:intelligent
    true}            {:animate true}

   {:living false}   {:animate false
                      :human false}

   {:living true}    {:artifact false
                      :place false}

   {:part-of-human-body
    true}            {:consumable false
                      :human false
                      :physical-object true}

   {:pet true}       {:animate true
                      :buyable true
                      :edible false
                      :human false
                      :spec {:of {:human true}}}

   {:physical-object
    false}           {:consumable false
                      :living false}
   {:physical-object
    true}            {:event false
                      :speakable false}

   {:place true}     {:activity false
                      :consumable false
                      :living false
                      :physical-object true
                      :speakable false
                      :spec {:of {:animate true}}}
   ;; some places could place additional
   ;; restrictions on owners (e.g. {:of {:human true}}).

   ;; <preds>
   {:pred :backpack} {:clothing true}

   {:pred :bag}      {:artifact true
                      :consumable false
                      :event false
                      :legible false
                      :place false
                      :spec {:of {:human true}}}

   {:pred :bicycle}  {:artifact true
                      :consumable false
                      :legible false
                      :place false
                      :spec {:of {:human true}}}

   {:pred :bread}    {:artifact true
                      :edible true}

   {:pred :car}      {:artifact true
                      :consumable false
                      :legible false
                      :place false}

   {:pred :coffee}   {:artifact true
                      :drinkable true}

   {:pred :espresso} {:artifact true
                      :drinkable true}

   {:pred :house}    {:artifact true
                      :city false
                      :consumable false
                      :place true
                      :legible false}

   {:pred :key}      {:animate false
                      :consumable false
                      :event false
                      :place false}

   {:pred :name}     {:physical-object false
                      :event false}

   {:pred :pizza}    {:artifact true
                      :edible true}

   {:pred :salad}    {:artifact true
                      :edible true}

   {:pred :shoe}     {:clothing true}

   {:pred :student}  {:human true}

   ;; The following inference rule is not
   ;; yet used, but intended as a way to integrate
   ;; verbs into the encyclopedia as we do with nouns.
   ;; Note the use of {:cat :verb} to distinguish this
   ;; from ..
   {:pred :study
    :cat :verb}  {:activity true
                  :subj {:human true}
                  :obj {:legible true}}

   ;; .. the next rule which applies to nouns only.
   {:pred :study
    :cat :noun}  {:place true}

   {:pred :vino}     {:artifact true
                      :drinkable true}
   ;; </preds>

   {:stupid true}    {:animate true}

   {:time true}      {:activity false
                      :living false
                      :place false}
   }
  )

;; {:aux false}: needed to prevent matching aux verbs because
;; they lack a {:pred} value.
(def verb-pred-defaults
  (map #(unify {:synsem {:aux false
                         :cat :verb}}
               {:synsem {:sem %}})

       [{:pred :abbracciare
         :active false
         :discrete false
         :obj {:animate true}
         :subj {:human true}}

        {:activity true
         :obj {:human true}
         :pred :aiutare}

        {:activity false
         :discrete false
         :pred :amare
         :subj {:human true}}

        {:pred :chat
         :subj {:human true}}

        {:pred :earn
         :subj {:human true}
         :obj {:human false}}

        {:pred :exit
         :subj {:animate true}}

        {:pred :get-dressed
         :subj {:human true}}

        {:pred :get-on
         :subj {:animate true}}

        {:pred :get-ready
         :subj {:human true}}

        {:pred :get-up
         :subj {:animate true}}

        {:pred :giocare
         :subj {:human true}
         :obj {:game true}}

        {:pred :go-out
         :subj {:animate true}}

        {:pred :go-upstairs
         :subj {:animate true}}

        {:pred :read
         :subj {:human true}
         :obj {:legible true}}

        {:pred :scold
         :subj {:human true}}

        {:pred :speak
         :subj {:human true}
         :obj {:speakable true}}

        {:pred :study
         :subj {:human true}
         :obj {:legible true}}

        {:pred :talk
         :subj {:human true}
         :obj {:speakable true}}

        {:pred :think
         :subj {:human true}}

        {:pred :vendere
         :subj {:human true}
         :obj {:human false}}

        {:pred :wake-up
         :subj {:animate true}}

        {:pred :wash
         :subj {:human true}}

        {:pred :win
         :subj {:human true}
         :obj {:human false}}

        {:pred :work-human
         :subj {:human true}}

        {:pred :work-nonhuman
         :subj {:human false}}

        {:pred :yell
         :subj {:human true}}]))

(defn null-sem-impl [input]
  "null sem-impl: simply return input."
  (log/trace (str "null-sem-impl:" (strip-refs input)))
  input)

(defn get-encyc [input k]
  (get encyc {k (get-in input [k])} {}))

(defn impl-list [input]
  (map (fn [kv]
         (let [k (first (first kv))]
           (get encyc {k (get-in input [k] :top)} {})))
       (keys encyc)))

(defn sem-impl [input & [original-input]]
  "expand input feature structures with semantic (really cultural) implicatures, e.g., if human, then not buyable or edible"
  (let [original-input (if original-input original-input
                           (do
                             (log/debug (str "original call of sem-impl: (" (get-in input [:pred]) ")" (strip-refs input)))
                             input))]
    (cond
      (keyword? input) input
      (empty? input) {}
      true
      (let [merged
            (unify input
                   (reduce unify (impl-list input)))]
        (log/debug (str "sem-impl so far: " merged))
        (if (not (= merged input)) ;; TODO: make this check more efficient: count how many rules were hit
          ;; rather than equality-check to see if merged has changed.
          (sem-impl merged original-input) ;; we've added some new information: more implications possible from that.

          ;; else, no more implications: done.
          (do
            (log/debug (str "sem-impl:" (strip-refs original-input) " -> " (strip-refs merged)))
            merged))))))

add semantics for {:pred :study}

add semantics for {:pred :study}


(ns braid.client.state
  (:require [reagent.ratom :include-macros true :refer-macros [reaction]]
            [braid.client.store :as store]
            [clojure.set :refer [union intersection subset?]]
[braid.client.state.subscription :refer [subscription]]
            [braid.client.quests.subscriptions])
  (:import goog.Uri))

(defn subscribe
  "Get a reaction for the given data.
  In one-argument form, this looks like `(subscribe [:key arg1 arg2])`
  Two-argument form enables you to have a subscription which takes reactions or
  atoms as arguments, e.g.
  `(let [foo (subscribe [:some-key 1])
         bar (r/atom ...)
         baz (subscribe [:other-key 2] [foo bar])]
     ...)"
  ([v] (subscription store/app-state v))
  ([v dynv] ; Dynamic subscription
   (let [dyn-vals (reaction (mapv deref dynv))
         sub (reaction (subscription store/app-state (into v @dyn-vals)))]
     (reaction @@sub))))

(defmethod subscription :default
  [_ [sub-name args]]
  (ex-info (str "No subscription for " sub-name) {::name sub-name ::args args}))

(defmethod subscription :active-group
  [state _]
  (let [group-id (reaction (:open-group-id @state))]
    (reaction (get-in @state [:groups @group-id]))))

(defmethod subscription :groups
  [state _]
  (reaction (vals (:groups @state))))

(defn order-groups
  "Helper function to impose an order on groups.
  This is a seperate function (instead of inline in :ordered-groups because the
  index route needs to be able to call this to find the first group"
  [groups group-order]
  (if (nil? group-order)
    groups
    (let [ordered? (comp boolean (set group-order) :id)
          {ord true unord false} (group-by ordered? groups)
          by-id (group-by :id groups)]
      (concat
        (map (comp first by-id) group-order)
        unord))))

(defmethod subscription :ordered-groups
  [state _]
  (let [groups (subscription state [:groups])
        group-order (subscription state [:user-preference :groups-order])]
    (reaction (order-groups @groups @group-order))))

(defmethod subscription :group-threads
  [state [_ group-id]]
  (reaction (->> (get-in @state [:group-threads group-id])
                 (map #(get-in @state [:threads %]))
                 doall)))

(defmethod subscription :group-admins
  [state [_ group-id]]
  (reaction (get-in @state [:groups group-id :admins])))

(defmethod subscription :group-bots
  [state [_ group-id]]
  (reaction (get-in @state [:groups group-id :bots])))

(defmethod subscription :user
  [state [_ user-id]]
  (reaction (if-let [u (get-in @state [:users user-id])]
              u
              (let [g-id (@state :open-group-id)
                    group-bots (get-in @state [:groups g-id :bots])]
                (-> group-bots
                    (->> (filter (fn [b] (= (b :user-id) user-id))))
                    first
                    (assoc :bot? true))))))

(defmethod subscription :users
  [state _]
  (reaction (@state :users)))

(defmethod subscription :user-is-group-admin?
  [state [_ user-id group-id]]
  (reaction (contains? (get-in @state [:groups group-id :admins]) user-id)))

(defmethod subscription :current-user-is-group-admin?
  [state [_ group-id]]
  (reaction (->> (get-in @state [:session :user-id])
                 (contains? (set (get-in @state [:groups group-id :admins]))))))

(defmethod subscription :open-thread-ids
  [state _]
  (reaction (get-in @state [:user :open-thread-ids])))

(defmethod subscription :group-unread-count
  [state [_ group-id]]
  (let [open-thread-ids (reaction (get-in @state [:user :open-thread-ids]))
        threads (reaction (@state :threads))
        tags (reaction (@state :tags))
        users (reaction (@state :users))
        thread-in-group? (fn [thread] (= group-id (thread :group-id)))
        thread-unseen? (fn [thread] (> (->> (thread :messages)
                                            (map :created-at)
                                            (apply max))
                                       (thread :last-open-at)))
        unseen-threads (reaction
                         (->>
                           (select-keys @threads @open-thread-ids)
                           vals
                           (filter thread-in-group?)
                           (filter thread-unseen?)))]
    (reaction (count @unseen-threads))))

(defmethod subscription :page
  [state _]
  (reaction (@state :page)))

(defmethod subscription :page-path
  [state _]
  (let [page (subscription state [:page])
        open-group (subscription state [:open-group-id])]
    (reaction
      ; depend on page & group, so when the page changes this sub updates too
      (do @page
          @open-group
          (.getPath (.parse Uri js/window.location))))))

(defmethod subscription :thread
  [state [_ thread-id]]
  (reaction (get-in @state [:threads thread-id])))

(defmethod subscription :threads
  [state _]
  (reaction (@state :threads)))

(defmethod subscription :page-id
  [state _]
  (reaction (get-in @state [:page :id])))

(defmethod subscription :open-threads
  [state [_ group-id]]
  (let [open-thread-ids (reaction (get-in @state [:user :open-thread-ids]))
        threads (reaction (@state :threads))
        open-threads (reaction (vals (select-keys @threads @open-thread-ids)))]
    (reaction
      (doall (filter (fn [thread] (= (thread :group-id) group-id))
                     @open-threads)))))

(defmethod subscription :recent-threads
  [state [_ group-id]]
  (let [open-thread-ids (reaction (get-in @state [:user :open-thread-ids]))
        threads (reaction (@state :threads))]
    (reaction
      (doall (filter (fn [thread] (and
                                    (= (thread :group-id) group-id)
                                    (not (contains? @open-thread-ids (thread :id)))))
                     (vals @threads))))))

(defmethod subscription :users-in-group
  [state [_ group-id]]
  (reaction
    (->> (@state :users)
         vals
         (filter (fn [u] (contains? (set (u :group-ids)) group-id)))
         doall)))

(defmethod subscription :open-group-id
  [state _]
  (reaction (get-in @state [:open-group-id])))

(defmethod subscription :users-in-open-group
  [state [_ status]]
  (reaction (->> @(subscription state state [:users-in-group (@state :open-group-id)])
                 (filter (fn [u] (= status (u :status))))
                 doall)))

(defmethod subscription :user-id
  [state _]
  (reaction (get-in @state [:session :user-id])))

(defmethod subscription :tags
  [state _]
  (reaction (vals (get-in @state [:tags]))))

(defmethod subscription :user-subscribed-to-tag?
  [state [_ tag-id]]
  (reaction (contains? (set (get-in @state [:user :subscribed-tag-ids])) tag-id)))

(defmethod subscription :group-subscribed-tags
  [state _]
  (reaction
    (into ()
          (comp
            (filter (fn [tag] @(subscription state [:user-subscribed-to-tag?  (tag :id)])))
            (filter (fn [tag] (= (get-in @state [:open-group-id]) (tag :group-id)))))
          (vals (get-in @state [:tags])))))

(defmethod subscription :user-avatar-url
  [state [_ user-id]]
  (reaction (get-in @state [:users user-id :avatar])))

(defmethod subscription :user-status
  [state [_ user-id]]
  (reaction (get-in @state [:users user-id :status])))

(defmethod subscription :search-query
  [state _]
  (reaction (get-in @state [:page :search-query])))

(defmethod subscription :tags-for-thread
  [state [_ thread-id]]
  (let [tag-ids (reaction (get-in @state [:threads thread-id :tag-ids]))
        tags (reaction (doall
                         (map (fn [thread-id]
                                (get-in @state [:tags thread-id])) @tag-ids)))]
    tags))

(defmethod subscription :mentions-for-thread
  [state [_ thread-id]]
  (let [mention-ids (reaction (get-in @state [:threads thread-id :mentioned-ids]))
        mentions (reaction (doall
                             (map (fn [user-id]
                                    (get-in @state [:users user-id])) @mention-ids)))]
    mentions))

(defmethod subscription :messages-for-thread
  [state [_ thread-id]]
  (reaction (get-in @state [:threads thread-id :messages])))

(defmethod subscription :thread-open?
  [state [_ thread-id]]
  (reaction (contains? (set (get-in @state [:user :open-thread-ids])) thread-id)))

(defmethod subscription :thread-focused?
  [state [_ thread-id]]
  (reaction (= thread-id (get-in @state [:focused-thread-id]))))

(defmethod subscription :thread-last-open-at
  [state [_ thread-id]]
  (reaction (get-in @state [:threads thread-id :last-open-at])))

(defmethod subscription :thread-new-message
  [state [_ thread-id]]
  (reaction (if-let [th (get-in @state [:threads thread-id])]
              (get th :new-message "")
              (get-in @state [:new-thread-msg thread-id] ""))))

(defmethod subscription :errors
  [state _]
  (reaction (get-in @state [:errors])))

(defmethod subscription :login-state
  [state _]
  (reaction (get-in @state [:login-state])))

(defmethod subscription :tag
  [state [_ tag-id]]
  (reaction (get-in @state [:tags tag-id])))

(defmethod subscription :group-for-tag
  [state [_ tag-id]]
  (reaction (get-in @state [:tags tag-id :group-id])))

(defmethod subscription :nickname
  [state [_ user-id]]
  (reaction (get-in @state [:users user-id :nickname])))

(defmethod subscription :invitations
  [state _]
  (reaction (get-in @state [:invitations])))

(defmethod subscription :pagination-remaining
  [state _]
  (reaction (@state :pagination-remaining)))

(defmethod subscription :user-subscribed-tag-ids
  [state _]
  (reaction (set (get-in @state [:user :subscribed-tag-ids]))))

(defmethod subscription :connected?
  [state _]
  (reaction (not-any? (fn [[k _]] (= :disconnected k)) (@state :errors))))

(defmethod subscription :new-thread-id
  [state _]
  (reaction (get @state :new-thread-id)))

(defmethod subscription :user-preference
  [state [_ pref]]
  (reaction (get-in @state [:preferences pref])))

Fix indentation

Fix indentation


(ns chat.server.migrate
  (:require [chat.server.db :as db]
            [datomic.api :as d]))

(defn migrate-2015-07-29
  "Schema changes for groups"
  []
  (db/with-conn
    (d/transact db/*conn*
      [{:db/ident :tag/group
        :db/valueType :db.type/ref
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}

       ; groups
       {:db/ident :group/id
        :db/valueType :db.type/uuid
        :db/cardinality :db.cardinality/one
        :db/unique :db.unique/identity
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :group/name
        :db/valueType :db.type/string
        :db/cardinality :db.cardinality/one
        :db/unique :db.unique/identity
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :group/user
        :db/valueType :db.type/ref
        :db/cardinality :db.cardinality/many
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}]))
  (println "You'll now need to create a group and add existing users & tags to that group"))

(defn create-group-for-users-and-tags
  "Helper function for migrate-2015-07-29 - give a group name to create that
  group and add all existing users and tags to that group"
  [group-name]
  (db/with-conn
    (let [group (db/create-group! {:id (db/uuid) :name group-name})
          all-users (->> (d/q '[:find ?u :where [?u :user/id]] (d/db db/*conn*)) (map first))
          all-tags (->> (d/q '[:find ?t :where [?t :tag/id]] (d/db db/*conn*)) (map first))]
      (d/transact db/*conn* (mapv (fn [u] [:db/add [:group/id (group :id)] :group/user u]) all-users))
      (d/transact db/*conn* (mapv (fn [t] [:db/add t :tag/group [:group/id (group :id)]]) all-tags)))))

(defn migrate-2015-08-26
  "schema change for invites"
  []
  (db/with-conn
    (d/transact db/*conn*
      [
       ; invitations
       {:db/ident :invite/id
        :db/valueType :db.type/uuid
        :db/cardinality :db.cardinality/one
        :db/unique :db.unique/identity
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :invite/group
        :db/valueType :db.type/ref
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :invite/from
        :db/valueType :db.type/ref
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :invite/to
        :db/valueType :db.type/string
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :invite/created-at
        :db/valueType :db.type/instant
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       ])))

(ns chat.server.migrate
  (:require [chat.server.db :as db]
            [datomic.api :as d]))

(defn migrate-2015-12-12
  "Make content fulltext"
  []
  ; rename content
  (db/with-conn (d/transact db/*conn* [{:db/id :message/content :db/ident :message/content-old}]))
  (db/with-conn (d/transact db/*conn* [{:db/ident :message/content
                                        :db/valueType :db.type/string
                                        :db/fulltext true
                                        :db/cardinality :db.cardinality/one
                                        :db/id #db/id [:db.part/db]
                                        :db.install/_attribute :db.part/db}]))
  (let [messages (db/with-conn (->> (d/q '[:find (pull ?e [:message/id
                                                           :message/content-old
                                                           :message/created-at
                                                           {:message/user [:user/id]}
                                                           {:message/thread [:thread/id]}])
                                           :where [?e :message/id]]
                                         (d/db db/*conn*))
                                    (map first)))]
    (db/with-conn
      (let [msg-tx (->> messages
                        (map (fn [msg]
                               [:db/add [:message/id (msg :message/id)]
                                :message/content (msg :message/content-old)])))]
        (d/transact db/*conn* (doall msg-tx))))))

(defn migrate-2015-07-29
  "Schema changes for groups"
  []
  (db/with-conn
    (d/transact db/*conn*
      [{:db/ident :tag/group
        :db/valueType :db.type/ref
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}

       ; groups
       {:db/ident :group/id
        :db/valueType :db.type/uuid
        :db/cardinality :db.cardinality/one
        :db/unique :db.unique/identity
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :group/name
        :db/valueType :db.type/string
        :db/cardinality :db.cardinality/one
        :db/unique :db.unique/identity
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :group/user
        :db/valueType :db.type/ref
        :db/cardinality :db.cardinality/many
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}]))
  (println "You'll now need to create a group and add existing users & tags to that group"))

(defn create-group-for-users-and-tags
  "Helper function for migrate-2015-07-29 - give a group name to create that
  group and add all existing users and tags to that group"
  [group-name]
  (db/with-conn
    (let [group (db/create-group! {:id (db/uuid) :name group-name})
          all-users (->> (d/q '[:find ?u :where [?u :user/id]] (d/db db/*conn*)) (map first))
          all-tags (->> (d/q '[:find ?t :where [?t :tag/id]] (d/db db/*conn*)) (map first))]
      (d/transact db/*conn* (mapv (fn [u] [:db/add [:group/id (group :id)] :group/user u]) all-users))
      (d/transact db/*conn* (mapv (fn [t] [:db/add t :tag/group [:group/id (group :id)]]) all-tags)))))

(defn migrate-2015-08-26
  "schema change for invites"
  []
  (db/with-conn
    (d/transact db/*conn*
      [
       ; invitations
       {:db/ident :invite/id
        :db/valueType :db.type/uuid
        :db/cardinality :db.cardinality/one
        :db/unique :db.unique/identity
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :invite/group
        :db/valueType :db.type/ref
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :invite/from
        :db/valueType :db.type/ref
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :invite/to
        :db/valueType :db.type/string
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       {:db/ident :invite/created-at
        :db/valueType :db.type/instant
        :db/cardinality :db.cardinality/one
        :db/id #db/id [:db.part/db]
        :db.install/_attribute :db.part/db}
       ])))

add migration to make msg content fulltext indexed


(ns my-money.core
  (:require [reagent.core :as r]
            [reagent.session :as session]
            [secretary.core :as secretary :include-macros true]
            [goog.events :as events]
            [goog.history.EventType :as HistoryEventType]
            [markdown.core :refer [md->html]]
            [my-money.ajax :refer [load-interceptors!]]
            [ajax.core :refer [GET POST]])
  (:import goog.History))

(defn nav-link [uri title page collapsed?]
  [:li.nav-item
   {:class (when (= page (session/get :page)) "active")}
   [:a.nav-link
    {:href uri
     :on-click #(reset! collapsed? true)} title]])

(defn navbar []
  (let [collapsed? (r/atom true)]
    (fn []
      [:nav.navbar.navbar-dark.bg-primary
       [:button.navbar-toggler.hidden-sm-up
        {:on-click #(swap! collapsed? not)} "☰"]
       [:div.collapse.navbar-toggleable-xs
        (when-not @collapsed? {:class "in"})
        [:a.navbar-brand {:href "#/"} "my-money"]
        [:ul.nav.navbar-nav
         [nav-link "#/" "Home" :home collapsed?]
         [nav-link "#/about" "About" :about collapsed?]]]])))

(defn about-page []
  [:div.container
   [:div.row
    [:div.col-md-12
     "this is the story of my-money... work in progress"]]])

(defn home-page []
  [:div.container
   (when-let [docs (session/get :docs)]
     [:div.row>div.col-sm-12
      [:div {:dangerouslySetInnerHTML
             {:__html (md->html docs)}}]])])

(def pages
  {:home #'home-page
   :about #'about-page})

(defn page []
  [(pages (session/get :page))])

;; -------------------------
;; Routes
(secretary/set-config! :prefix "#")

(secretary/defroute "/" []
  (session/put! :page :home))

(secretary/defroute "/about" []
  (session/put! :page :about))

;; -------------------------
;; History
;; must be called after routes have been defined
(defn hook-browser-navigation! []
  (doto (History.)
        (events/listen
          HistoryEventType/NAVIGATE
          (fn [event]
              (secretary/dispatch! (.-token event))))
        (.setEnabled true)))

;; -------------------------
;; Initialize app
(defn fetch-docs! []
  (GET "/docs" {:handler #(session/put! :docs %)}))

(defn mount-components []
  (r/render [#'navbar] (.getElementById js/document "navbar"))
  (r/render [#'page] (.getElementById js/document "app")))

(defn init! []
  (load-interceptors!)
  (fetch-docs!)
  (hook-browser-navigation!)
  (mount-components))

(ns my-money.core
  (:require [reagent.core :as r]
            [reagent.session :as session]
            [secretary.core :as secretary :include-macros true]
            [goog.events :as events]
            [goog.history.EventType :as HistoryEventType]
            [markdown.core :refer [md->html]]
            [my-money.ajax :refer [load-interceptors!]]
            [ajax.core :refer [GET POST]])
  (:import goog.History))

(defn nav-link [uri title page collapsed?]
  [:li.nav-item
   {:class (when (= page (session/get :page)) "active")}
   [:a.nav-link
    {:href uri
     :on-click #(reset! collapsed? true)} title]])

(defn navbar []
  (let [collapsed? (r/atom true)]
    (fn []
      [:nav.navbar.navbar-dark.bg-primary
       [:button.navbar-toggler.hidden-sm-up
        {:on-click #(swap! collapsed? not)} "☰"]
       [:div.collapse.navbar-toggleable-xs
        (when-not @collapsed? {:class "in"})
        [:a.navbar-brand {:href "#/"} "my-money"]
        [:ul.nav.navbar-nav
         [nav-link "#/" "Home" :home collapsed?]
         [nav-link "#/submit" "Submit" :submit collapsed?]
         [nav-link "#/about" "About" :about collapsed?]]]])))

(defn submit-page []
  [:div.container
   [:form
    [:div.form-group
     [:label {:for "file-input"} "Add your bank csv"]
     [:input {:class "form-control-file"
              :id "file-input"
              :type "file"}]]]])

(defn about-page []
  [:div.container
   [:div.row
    [:div.col-md-12
     "this is the story of my-money... work in progress"]]])

(defn home-page []
  [:div.container
   (when-let [docs (session/get :docs)]
     [:div.row>div.col-sm-12
      [:div {:dangerouslySetInnerHTML
             {:__html (md->html docs)}}]])])

(def pages
  {:home #'home-page
   :about #'about-page
   :submit #'submit-page})

(defn page []
  [(pages (session/get :page))])

;; -------------------------
;; Routes
(secretary/set-config! :prefix "#")

(secretary/defroute "/" []
  (session/put! :page :home))

(secretary/defroute "/submit" []
  (session/put! :page :submit))

(secretary/defroute "/about" []
  (session/put! :page :about))

;; -------------------------
;; History
;; must be called after routes have been defined
(defn hook-browser-navigation! []
  (doto (History.)
        (events/listen
          HistoryEventType/NAVIGATE
          (fn [event]
              (secretary/dispatch! (.-token event))))
        (.setEnabled true)))

;; -------------------------
;; Initialize app
(defn fetch-docs! []
  (GET "/docs" {:handler #(session/put! :docs %)}))

(defn mount-components []
  (r/render [#'navbar] (.getElementById js/document "navbar"))
  (r/render [#'page] (.getElementById js/document "app")))

(defn init! []
  (load-interceptors!)
  (fetch-docs!)
  (hook-browser-navigation!)
  (mount-components))

Add file input form on a new page.

Add file input form on a new page.

- To be used for submitting bank event csv to server


(ns cljs-api-gen.docset
  (:refer-clojure :exclude [replace])
  (:require
    [clojure.string :refer [replace]]
    [cljs-api-gen.write :refer [get-last-written-result]]
    [cljs-api-gen.encode :refer [decode-fullname]]
    [clojure.java.jdbc :as j]
    [me.raynes.fs :refer [delete-dir copy copy-dir list-dir base-name mkdirs]]
    ))

;; NOTE: you have to run docset/run-all.sh first to download/process the
;;       rendered html pages of our markdown docs from github.

;; code derived from Lokeshwaran's (@dlokesh) project:
;; https://github.com/dlokesh/clojuredocs-docset

(def offline-path "docset/offline")
(def docset-path "docset/cljs.docset")
(def docset-docs-path (str docset-path "/Contents/Resources/Documents"))
(def db-path (str docset-path "/Contents/Resources/docSet.dsidx"))

(def sqlite-db {:classname "org.sqlite.JDBC"
			          :subprotocol "sqlite"
                :subname db-path})

(defn resolve-path [& paths]
  (apply str "offline/github.com/cljsinfo/api-refs/blob/catalog/" paths))

(def type->dash
  {"var"                 "Variable"
   "dynamic var"         "Variable"
   "protocol"            "Protocol"
   "type"                "Type"
   "macro"               "Macro"
   "function"            "Function"
   "special form"        "Statement" ;; <-- Pending "Special Form"
   "special form (repl)" "Statement" ;;     (avaiable in next Dash version)
   })

(defn create!
  []

  (let [result (get-last-written-result)
        syms (merge (-> result :library-api :symbols)
                    (-> result :compiler-api :symbols))
        namespaces (set (map :ns (vals syms)))]

    (delete-dir docset-path)

    (mkdirs docset-docs-path)

    ;; copy over offline pages
    (copy-dir offline-path docset-docs-path)

    ;; copy over resources
    (copy "docset/icon.png" (str docset-path "/icon.png"))
    (copy "docset/Info.plist" (str docset-path "/Contents/Info.plist"))

    ;; reset/create tables
    (j/db-do-commands sqlite-db
       "DROP TABLE IF EXISTS searchIndex"
       "CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT)"
       "CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path)")

    (j/insert! sqlite-db :searchIndex
       ;; insert categories
       {:name "Library API"  :type "Category" :path (resolve-path "README.html#library-api-reference")}
       {:name "Compiler API" :type "Category" :path (resolve-path "README.html#compiler-api-reference")}

       ;; insert sections
       {:name "Overview"                :type "Section" :path (resolve-path "README.html")}
       {:name "History"                 :type "Section" :path (resolve-path "HISTORY.html")}
       {:name "Not Ported From Clojure" :type "Section" :path (resolve-path "UNPORTED.html")}
       )

    ;; insert namespaces
    (apply j/insert! sqlite-db :searchIndex
      (for [ns- namespaces]
        {:name ns- :type "Namespace" :path (resolve-path "README.html#" (replace ns- "." ""))}))

    ;; insert symbols
    (let [refs-path (str docset-docs-path "/" (resolve-path "refs"))]
      (apply j/insert! sqlite-db :searchIndex
        (for [ref-file (list-dir refs-path)]
          (let [encoded-name
                (second
                  (re-find #"github\.com/cljsinfo/api-refs/blob/catalog/refs/(.*)\.md "
                           (slurp ref-file)))
                full-name (decode-fullname encoded-name)
                item (get syms full-name)]
            {:name (:name item)
             :type (type->dash (:type item))
             :path (resolve-path "refs/" encoded-name ".html")}
            ))))
    ))

(ns cljs-api-gen.docset
  (:refer-clojure :exclude [replace])
  (:require
    [clojure.string :refer [replace]]
    [cljs-api-gen.write :refer [get-last-written-result]]
    [cljs-api-gen.encode :refer [decode-fullname]]
    [clojure.java.jdbc :as j]
    [me.raynes.fs :refer [delete-dir copy copy-dir list-dir base-name mkdirs]]
    ))

;; NOTE: you have to run docset/run-all.sh first to download/process the
;;       rendered html pages of our markdown docs from github.

;; code derived from Lokeshwaran's (@dlokesh) project:
;; https://github.com/dlokesh/clojuredocs-docset

(def offline-path "docset/offline")
(def docset-path "docset/cljs.docset")
(def docset-docs-path (str docset-path "/Contents/Resources/Documents"))
(def db-path (str docset-path "/Contents/Resources/docSet.dsidx"))

(def sqlite-db {:classname "org.sqlite.JDBC"
			          :subprotocol "sqlite"
                :subname db-path})

(defn resolve-path [& paths]
  (apply str "offline/github.com/cljsinfo/api-refs/blob/catalog/" paths))

(def type->dash
  {"var"                 "Variable"
   "dynamic var"         "Variable"
   "protocol"            "Protocol"
   "type"                "Type"
   "macro"               "Macro"
   "function"            "Function"
   "special form"        "Statement" ;; <-- Pending "Special Form"
   "special form (repl)" "Statement" ;;     (avaiable in next Dash version)
   })

(defn create!
  []

  (let [result (get-last-written-result)
        syms (merge (-> result :library-api :symbols)
                    (-> result :compiler-api :symbols))
        namespaces (set (map :ns (vals syms)))]

    (delete-dir docset-path)

    (mkdirs docset-docs-path)

    ;; copy over offline pages
    (copy-dir offline-path docset-docs-path)

    ;; copy over resources
    (copy "docset/icon.png" (str docset-path "/icon.png"))
    (copy "docset/Info.plist" (str docset-path "/Contents/Info.plist"))

    ;; reset/create tables
    (j/db-do-commands sqlite-db
       "DROP TABLE IF EXISTS searchIndex"
       "CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT)"
       "CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path)")

    (j/insert! sqlite-db :searchIndex
       ;; insert categories
       {:name "Library API"  :type "Category" :path (resolve-path "README.html#library-api-reference")}
       {:name "Compiler API" :type "Category" :path (resolve-path "README.html#compiler-api-reference")}

       ;; insert sections
       {:name "Overview"                :type "Section" :path (resolve-path "README.html")}
       {:name "History"                 :type "Section" :path (resolve-path "HISTORY.html")}
       {:name "Not Ported From Clojure" :type "Section" :path (resolve-path "UNPORTED.html")}
       )

    ;; insert namespaces
    (apply j/insert! sqlite-db :searchIndex
      (for [ns- namespaces]
        {:name ns- :type "Namespace" :path (resolve-path "README.html#" (replace ns- "." ""))}))

    ;; insert symbols
    (let [refs-path (str docset-docs-path "/" (resolve-path "refs"))]
      (apply j/insert! sqlite-db :searchIndex
        (for [ref-file (list-dir refs-path)]
          (let [encoded-name
                (second
                  (re-find #"github\.com/cljsinfo/api-refs/blob/catalog/refs/(.*)\.md "
                           (slurp ref-file)))
                full-name (decode-fullname encoded-name)
                item (get syms full-name)]
            {:name (:name item)
             :type (type->dash (:type item))
             :path (resolve-path "refs/" (base-name ref-file))}
            ))))
    ))

fix filename symbol resolver

fix filename symbol resolver


(ns aspire.core
  (:require [aspire.conf :as a-conf]
            [aspire.cli :as a-cli]
            [aspire.util :as a-util]
            [aspire.sqldb-ddl :as a-sqldb-ddl]
            [aspire.sqldb :as a-sqldb]
            [aspire.web :as a-web]))

(def jetty-args
  [:port :join?])

(defn system
  "See http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded"
  [conf]
  {:conf conf})

(defn start-database!
  [system]
  (assoc system :sql-db-pool
         (a-sqldb/default-connection! (get-in system [:conf :conf-sql-db]))))

(defn stop-database!
  [system]
  (.close (:datasource @(:sql-db-pool system)))
  (dissoc system :sql-db-pool))

(defn start-http!
  [system]
  (let [args (select-keys (get-in system [:conf :conf-web]) jetty-args)]
    (assoc system :jetty-instance (a-web/run! args))))

(defn stop-http!
  [system]
  (.stop (:jetty-instance system))
  (dissoc system :jetty-instance))

;; This defines how the system should be started and stopped.
(def all-sub-systems
  {:jetty-instance {:startup start-http!
                    :shutdown stop-http!}
   :sql-db-pool {:startup start-database!
                 :shutdown stop-database!}})

;; This defines the order in which the system is started up.
(def startup-order
  [:sql-db-pool :jetty-instance])

;; This defines the order in which the system is shutdown.
(def shutdown-order (into [] (reverse startup-order)))

(defn process-single-interaction!
  "Causes side-effects, such as stopping or starting the HTTP server
  or connecting or disconnecting from a database. Whatever task gets
  called has full access to the global state of the system (third arg
  passed becomes the first and only arg passed to the task fn.)"
  [sub-sys task system]
  (a-util/output! true (str "Interactions with [" sub-sys "] executing [" task "]"))
  ((get-in all-sub-systems [sub-sys task]) system))

(defn process-ordered-interaction!
  "Does the same task to several sub systems in the order that they're
  provided. Uses sub-system task map for calling task fns."
  [ordered-sub-systems task system]
  (loop [remaining-sub-systems ordered-sub-systems
         system-state system]
    (if (empty? remaining-sub-systems)
      system-state
      (let [sub-sys (first remaining-sub-systems)]
        (recur (rest remaining-sub-systems)
               (process-single-interaction! sub-sys task system-state))))))

(defn start!
  "Performs side effects to initialize the system, acquire resources,
  and start it running. Returns an updated instance of the system."
  ([system]
   (process-ordered-interaction! startup-order :startup system))
  ([system sub-sys]
   (process-single-interaction! sub-sys :startup system)))

(defn stop!
  "Performs side effects to shut down the system and release its
  resources. Returns an updated instance of the system."
  ([system]
   (process-ordered-interaction! shutdown-order :shutdown system))
  ([system sub-sys]
   (process-single-interaction! sub-sys :shutdown system)))

(defn opts-and-conf-from-args
  [args]
  (let [opts (a-cli/get-opts args)]
    [opts
     (a-conf/load-configs (:config-path opts))]))

(defn -main [& args]
  ;; work around dangerous default behaviour in Clojure
  (alter-var-root #'*read-eval* (constantly false))

  (let [opts (a-cli/get-opts args)
        conf (a-conf/load-configs (:config-path opts))
        db (:conf-sql-db conf)
        system (system conf)]
    (a-util/output! (:verbose opts) :opts opts :system system :conf conf :db db)

    (cond
      (:init-sql opts) (a-sqldb-ddl/init! db)
      (:zero-out-sql-db opts) (a-sqldb-ddl/print-drop-sql!)
      :else (start! system))))

(ns aspire.core
  (:require [aspire.conf :as a-conf]
            [aspire.cli :as a-cli]
            [aspire.util :as a-util]
            [aspire.sqldb-ddl :as a-sqldb-ddl]
            [aspire.sqldb :as a-sqldb]
            [aspire.web :as a-web]))

(def jetty-args
  [:port :join?])

(defn system
  "See http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded"
  [conf]
  {:conf conf})

(defn start-database!
  [system]
  (assoc system :sql-db-pool
         (a-sqldb/default-connection! (get-in system [:conf :conf-sql-db]))))

(defn stop-database!
  [system]
  (.close (:datasource @(:sql-db-pool system)))
  (dissoc system :sql-db-pool))

(defn start-http!
  [system]
  (let [args (select-keys (get-in system [:conf :conf-web]) jetty-args)]
    (assoc system :jetty-instance (a-web/run! args))))

(defn stop-http!
  [system]
  (.stop (:jetty-instance system))
  (dissoc system :jetty-instance))

;; This defines how the system should be started and stopped.
(def all-sub-systems
  {:jetty-instance {:startup start-http!
                    :shutdown stop-http!}
   :sql-db-pool {:startup start-database!
                 :shutdown stop-database!}})

;; This defines the order in which the system is started up.
(def startup-order
  [:sql-db-pool :jetty-instance])

;; This defines the order in which the system is shut down.
(def shutdown-order (into [] (reverse startup-order)))

(defn process-single-interaction!
  "Causes side-effects, such as stopping or starting the HTTP server
  or connecting or disconnecting from a database. Whatever task gets
  called has full access to the global state of the system (third arg
  passed becomes the first and only arg passed to the task fn.)"
  [sub-sys task system]
  (a-util/output! true (str "Interactions with [" sub-sys "] executing [" task "]"))
  ((get-in all-sub-systems [sub-sys task]) system))

(defn process-ordered-interaction!
  "Does the same task to several sub systems in the order that they're
  provided. Uses sub-system task map for calling task fns."
  [ordered-sub-systems task system]
  (loop [remaining-sub-systems ordered-sub-systems
         system-state system]
    (if (empty? remaining-sub-systems)
      system-state
      (let [sub-sys (first remaining-sub-systems)]
        (recur (rest remaining-sub-systems)
               (process-single-interaction! sub-sys task system-state))))))

(defn start!
  "Performs side effects to initialize the system, acquire resources,
  and start it running. Returns an updated instance of the system."
  ([system]
   (process-ordered-interaction! startup-order :startup system))
  ([system sub-sys]
   (process-single-interaction! sub-sys :startup system)))

(defn stop!
  "Performs side effects to shut down the system and release its
  resources. Returns an updated instance of the system."
  ([system]
   (process-ordered-interaction! shutdown-order :shutdown system))
  ([system sub-sys]
   (process-single-interaction! sub-sys :shutdown system)))

(defn opts-and-conf-from-args
  [args]
  (let [opts (a-cli/get-opts args)]
    [opts
     (a-conf/load-configs (:config-path opts))]))

(defn -main [& args]
  ;; work around dangerous default behaviour in Clojure
  (alter-var-root #'*read-eval* (constantly false))

  (let [opts (a-cli/get-opts args)
        conf (a-conf/load-configs (:config-path opts))
        db (:conf-sql-db conf)
        system (system conf)]
    (a-util/output! (:verbose opts) :opts opts :system system :conf conf :db db)

    (cond
      (:init-sql opts) (a-sqldb-ddl/init! db)
      (:zero-out-sql-db opts) (a-sqldb-ddl/print-drop-sql!)
      :else (start! system))))

Update core.clj

Update core.clj