Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3dcba6c37 | ||
|
|
56fcacc2d8 | ||
|
|
ff1ba2dfde | ||
|
|
75a91f7f7b | ||
|
|
30d732f708 | ||
|
|
cfb63cb473 | ||
|
|
ed7f4ef668 | ||
|
|
c5d4e83d44 | ||
|
|
1fa115db79 | ||
|
|
d5c6360f88 | ||
|
|
b7af65b705 | ||
|
|
2c53b516d6 | ||
|
|
10b054db25 | ||
|
|
b972e6e69f | ||
|
|
440206e924 | ||
|
|
6e266c787b | ||
|
|
82b43ddf90 | ||
|
|
1b0d58d1dd | ||
|
|
addff66470 | ||
|
|
d4bc2490ff | ||
|
|
bce64fc8f6 | ||
|
|
fd843a5425 | ||
|
|
33c1d42e63 | ||
|
|
f5e8ffd82d | ||
|
|
6867f6ffbc |
No files matched your search
@@ -15,3 +15,5 @@ skirmish.iml
|
||||
full-stack
|
||||
fixtures
|
||||
node_modules
|
||||
figwheel_server.log
|
||||
.rebel_readline_history
|
||||
@@ -1,4 +1,5 @@
|
||||
FROM clojure
|
||||
MAINTAINER Didier Amyot <didier.amyot@gmail.com>
|
||||
|
||||
# Set the working directory to /app
|
||||
WORKDIR /app
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Skrimish
|
||||
|
||||

|
||||

|
||||
|
||||
A stock exchange simulator. The scope of this project is not yet defined but it should
|
||||
allow end user(s?) to exchange securities via the common exchange rules.
|
||||
allow end user(s?) to exchange securities via a kind of stock exchange
|
||||
|
||||
|
||||
## Getting Started
|
||||
@@ -26,22 +26,52 @@ All configuration are set in the `resources/config.edn` file.
|
||||
Configuration uses [aero](https://github.com/juxt/aero). The configuration
|
||||
file should be self documented.
|
||||
|
||||
|
||||
### Technologies
|
||||
|
||||
#### Big architecture
|
||||
|
||||
* [docker](https://www.docker.com/) because it is trendy.
|
||||
* [docker-compose](https://docs.docker.com/compose/) to manage system dependencies.
|
||||
* [jvm](https://en.wikipedia.org/wiki/Java_virtual_machine) because nothing beats it.
|
||||
|
||||
#### Server
|
||||
* [clojure](https://clojure.org/) for programming language
|
||||
* [kafka](http://kafka.apache.org/) for message broker/database
|
||||
* [datomic-free](https://www.datomic.com/) for transaction needs
|
||||
* [clickhouse](https://clickhouse.yandex) to store the market data
|
||||
|
||||
#### In the browser
|
||||
* [clojure script](https://clojurescript.org/) for programming language
|
||||
* [sparks](https://aftertheflood.com/projects/sparks/) for trivial charts
|
||||
* [reagent](https://reagent-project.github.io/) as frontend framework. Simple and powerful.
|
||||
* [metricsgraphicsjs](http://metricsgraphicsjs.org/) for complex charts
|
||||
* [dc-js](http://dc-js.github.io/dc.js/) for some charting. Looks awesome!.
|
||||
|
||||
|
||||
### Architecture shenanigans
|
||||
|
||||
As any personal project, over engineering it the only solution. Moreover the
|
||||
scope of the project is unknown. Consequently, there is a plethora of
|
||||
micro-servicesh.
|
||||
|
||||
|
||||
#### Micro services
|
||||
|
||||
A micro service does one thing, and does it well. Micro services communicate to the world
|
||||
via REST api and collaborate together via a global state kept in kafka.
|
||||
|
||||
| name | description | REST |
|
||||
|:----------------------------|:--------------------------------------------------------------------------|:-----:|
|
||||
| `skirmish.exchange` | Exchange engine. Knows nothing about what it trades. | `yes` |
|
||||
| `skirmish.exchange-gateway` | Public api to `skirmish.exchange`. Dispatch an order to the proper place | `no` |
|
||||
| `skirmish.ledger` | Source of truth for who owns what. | `yes` |
|
||||
| `skirmish.bookkeeper` | Source of truth for the marker data. Publishes market data to the world. | `yes` |
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2018 didier amyot
|
||||
Copyright © 2020 didier amyot
|
||||
|
||||
Distributed under the Eclipse Public License either version 1.0 or (at
|
||||
your option) any later version.
|
||||
@@ -0,0 +1,32 @@
|
||||
FROM openjdk:11-jdk
|
||||
MAINTAINER Didier Amyot <didier.amyot@gmail.com>
|
||||
|
||||
ENV DATOMIC_VERSION 0.9.5656
|
||||
|
||||
ADD https://my.datomic.com/downloads/free/${DATOMIC_VERSION} /tmp/datomic.zip
|
||||
|
||||
RUN unzip /tmp/datomic.zip && rm /tmp/datomic.zip
|
||||
|
||||
WORKDIR datomic-free-${DATOMIC_VERSION}
|
||||
|
||||
RUN cp config/samples/free-transactor-template.properties transactor.properties
|
||||
|
||||
ADD https://clojars.org/repo/slingshot/slingshot/0.12.2/slingshot-0.12.2.jar /tmp/slingshot-0.12.2.jar
|
||||
RUN mv /tmp/slingshot-0.12.2.jar lib/
|
||||
|
||||
RUN sed "s/host=localhost/host=0.0.0.0/" -i transactor.properties
|
||||
|
||||
RUN mkdir /data
|
||||
RUN sed "s/# data-dir=data/data-dir=\/data/" -i transactor.properties
|
||||
VOLUME /data
|
||||
|
||||
RUN mkdir /log
|
||||
RUN sed "s/# log-dir=log/log-dir=\/log/" -i transactor.properties
|
||||
VOLUME /log
|
||||
|
||||
ADD start.sh ./
|
||||
RUN chmod +x start.sh
|
||||
|
||||
EXPOSE 4334 4335 4336
|
||||
|
||||
CMD ["./start.sh"]
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sed "/host=0.0.0.0/a alt-host=${ALT_HOST:-127.0.0.1}" -i transactor.properties
|
||||
exec bin/transactor transactor.properties
|
||||
+39
-21
@@ -4,7 +4,7 @@ version: '2'
|
||||
services:
|
||||
zoo1:
|
||||
image: zookeeper:3.4.9
|
||||
restart: unless-stopped
|
||||
restart: "unless-stopped"
|
||||
hostname: zoo1
|
||||
ports:
|
||||
- "2181:2181"
|
||||
@@ -150,26 +150,44 @@ services:
|
||||
depends_on:
|
||||
- zoo1
|
||||
|
||||
# skirmish
|
||||
|
||||
skirmish-api:
|
||||
image: skirmish
|
||||
command: ["lein", "run", "api-server"]
|
||||
depends_on:
|
||||
- kafka-topics-ui # basically, we need all kafka
|
||||
environment:
|
||||
PORT: 1602 # https://en.wikipedia.org/wiki/Euronext_Amsterdam
|
||||
KAFKA_BOOTSTRAP_SERVERS: "kafka1:9092"
|
||||
# datomic
|
||||
datomic-transactors:
|
||||
build: "datomic/"
|
||||
restart: "unless-stopped"
|
||||
ports:
|
||||
- "1602:1602"
|
||||
- "4334:4334"
|
||||
- "4335:4335"
|
||||
- "4336:4336"
|
||||
|
||||
skirmish-exchange-core:
|
||||
image: skirmish
|
||||
command: ["lein", "run", "exchange-core"]
|
||||
depends_on:
|
||||
- skirmish-api # basically, we need all kafka
|
||||
environment:
|
||||
PORT: 1602 # https://en.wikipedia.org/wiki/Euronext_Amsterdam
|
||||
KAFKA_BOOTSTRAP_SERVERS: "kafka1:9092"
|
||||
clickhouse:
|
||||
image: "yandex/clickhouse-server:18.14"
|
||||
restart: "unless-stopped"
|
||||
ports:
|
||||
- "1602:1602"
|
||||
- "8123:8123"
|
||||
- "9000:9000"
|
||||
|
||||
|
||||
|
||||
# skirmish itself
|
||||
|
||||
# skirmish-api:
|
||||
# build: .
|
||||
# command: ["lein", "run", "api-server"]
|
||||
# depends_on:
|
||||
# - kafka-topics-ui # basically, we need all kafka
|
||||
# environment:
|
||||
# PORT: 1602 # https://en.wikipedia.org/wiki/Euronext_Amsterdam
|
||||
# KAFKA_BOOTSTRAP_SERVERS: "kafka1:9092"
|
||||
# ports:
|
||||
# - "1602:1602"
|
||||
#
|
||||
# skirmish-exchange-core:
|
||||
# build: .
|
||||
# command: ["lein", "run", "exchange-core"]
|
||||
# depends_on:
|
||||
# - skirmish-api # basically, we need all kafka
|
||||
# environment:
|
||||
# PORT: 1602 # https://en.wikipedia.org/wiki/Euronext_Amsterdam
|
||||
# KAFKA_BOOTSTRAP_SERVERS: "kafka1:9092"
|
||||
# ports:
|
||||
# - "1602:1602"
|
||||
+8
-4
@@ -1,10 +1,14 @@
|
||||
(ns skirmish.wui.middleware
|
||||
(:require [ring.middleware.defaults :refer [site-defaults wrap-defaults]]
|
||||
[prone.middleware :refer [wrap-exceptions]]
|
||||
[ring.middleware.reload :refer [wrap-reload]]))
|
||||
[prone.middleware :refer [wrap-exceptions]]))
|
||||
|
||||
(defn custom-dev-middleware [handler]
|
||||
(fn [request]
|
||||
(let [response (handler request)]
|
||||
response)))
|
||||
|
||||
(defn wrap-middleware [handler]
|
||||
(-> handler
|
||||
(wrap-defaults site-defaults)
|
||||
wrap-exceptions
|
||||
wrap-reload))
|
||||
custom-dev-middleware
|
||||
wrap-exceptions))
|
||||
Vendored
-33
@@ -1,33 +0,0 @@
|
||||
(ns skirmish.wui.repl
|
||||
(:use skirmish.wui.handler
|
||||
figwheel-sidecar.repl-api
|
||||
ring.server.standalone
|
||||
[ring.middleware file-info file]))
|
||||
|
||||
(defonce server (atom nil))
|
||||
|
||||
(defn get-handler []
|
||||
;; #'app expands to (var app) so that when we reload our code,
|
||||
;; the server is forced to re-resolve the symbol in the var
|
||||
;; rather than having its own copy. When the root binding
|
||||
;; changes, the server picks it up without having to restart.
|
||||
(-> #'app
|
||||
; Makes static assets in $PROJECT_DIR/resources/public/ available.
|
||||
(wrap-file "resources")
|
||||
; Content-Type, Content-Length, and Last Modified headers for files in body
|
||||
(wrap-file-info)))
|
||||
|
||||
(defn start-server
|
||||
"used for starting the server in development mode from REPL"
|
||||
[& [port]]
|
||||
(let [port (if port (Integer/parseInt port) 3000)]
|
||||
(reset! server
|
||||
(serve (get-handler)
|
||||
{:port port
|
||||
:auto-reload? true
|
||||
:join? false}))
|
||||
(println (str "You can view the site at http://localhost:" port))))
|
||||
|
||||
(defn stop-server []
|
||||
(.stop @server)
|
||||
(reset! server nil))
|
||||
@@ -1,867 +0,0 @@
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.611 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/goog/deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.552 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.471 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.464 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.447 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:37 column:1 ----[0m
|
||||
|
||||
[1mcurrent-page at line 24 is being replaced[0m
|
||||
|
||||
[36m33[0m [36m;; -------------------------[0m
|
||||
[36m34[0m [36m;; Initialize app[0m
|
||||
[36m35[0m [36m[0m
|
||||
[36m36[0m [36m[0m
|
||||
[33m37[0m [1m(defn current-page [][0m
|
||||
[0m [0m [33m^--- current-page at line 24 is being replaced[0m
|
||||
[36m38[0m [36m [:div[0m
|
||||
[36m39[0m [36m (dase.topbar/top-bar state)[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:39 column:5 ----[0m
|
||||
|
||||
[1mNo such namespace: dase.topbar, could not locate dase/topbar.cljs, dase/topbar.cljc, or JavaScript source providing "dase.topbar"[0m
|
||||
|
||||
[36m37[0m [36m(defn current-page [][0m
|
||||
[36m38[0m [36m [:div[0m
|
||||
[33m39[0m [1m (dase.topbar/top-bar state)[0m
|
||||
[0m [0m [33m ^--- No such namespace: dase.topbar, could not locate dase/topbar.cljs, dase/topbar.cljc, or JavaScript source providing "dase.topbar"[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[36m43[0m [36m [(session/get :current-page)]]]]])[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:39 column:5 ----[0m
|
||||
|
||||
[1mUse of undeclared Var dase.topbar/top-bar[0m
|
||||
|
||||
[36m37[0m [36m(defn current-page [][0m
|
||||
[36m38[0m [36m [:div[0m
|
||||
[33m39[0m [1m (dase.topbar/top-bar state)[0m
|
||||
[0m [0m [33m ^--- Use of undeclared Var dase.topbar/top-bar[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[36m43[0m [36m [(session/get :current-page)]]]]])[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:39 column:25 ----[0m
|
||||
|
||||
[1mUse of undeclared Var skirmish.core/state[0m
|
||||
|
||||
[36m37[0m [36m(defn current-page [][0m
|
||||
[36m38[0m [36m [:div[0m
|
||||
[33m39[0m [1m (dase.topbar/top-bar state)[0m
|
||||
[0m [0m [33m ^--- Use of undeclared Var skirmish.core/state[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[36m43[0m [36m [(session/get :current-page)]]]]])[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:43 column:9 ----[0m
|
||||
|
||||
[1mNo such namespace: session, could not locate session.cljs, session.cljc, or JavaScript source providing "session"[0m
|
||||
|
||||
[36m39[0m [36m (dase.topbar/top-bar state)[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[33m43[0m [1m [(session/get :current-page)]]]]])[0m
|
||||
[0m [0m [33m ^--- No such namespace: session, could not locate session.cljs, session.cljc, or JavaScript source providing "session"[0m
|
||||
[36m44[0m [36m[0m
|
||||
[36m45[0m [36m[0m
|
||||
[36m46[0m [36m(defn mount-root [][0m
|
||||
[36m47[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:43 column:9 ----[0m
|
||||
|
||||
[1mUse of undeclared Var session/get[0m
|
||||
|
||||
[36m39[0m [36m (dase.topbar/top-bar state)[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[33m43[0m [1m [(session/get :current-page)]]]]])[0m
|
||||
[0m [0m [33m ^--- Use of undeclared Var session/get[0m
|
||||
[36m44[0m [36m[0m
|
||||
[36m45[0m [36m[0m
|
||||
[36m46[0m [36m(defn mount-root [][0m
|
||||
[36m47[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:51 column:1 ----[0m
|
||||
|
||||
[1mmount-root at line 46 is being replaced[0m
|
||||
|
||||
[36m47[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
[36m48[0m [36m[0m
|
||||
[36m49[0m [36m[0m
|
||||
[36m50[0m [36m[0m
|
||||
[33m51[0m [1m(defn mount-root [][0m
|
||||
[0m [0m [33m^--- mount-root at line 46 is being replaced[0m
|
||||
[36m52[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
[36m53[0m [36m[0m
|
||||
[36m54[0m [36m(defn init! [][0m
|
||||
[36m55[0m [36m (accountant/configure-navigation![0m
|
||||
[36m56[0m [36m {:nav-handler[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.575 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:37 column:1 ----[0m
|
||||
|
||||
[1mcurrent-page at line 24 is being replaced[0m
|
||||
|
||||
[36m33[0m [36m;; -------------------------[0m
|
||||
[36m34[0m [36m;; Initialize app[0m
|
||||
[36m35[0m [36m[0m
|
||||
[36m36[0m [36m[0m
|
||||
[33m37[0m [1m(defn current-page [][0m
|
||||
[0m [0m [33m^--- current-page at line 24 is being replaced[0m
|
||||
[36m38[0m [36m [:div[0m
|
||||
[36m39[0m [36m (top-bar state)[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:39 column:13 ----[0m
|
||||
|
||||
[1mUse of undeclared Var skirmish.core/state[0m
|
||||
|
||||
[36m37[0m [36m(defn current-page [][0m
|
||||
[36m38[0m [36m [:div[0m
|
||||
[33m39[0m [1m (top-bar state)[0m
|
||||
[0m [0m [33m ^--- Use of undeclared Var skirmish.core/state[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[36m43[0m [36m [(session/get :current-page)]]]]])[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:43 column:9 ----[0m
|
||||
|
||||
[1mNo such namespace: session, could not locate session.cljs, session.cljc, or JavaScript source providing "session"[0m
|
||||
|
||||
[36m39[0m [36m (top-bar state)[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[33m43[0m [1m [(session/get :current-page)]]]]])[0m
|
||||
[0m [0m [33m ^--- No such namespace: session, could not locate session.cljs, session.cljc, or JavaScript source providing "session"[0m
|
||||
[36m44[0m [36m[0m
|
||||
[36m45[0m [36m[0m
|
||||
[36m46[0m [36m(defn mount-root [][0m
|
||||
[36m47[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:43 column:9 ----[0m
|
||||
|
||||
[1mUse of undeclared Var session/get[0m
|
||||
|
||||
[36m39[0m [36m (top-bar state)[0m
|
||||
[36m40[0m [36m [:div[0m
|
||||
[36m41[0m [36m [:div.columns[0m
|
||||
[36m42[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[33m43[0m [1m [(session/get :current-page)]]]]])[0m
|
||||
[0m [0m [33m ^--- Use of undeclared Var session/get[0m
|
||||
[36m44[0m [36m[0m
|
||||
[36m45[0m [36m[0m
|
||||
[36m46[0m [36m(defn mount-root [][0m
|
||||
[36m47[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:51 column:1 ----[0m
|
||||
|
||||
[1mmount-root at line 46 is being replaced[0m
|
||||
|
||||
[36m47[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
[36m48[0m [36m[0m
|
||||
[36m49[0m [36m[0m
|
||||
[36m50[0m [36m[0m
|
||||
[33m51[0m [1m(defn mount-root [][0m
|
||||
[0m [0m [33m^--- mount-root at line 46 is being replaced[0m
|
||||
[36m52[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
[36m53[0m [36m[0m
|
||||
[36m54[0m [36m(defn init! [][0m
|
||||
[36m55[0m [36m (accountant/configure-navigation![0m
|
||||
[36m56[0m [36m {:nav-handler[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.517 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:40 column:1 ----[0m
|
||||
|
||||
[1mcurrent-page at line 27 is being replaced[0m
|
||||
|
||||
[36m36[0m [36m;; -------------------------[0m
|
||||
[36m37[0m [36m;; Initialize app[0m
|
||||
[36m38[0m [36m[0m
|
||||
[36m39[0m [36m[0m
|
||||
[33m40[0m [1m(defn current-page [][0m
|
||||
[0m [0m [33m^--- current-page at line 27 is being replaced[0m
|
||||
[36m41[0m [36m [:div[0m
|
||||
[36m42[0m [36m (top-bar state)[0m
|
||||
[36m43[0m [36m [:div[0m
|
||||
[36m44[0m [36m [:div.columns[0m
|
||||
[36m45[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:46 column:9 ----[0m
|
||||
|
||||
[1mNo such namespace: session, could not locate session.cljs, session.cljc, or JavaScript source providing "session"[0m
|
||||
|
||||
[36m42[0m [36m (top-bar state)[0m
|
||||
[36m43[0m [36m [:div[0m
|
||||
[36m44[0m [36m [:div.columns[0m
|
||||
[36m45[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[33m46[0m [1m [(session/get :current-page)]]]]])[0m
|
||||
[0m [0m [33m ^--- No such namespace: session, could not locate session.cljs, session.cljc, or JavaScript source providing "session"[0m
|
||||
[36m47[0m [36m[0m
|
||||
[36m48[0m [36m[0m
|
||||
[36m49[0m [36m(defn mount-root [][0m
|
||||
[36m50[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:46 column:9 ----[0m
|
||||
|
||||
[1mUse of undeclared Var session/get[0m
|
||||
|
||||
[36m42[0m [36m (top-bar state)[0m
|
||||
[36m43[0m [36m [:div[0m
|
||||
[36m44[0m [36m [:div.columns[0m
|
||||
[36m45[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[33m46[0m [1m [(session/get :current-page)]]]]])[0m
|
||||
[0m [0m [33m ^--- Use of undeclared Var session/get[0m
|
||||
[36m47[0m [36m[0m
|
||||
[36m48[0m [36m[0m
|
||||
[36m49[0m [36m(defn mount-root [][0m
|
||||
[36m50[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:54 column:1 ----[0m
|
||||
|
||||
[1mmount-root at line 49 is being replaced[0m
|
||||
|
||||
[36m50[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
[36m51[0m [36m[0m
|
||||
[36m52[0m [36m[0m
|
||||
[36m53[0m [36m[0m
|
||||
[33m54[0m [1m(defn mount-root [][0m
|
||||
[0m [0m [33m^--- mount-root at line 49 is being replaced[0m
|
||||
[36m55[0m [36m (reagent/render [current-page] (.getElementById js/document "app")))[0m
|
||||
[36m56[0m [36m[0m
|
||||
[36m57[0m [36m(defn init! [][0m
|
||||
[36m58[0m [36m (accountant/configure-navigation![0m
|
||||
[36m59[0m [36m {:nav-handler[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.489 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:41 column:1 ----[0m
|
||||
|
||||
[1mcurrent-page at line 28 is being replaced[0m
|
||||
|
||||
[36m37[0m [36m;; -------------------------[0m
|
||||
[36m38[0m [36m;; Initialize app[0m
|
||||
[36m39[0m [36m[0m
|
||||
[36m40[0m [36m[0m
|
||||
[33m41[0m [1m(defn current-page [][0m
|
||||
[0m [0m [33m^--- current-page at line 28 is being replaced[0m
|
||||
[36m42[0m [36m [:div[0m
|
||||
[36m43[0m [36m (top-bar state)[0m
|
||||
[36m44[0m [36m [:div[0m
|
||||
[36m45[0m [36m [:div.columns[0m
|
||||
[36m46[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.553 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.436 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.447 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.649 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/goog/deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/todo.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.561 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/todo.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.521 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/todo.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.477 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/home_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.531 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/todo_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.464 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/home_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 1.474 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.496 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.479 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.44 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.472 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.432 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.449 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.468 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.466 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:26 column:1 ----[0m
|
||||
|
||||
[1mpage already refers to: skirmish.wui.components.todo-page/page being replaced by: skirmish.core/page[0m
|
||||
|
||||
[36m23[0m [36m;; -------------------------[0m
|
||||
[36m24[0m [36m;; Routes[0m
|
||||
[36m25[0m [36m[0m
|
||||
[33m26[0m [1m(defonce page (atom #'home-page))[0m
|
||||
[0m [0m [33m^--- page already refers to: skirmish.wui.components.todo-page/page being replaced by: skirmish.core/page[0m
|
||||
[36m27[0m [36m[0m
|
||||
[36m28[0m [36m(secretary/defroute "/todo" [][0m
|
||||
[36m29[0m [36m (session/put! :current-page 'page)[0m
|
||||
[36m30[0m [36m (swap! state #(assoc % :page :todo)))[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.479 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:26 column:1 ----[0m
|
||||
|
||||
[1mpage already refers to: skirmish.wui.components.todo-page/page being replaced by: skirmish.core/page[0m
|
||||
|
||||
[36m23[0m [36m;; -------------------------[0m
|
||||
[36m24[0m [36m;; Routes[0m
|
||||
[36m25[0m [36m[0m
|
||||
[33m26[0m [1m(defonce page (atom #'home-page))[0m
|
||||
[0m [0m [33m^--- page already refers to: skirmish.wui.components.todo-page/page being replaced by: skirmish.core/page[0m
|
||||
[36m27[0m [36m[0m
|
||||
[36m28[0m [36m(secretary/defroute "/todo" [][0m
|
||||
[36m29[0m [36m (session/put! :current-page #'page)[0m
|
||||
[36m30[0m [36m (swap! state #(assoc % :page :todo)))[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.473 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.458 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.435 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.474 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:34 column:21 ----[0m
|
||||
|
||||
[1mNo such namespace: pages, could not locate pages.cljs, pages.cljc, or JavaScript source providing "pages"[0m
|
||||
|
||||
[36m30[0m [36m (session/put! :current-page #'page)[0m
|
||||
[36m31[0m [36m (swap! state #(assoc % :page :todo)))[0m
|
||||
[36m32[0m [36m[0m
|
||||
[36m33[0m [36m(secretary/defroute "/" [][0m
|
||||
[33m34[0m [1m (session/put! :current-page #'pages/homepage)[0m
|
||||
[0m [0m [33m ^--- No such namespace: pages, could not locate pages.cljs, pages.cljc, or JavaScript source providing "pages"[0m
|
||||
[36m35[0m [36m (swap! state #(assoc % :page :home)))[0m
|
||||
[36m36[0m [36m;(secretary/defroute "/" [][0m
|
||||
[36m37[0m [36m; (reset! page #'home-page))[0m
|
||||
[36m38[0m [36m;[0m
|
||||
[36m39[0m [36m;(secretary/defroute "/about" [][0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.234 seconds.[0m
|
||||
[36m---- Could not Analyze src/cljs/skirmish/core.cljs line:34 column:21 ----[0m
|
||||
|
||||
[1mUnable to resolve var: homepage in this context at line 34 src/cljs/skirmish/core.cljs[0m
|
||||
|
||||
[36m33[0m [36m(secretary/defroute "/" [][0m
|
||||
[33m34[0m [1m (session/put! :current-page #'pages/homepage)[0m
|
||||
[0m [0m [33m ^--- Unable to resolve var: homepage in this context at line 34 src/cljs/skirmish/core.cljs[0m
|
||||
[36m35[0m [36m (swap! state #(assoc % :page :home)))[0m
|
||||
[36m36[0m [36m;(secretary/defroute "/" [][0m
|
||||
[36m37[0m [36m; (reset! page #'home-page))[0m
|
||||
|
||||
[36m---- Analysis Error : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:35 column:21 ----[0m
|
||||
|
||||
[1mNo such namespace: pages, could not locate pages.cljs, pages.cljc, or JavaScript source providing "pages"[0m
|
||||
|
||||
[36m31[0m [36m (session/put! :current-page #'page)[0m
|
||||
[36m32[0m [36m (swap! state #(assoc % :page :todo)))[0m
|
||||
[36m33[0m [36m[0m
|
||||
[36m34[0m [36m(secretary/defroute "/" [][0m
|
||||
[33m35[0m [1m (session/put! :current-page #'pages/homepage)[0m
|
||||
[0m [0m [33m ^--- No such namespace: pages, could not locate pages.cljs, pages.cljc, or JavaScript source providing "pages"[0m
|
||||
[36m36[0m [36m (swap! state #(assoc % :page :home)))[0m
|
||||
[36m37[0m [36m;(secretary/defroute "/" [][0m
|
||||
[36m38[0m [36m; (reset! page #'home-page))[0m
|
||||
[36m39[0m [36m;[0m
|
||||
[36m40[0m [36m;(secretary/defroute "/about" [][0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.286 seconds.[0m
|
||||
[36m---- Could not Analyze src/cljs/skirmish/core.cljs line:35 column:21 ----[0m
|
||||
|
||||
[1mUnable to resolve var: homepage in this context at line 35 /home/didier/gitlab/skirmish/skirmish/src/cljs/skirmish/core.cljs[0m
|
||||
|
||||
[36m34[0m [36m(secretary/defroute "/" [][0m
|
||||
[33m35[0m [1m (session/put! :current-page #'pages/homepage)[0m
|
||||
[0m [0m [33m ^--- Unable to resolve var: homepage in this context at line 35 /home/didier/gitlab/skirmish/skirmish/src/cljs/skirmish/core.cljs[0m
|
||||
[36m36[0m [36m (swap! state #(assoc % :page :home)))[0m
|
||||
[36m37[0m [36m;(secretary/defroute "/" [][0m
|
||||
[36m38[0m [36m; (reset! page #'home-page))[0m
|
||||
|
||||
[36m---- Analysis Error : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.443 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.444 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/home_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.437 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/pages.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.394 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/pages.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.409 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.409 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.384 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/pages.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.245 seconds.[0m
|
||||
[36m---- Could not Analyze src/cljs/skirmish/core.cljs ----[0m
|
||||
|
||||
[1mInvalid :refer, var skirmish.pages/pages does not exist [0m
|
||||
|
||||
[36m---- Analysis Error : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.248 seconds.[0m
|
||||
[36m---- Could not Analyze src/cljs/skirmish/core.cljs ----[0m
|
||||
|
||||
[1mInvalid :refer, var skirmish.pages/pages does not exist [0m
|
||||
|
||||
[36m---- Analysis Error : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.254 seconds.[0m
|
||||
[36m---- Could not Analyze src/cljs/skirmish/core.cljs ----[0m
|
||||
|
||||
[1mInvalid :refer, var skirmish.pages/pages does not exist [0m
|
||||
|
||||
[36m---- Analysis Error : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[36m---- Compiler Warning on src/cljs/skirmish/core.cljs line:49 column:5 ----[0m
|
||||
|
||||
[1mUse of undeclared Var skirmish.core/top-bar[0m
|
||||
|
||||
[36m47[0m [36m(defn current-page [][0m
|
||||
[36m48[0m [36m [:div[0m
|
||||
[33m49[0m [1m (top-bar state)[0m
|
||||
[0m [0m [33m ^--- Use of undeclared Var skirmish.core/top-bar[0m
|
||||
[36m50[0m [36m [:div[0m
|
||||
[36m51[0m [36m [:div.columns[0m
|
||||
[36m52[0m [36m [:div.column.is-8.is-offset-2[0m
|
||||
[36m53[0m [36m [(session/get :current-page)]]]]])[0m
|
||||
|
||||
[36m---- Compiler Warning : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.434 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.409 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.395 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.439 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/home_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.39 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.398 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.433 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.424 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.422 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.413 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.391 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.389 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.402 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 1.82 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/goog/deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.616 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.515 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.586 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.481 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.521 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.496 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.457 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.531 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.448 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.442 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.461 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.437 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/topbar.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.419 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.438 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.436 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.414 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.453 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.435 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.412 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.407 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.433 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.497 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.504 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.384 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.373 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.39 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.367 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.444 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/pages.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.278 seconds.[0m
|
||||
[36m---- Could not Read src/cljs/skirmish/core.cljs line:68 ----[0m
|
||||
|
||||
[1m/home/didier/gitlab/skirmish/skirmish/src/cljs/skirmish/core.cljs [line 68, col 1] Unexpected EOF while reading item 8 of list, starting at line 37 and column 1.[0m
|
||||
|
||||
[36m---- Reader Error : Please see src/cljs/skirmish/core.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.427 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.441 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.455 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.432 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.418 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.421 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.445 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.407 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.398 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.41 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.427 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.402 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.427 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.393 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.392 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.4 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.385 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.392 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.423 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.386 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.399 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.393 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.393 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.404 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.388 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.431 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/security_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.457 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/security_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.417 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/pages.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.414 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/pages.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.45 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.452 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.445 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.402 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.397 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.452 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.44 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.423 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.446 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Notifying browser that CSS file changed: resources/public/css/site.css
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.402 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/security_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.385 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/security_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.396 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/core.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.418 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.401 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/home_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.39 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/security_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.392 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/components/security_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.387 seconds.[0m
|
||||
[36m---- Could not Analyze src/cljs/skirmish/wui/pages.cljs ----[0m
|
||||
|
||||
[1mNo such namespace: skirmish.components.todo-page, could not locate skirmish/components/todo_page.cljs, skirmish/components/todo_page.cljc, or JavaScript source providing "skirmish.components.todo-page" (Please check that namespaces with dashes use underscores in the ClojureScript file name) [0m
|
||||
|
||||
[36m---- Analysis Error : Please see src/cljs/skirmish/wui/pages.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.3 seconds.[0m
|
||||
[36m---- Could not Analyze src/cljs/skirmish/wui/pages.cljs ----[0m
|
||||
|
||||
[1mNo such namespace: skirmish.components.todo-page, could not locate skirmish/components/todo_page.cljs, skirmish/components/todo_page.cljc, or JavaScript source providing "skirmish.components.todo-page" (Please check that namespaces with dashes use underscores in the ClojureScript file name) [0m
|
||||
|
||||
[36m---- Analysis Error : Please see src/cljs/skirmish/wui/pages.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[31mFailed to compile build :app from ["src/cljs" "src/cljc" "env/dev/cljs"] in 0.307 seconds.[0m
|
||||
[36m---- Could not Analyze src/cljs/skirmish/wui/pages.cljs ----[0m
|
||||
|
||||
[1mNo such namespace: skirmish.components.todo-page, could not locate skirmish/components/todo_page.cljs, skirmish/components/todo_page.cljc, or JavaScript source providing "skirmish.components.todo-page" (Please check that namespaces with dashes use underscores in the ClojureScript file name) [0m
|
||||
|
||||
[36m---- Analysis Error : Please see src/cljs/skirmish/wui/pages.cljs ----[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 2.041 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/goog/deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/wui/pages.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.814 seconds.[0m
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.603 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/goog/deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/order.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.746 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/goog/deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/cljs_deps.js
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/wui/components/securities_page.js
|
||||
Compiling build :app to "target/cljsbuild/public/js/app.js" from ["src/cljs" "src/cljc" "env/dev/cljs"]...
|
||||
[32mSuccessfully compiled build :app to "target/cljsbuild/public/js/app.js" in 0.533 seconds.[0m
|
||||
notifying browser that file changed: target/cljsbuild/public/js/out/skirmish/wui/components/securities_page.js
|
||||
Generated
+3
-3
@@ -5,9 +5,9 @@
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"bulma": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.1.tgz",
|
||||
"integrity": "sha512-wRSO2LXB+qI9Pyz2id+uZr4quz5aftSN7Ay1ysr1+krzVp3utD+Ci4CeKuZdrYGc800t65b7heXBL6qw2Wo/lQ=="
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.2.tgz",
|
||||
"integrity": "sha512-6JHEu8U/1xsyOst/El5ImLcZIiE2JFXgvrz8GGWbnDLwTNRPJzdAM0aoUM1Ns0avALcVb6KZz9NhzmU53dGDcQ=="
|
||||
},
|
||||
"font-awesome": {
|
||||
"version": "4.7.0",
|
||||
|
||||
+35
-29
@@ -4,49 +4,57 @@
|
||||
:license {:name "Eclipse Public License"
|
||||
:url "http://www.eclipse.org/legal/epl-v10.html"}
|
||||
|
||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||
[org.clojure/core.async "0.4.474"]
|
||||
[org.clojure/math.combinatorics "0.1.4"]
|
||||
:resource-paths ["resources"
|
||||
"target/cljsbuild"]
|
||||
|
||||
:dependencies [[org.clojure/clojure "1.10.1"]
|
||||
[org.clojure/core.async "1.3.610"]
|
||||
[org.clojure/math.combinatorics "0.1.6"]
|
||||
[com.datomic/datomic-free "0.9.5697"]
|
||||
[com.google.guava/guava "22.0"]
|
||||
;[javax.xml.bind/jaxb-api "2.2.11"]
|
||||
|
||||
;; server
|
||||
[aero "1.1.3"]
|
||||
[http-kit "2.3.0"]
|
||||
[compojure "1.6.1"]
|
||||
[com.taoensso/nippy "2.14.0"]
|
||||
[ring-cors "0.1.13"]
|
||||
[ring/ring-defaults "0.3.2"]
|
||||
;[ring/ring-jetty-adapter "1.8.0"]
|
||||
[javax.servlet/javax.servlet-api "3.1.0"]
|
||||
[org.apache.kafka/kafka-streams "1.1.0"]
|
||||
[org.apache.kafka/kafka-clients "1.1.0"]
|
||||
[spootnik/kinsky "0.1.22"]
|
||||
[aero "1.1.3"]
|
||||
[com.taoensso/timbre "4.10.0"]
|
||||
[org.clojure/tools.reader "1.3.3"]
|
||||
[http-kit "2.4.0"]
|
||||
[compojure "1.6.2"]
|
||||
|
||||
;; backends
|
||||
[spootnik/kinsky "0.1.25"]
|
||||
|
||||
;;utils
|
||||
[slingshot "0.12.2"]
|
||||
[orchestra "2017.11.12-1"]
|
||||
[cheshire "5.8.0"]
|
||||
[orchestra "2020.07.12-1"]
|
||||
[cheshire "5.10.0"]
|
||||
[com.stuartsierra/frequencies "0.1.0"]
|
||||
[rm-hull/infix "0.3.3"]
|
||||
|
||||
;; wui
|
||||
[ring-server "0.5.0"]
|
||||
[reagent "0.8.1"]
|
||||
[reagent-utils "0.3.1"]
|
||||
[ring "1.6.3"]
|
||||
[ring/ring-defaults "0.3.1"]
|
||||
[compojure "1.6.1"]
|
||||
[hiccup "1.0.5"]
|
||||
|
||||
;; cljs
|
||||
[org.clojure/clojurescript "1.10.339" :scope "provided"]
|
||||
[org.clojure/clojurescript "1.10.773" :scope "provided"]
|
||||
[cljs-http "0.1.46"]
|
||||
[secretary "1.2.3"]
|
||||
[venantius/accountant "0.2.4" :exclusions [org.clojure/tools.reader]]]
|
||||
[venantius/accountant "0.2.2" :exclusions [org.clojure/tools.reader]]]
|
||||
|
||||
:plugins [[lein-midje "3.2.1"]
|
||||
[lein-npm "0.6.2"]
|
||||
[lein-environ "1.1.0"] ;; maybe to remove
|
||||
[lein-cljsbuild "1.1.7"]
|
||||
[lein-asset-minifier "0.2.7" :exclusions [org.clojure/clojure]]]
|
||||
[lein-cljsbuild "1.1.8"]
|
||||
[lein-asset-minifier "0.4.6" :exclusions [org.clojure/clojure]]]
|
||||
|
||||
:java-source-paths ["src/java"]
|
||||
|
||||
:npm {:dependencies [[bulma "0.7.1"]
|
||||
:npm {:dependencies [[bulma "0.7.2"]
|
||||
[font-awesome "4.7.0"]]}
|
||||
|
||||
:ring {:handler skirmish.wui.handler/app
|
||||
@@ -54,15 +62,13 @@
|
||||
|
||||
:min-lein-version "2.5.0"
|
||||
:uberjar-name "skirmish.jar"
|
||||
:main skirmish.wui.core
|
||||
:jvm-opts ["--add-modules" "java.xml.bind"]
|
||||
:main skirmish.core
|
||||
:clean-targets ^{:protect false}
|
||||
[:target-path
|
||||
[:cljsbuild :builds :app :compiler :output-dir]
|
||||
[:cljsbuild :builds :app :compiler :output-to]]
|
||||
|
||||
:source-paths ["src/clj" "src/cljc"]
|
||||
:resource-paths ["resources" "target/cljsbuild"]
|
||||
|
||||
:minify-assets
|
||||
{:assets
|
||||
@@ -92,7 +98,7 @@
|
||||
|
||||
:devcards
|
||||
{:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"]
|
||||
:figwheel {:devcards true}
|
||||
:figwheel {:devcards false}
|
||||
:compiler {:main "skirmish.wui.cards"
|
||||
:asset-path "js/devcards_out"
|
||||
:output-to "target/cljsbuild/public/js/app_devcards.js"
|
||||
@@ -112,14 +118,14 @@
|
||||
:css-dirs ["resources/public/css"]
|
||||
:ring-handler skirmish.wui.handler/app}
|
||||
|
||||
:test-paths ["test/clj" "test/cljs"]
|
||||
|
||||
|
||||
:sass {:source-paths ["src/sass"]
|
||||
:target-path "resources/public/css"}
|
||||
|
||||
:profiles {:dev {:repl-options {:init-ns skirmish.wui.repl
|
||||
:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}
|
||||
|
||||
:dependencies [[midje "1.9.1"]
|
||||
:profiles {:dev {
|
||||
:dependencies [[midje "1.9.9"]
|
||||
[stylefruits/gniazdo "1.0.1"] ;; only used in benchmark
|
||||
[clj-http "3.9.0"] ;; only used in benchmark
|
||||
|
||||
|
||||
+19
-14
@@ -1,10 +1,13 @@
|
||||
{
|
||||
;; Specify which middleware to use, it will default to :chan.
|
||||
:middleware :kafka
|
||||
:middleware :chan
|
||||
|
||||
;; If set to true, orchestra will instrument all the spec'ed functions
|
||||
:instrument-spec true
|
||||
|
||||
:datomic
|
||||
{:transactor-url "datomic:free://localhost:4334/skirmish.ledger?password=datomicpassword"}
|
||||
|
||||
;; all the kafka configuration goes bellow.
|
||||
:kafka
|
||||
{:bootstrap.servers #or [#env KAFKA_BOOTSTRAP_SERVERS "localhost:9092"]
|
||||
@@ -24,19 +27,21 @@
|
||||
:max-body 524288 ;; 512kb, small but enough
|
||||
:max-ws 524288}
|
||||
|
||||
:ledger-server
|
||||
{:port #long #or [#env LEDGER_SERVER_PORT 1604]
|
||||
:ip "0.0.0.0"
|
||||
:max-body 524288 ;; 512kb, small but enough
|
||||
:max-ws 524288}
|
||||
|
||||
:api-broker
|
||||
{:port #long #or [#env BROKER_SERVER_PORT 1605]
|
||||
:ip "0.0.0.0"
|
||||
:max-body 524288 ;; 512kb, small but enough
|
||||
:max-ws 524288
|
||||
:default-sec-id :dapm
|
||||
:datomic {:transactor-url "datomic:free://localhost:4334/skirmish.broker?password=datomicpassword"}}
|
||||
|
||||
:wui
|
||||
{:port #long #or [#env WUI_PORT 3000]}
|
||||
|
||||
;; list of tradable securities
|
||||
:securities
|
||||
[{:sec-id :foo}
|
||||
{:sec-id :bar}
|
||||
{:sec-id :toto}
|
||||
{:sec-id :tata}]
|
||||
|
||||
;; stupid parameters about benchmarking tools
|
||||
:benchmark {
|
||||
:number-of-requests-per-securities 30}}
|
||||
|
||||
{:port #long #or [#env WUI_PORT 3000]}}
|
||||
|
||||
|
||||
+415
-88
@@ -14,7 +14,7 @@
|
||||
-ms-user-select: none;
|
||||
user-select: none; }
|
||||
|
||||
.select:not(.is-multiple):not(.is-loading)::after, .navbar-link::after {
|
||||
.select:not(.is-multiple):not(.is-loading)::after, .navbar-link:not(.is-arrowless)::after {
|
||||
border: 3px solid transparent;
|
||||
border-radius: 2px;
|
||||
border-right: 0;
|
||||
@@ -31,7 +31,7 @@
|
||||
width: 0.625em; }
|
||||
|
||||
.box:not(:last-child), .content:not(:last-child), .notification:not(:last-child), .progress:not(:last-child), .table:not(:last-child), .table-container:not(:last-child), .title:not(:last-child),
|
||||
.subtitle:not(:last-child), .block:not(:last-child), .highlight:not(:last-child), .breadcrumb:not(:last-child), .level:not(:last-child), .message:not(:last-child), .tabs:not(:last-child) {
|
||||
.subtitle:not(:last-child), .block:not(:last-child), .highlight:not(:last-child), .breadcrumb:not(:last-child), .level:not(:last-child), .list:not(:last-child), .message:not(:last-child), .tabs:not(:last-child) {
|
||||
margin-bottom: 1.5rem; }
|
||||
|
||||
.delete, .modal-close {
|
||||
@@ -41,6 +41,7 @@
|
||||
border: none;
|
||||
border-radius: 290486px;
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
display: inline-block;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
@@ -993,6 +994,16 @@ a.has-text-danger:hover, a.has-text-danger:focus {
|
||||
.is-hidden {
|
||||
display: none !important; }
|
||||
|
||||
.is-sr-only {
|
||||
border: none !important;
|
||||
clip: rect(0, 0, 0, 0) !important;
|
||||
height: 0.01em !important;
|
||||
overflow: hidden !important;
|
||||
padding: 0 !important;
|
||||
position: absolute !important;
|
||||
white-space: nowrap !important;
|
||||
width: 0.01em !important; }
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.is-hidden-mobile {
|
||||
display: none !important; } }
|
||||
@@ -1081,10 +1092,10 @@ a.has-text-danger:hover, a.has-text-danger:focus {
|
||||
box-shadow: none !important; }
|
||||
|
||||
.box {
|
||||
background-color: white;
|
||||
background-color: #7a7a7a;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
|
||||
color: whitesmoke;
|
||||
box-shadow: 0 2px 3px #b5b5b5, 0 0 0 1px #b5b5b5;
|
||||
color: white;
|
||||
display: block;
|
||||
padding: 1.25rem; }
|
||||
|
||||
@@ -1788,7 +1799,7 @@ a.box:active {
|
||||
justify-content: flex-start; }
|
||||
.buttons .button {
|
||||
margin-bottom: 0.5rem; }
|
||||
.buttons .button:not(:last-child) {
|
||||
.buttons .button:not(:last-child):not(.is-fullwidth) {
|
||||
margin-right: 0.5rem; }
|
||||
.buttons:last-child {
|
||||
margin-bottom: -0.5rem; }
|
||||
@@ -1899,13 +1910,23 @@ a.box:active {
|
||||
|
||||
.content blockquote {
|
||||
background-color: #0a0a0a;
|
||||
border-left: 5px solid #ffdd57;
|
||||
border-left: 5px solid #dbdbdb;
|
||||
padding: 1.25em 1.5em; }
|
||||
|
||||
.content ol {
|
||||
list-style: decimal outside;
|
||||
list-style-position: outside;
|
||||
margin-left: 2em;
|
||||
margin-top: 1em; }
|
||||
.content ol:not([type]) {
|
||||
list-style-type: decimal; }
|
||||
.content ol:not([type]).is-lower-alpha {
|
||||
list-style-type: lower-alpha; }
|
||||
.content ol:not([type]).is-lower-roman {
|
||||
list-style-type: lower-roman; }
|
||||
.content ol:not([type]).is-upper-alpha {
|
||||
list-style-type: upper-alpha; }
|
||||
.content ol:not([type]).is-upper-roman {
|
||||
list-style-type: upper-roman; }
|
||||
|
||||
.content ul {
|
||||
list-style: disc outside;
|
||||
@@ -1948,7 +1969,7 @@ a.box:active {
|
||||
width: 100%; }
|
||||
.content table td,
|
||||
.content table th {
|
||||
border: 1px solid #ffdd57;
|
||||
border: 1px solid #dbdbdb;
|
||||
border-width: 0 0 1px;
|
||||
padding: 0.5em 0.75em;
|
||||
vertical-align: top; }
|
||||
@@ -2239,7 +2260,7 @@ a.box:active {
|
||||
.select select:not([multiple]) {
|
||||
padding-right: 2.5em; }
|
||||
.select select[multiple] {
|
||||
height: initial;
|
||||
height: auto;
|
||||
padding: 0; }
|
||||
.select select[multiple] option {
|
||||
padding: 0.5em 1em; }
|
||||
@@ -2587,24 +2608,25 @@ a.box:active {
|
||||
background-color: #eeeeee;
|
||||
color: #363636; }
|
||||
.file-label:hover .file-name {
|
||||
border-color: #ffdb4a; }
|
||||
border-color: #d5d5d5; }
|
||||
.file-label:active .file-cta {
|
||||
background-color: #e8e8e8;
|
||||
color: #363636; }
|
||||
.file-label:active .file-name {
|
||||
border-color: #ffd83d; }
|
||||
border-color: #cfcfcf; }
|
||||
|
||||
.file-input {
|
||||
height: 0.01em;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
outline: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 0.01em; }
|
||||
width: 100%; }
|
||||
|
||||
.file-cta,
|
||||
.file-name {
|
||||
border-color: #ffdd57;
|
||||
border-color: #dbdbdb;
|
||||
border-radius: 4px;
|
||||
font-size: 1em;
|
||||
padding-left: 1em;
|
||||
@@ -2616,7 +2638,7 @@ a.box:active {
|
||||
color: #4a4a4a; }
|
||||
|
||||
.file-name {
|
||||
border-color: #ffdd57;
|
||||
border-color: #dbdbdb;
|
||||
border-style: solid;
|
||||
border-width: 1px 1px 1px 0;
|
||||
display: block;
|
||||
@@ -2696,31 +2718,31 @@ a.box:active {
|
||||
.field.has-addons .control:last-child .select select {
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0; }
|
||||
.field.has-addons .control .button:hover, .field.has-addons .control .button.is-hovered,
|
||||
.field.has-addons .control .input:hover,
|
||||
.field.has-addons .control .input.is-hovered,
|
||||
.field.has-addons .control .select select:hover,
|
||||
.field.has-addons .control .select select.is-hovered {
|
||||
.field.has-addons .control .button:not([disabled]):hover, .field.has-addons .control .button:not([disabled]).is-hovered,
|
||||
.field.has-addons .control .input:not([disabled]):hover,
|
||||
.field.has-addons .control .input:not([disabled]).is-hovered,
|
||||
.field.has-addons .control .select select:not([disabled]):hover,
|
||||
.field.has-addons .control .select select:not([disabled]).is-hovered {
|
||||
z-index: 2; }
|
||||
.field.has-addons .control .button:focus, .field.has-addons .control .button.is-focused, .field.has-addons .control .button:active, .field.has-addons .control .button.is-active,
|
||||
.field.has-addons .control .input:focus,
|
||||
.field.has-addons .control .input.is-focused,
|
||||
.field.has-addons .control .input:active,
|
||||
.field.has-addons .control .input.is-active,
|
||||
.field.has-addons .control .select select:focus,
|
||||
.field.has-addons .control .select select.is-focused,
|
||||
.field.has-addons .control .select select:active,
|
||||
.field.has-addons .control .select select.is-active {
|
||||
.field.has-addons .control .button:not([disabled]):focus, .field.has-addons .control .button:not([disabled]).is-focused, .field.has-addons .control .button:not([disabled]):active, .field.has-addons .control .button:not([disabled]).is-active,
|
||||
.field.has-addons .control .input:not([disabled]):focus,
|
||||
.field.has-addons .control .input:not([disabled]).is-focused,
|
||||
.field.has-addons .control .input:not([disabled]):active,
|
||||
.field.has-addons .control .input:not([disabled]).is-active,
|
||||
.field.has-addons .control .select select:not([disabled]):focus,
|
||||
.field.has-addons .control .select select:not([disabled]).is-focused,
|
||||
.field.has-addons .control .select select:not([disabled]):active,
|
||||
.field.has-addons .control .select select:not([disabled]).is-active {
|
||||
z-index: 3; }
|
||||
.field.has-addons .control .button:focus:hover, .field.has-addons .control .button.is-focused:hover, .field.has-addons .control .button:active:hover, .field.has-addons .control .button.is-active:hover,
|
||||
.field.has-addons .control .input:focus:hover,
|
||||
.field.has-addons .control .input.is-focused:hover,
|
||||
.field.has-addons .control .input:active:hover,
|
||||
.field.has-addons .control .input.is-active:hover,
|
||||
.field.has-addons .control .select select:focus:hover,
|
||||
.field.has-addons .control .select select.is-focused:hover,
|
||||
.field.has-addons .control .select select:active:hover,
|
||||
.field.has-addons .control .select select.is-active:hover {
|
||||
.field.has-addons .control .button:not([disabled]):focus:hover, .field.has-addons .control .button:not([disabled]).is-focused:hover, .field.has-addons .control .button:not([disabled]):active:hover, .field.has-addons .control .button:not([disabled]).is-active:hover,
|
||||
.field.has-addons .control .input:not([disabled]):focus:hover,
|
||||
.field.has-addons .control .input:not([disabled]).is-focused:hover,
|
||||
.field.has-addons .control .input:not([disabled]):active:hover,
|
||||
.field.has-addons .control .input:not([disabled]).is-active:hover,
|
||||
.field.has-addons .control .select select:not([disabled]):focus:hover,
|
||||
.field.has-addons .control .select select:not([disabled]).is-focused:hover,
|
||||
.field.has-addons .control .select select:not([disabled]):active:hover,
|
||||
.field.has-addons .control .select select:not([disabled]).is-active:hover {
|
||||
z-index: 4; }
|
||||
.field.has-addons .control.is-expanded {
|
||||
flex-grow: 1; }
|
||||
@@ -2805,6 +2827,7 @@ a.box:active {
|
||||
margin-right: 0.75rem; } }
|
||||
|
||||
.control {
|
||||
clear: both;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
text-align: left; }
|
||||
@@ -2963,7 +2986,7 @@ a.box:active {
|
||||
border-radius: 4px;
|
||||
padding: 1.25rem 2.5rem 1.25rem 1.5rem;
|
||||
position: relative; }
|
||||
.notification a:not(.button) {
|
||||
.notification a:not(.button):not(.dropdown-item) {
|
||||
color: currentColor;
|
||||
text-decoration: underline; }
|
||||
.notification strong {
|
||||
@@ -3023,7 +3046,7 @@ a.box:active {
|
||||
padding: 0;
|
||||
width: 100%; }
|
||||
.progress::-webkit-progress-bar {
|
||||
background-color: #ffdd57; }
|
||||
background-color: #dbdbdb; }
|
||||
.progress::-webkit-progress-value {
|
||||
background-color: whitesmoke; }
|
||||
.progress::-moz-progress-bar {
|
||||
@@ -3203,9 +3226,11 @@ a.box:active {
|
||||
.table.is-fullwidth {
|
||||
width: 100%; }
|
||||
.table.is-hoverable tbody tr:not(.is-selected):hover {
|
||||
background-color: #fafafa; }
|
||||
background-color: #242424; }
|
||||
.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover {
|
||||
background-color: whitesmoke; }
|
||||
background-color: #242424; }
|
||||
.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) {
|
||||
background-color: whitesmoke; }
|
||||
.table.is-narrow td,
|
||||
.table.is-narrow th {
|
||||
padding: 0.25em 0.5em; }
|
||||
@@ -3502,7 +3527,7 @@ a.tag:hover {
|
||||
position: relative; }
|
||||
|
||||
.card-header {
|
||||
background-color: none;
|
||||
background-color: transparent;
|
||||
align-items: stretch;
|
||||
box-shadow: 0 1px 2px rgba(10, 10, 10, 0.1);
|
||||
display: flex; }
|
||||
@@ -3529,12 +3554,12 @@ a.tag:hover {
|
||||
position: relative; }
|
||||
|
||||
.card-content {
|
||||
background-color: none;
|
||||
background-color: transparent;
|
||||
padding: 1.5rem; }
|
||||
|
||||
.card-footer {
|
||||
background-color: none;
|
||||
border-top: 1px solid #ffdd57;
|
||||
background-color: transparent;
|
||||
border-top: 1px solid #dbdbdb;
|
||||
align-items: stretch;
|
||||
display: flex; }
|
||||
|
||||
@@ -3547,7 +3572,7 @@ a.tag:hover {
|
||||
justify-content: center;
|
||||
padding: 0.75rem; }
|
||||
.card-footer-item:not(:last-child) {
|
||||
border-right: 1px solid #ffdd57; }
|
||||
border-right: 1px solid #dbdbdb; }
|
||||
|
||||
.card .media:not(:last-child) {
|
||||
margin-bottom: 0.75rem; }
|
||||
@@ -3591,18 +3616,23 @@ a.tag:hover {
|
||||
padding: 0.375rem 1rem;
|
||||
position: relative; }
|
||||
|
||||
a.dropdown-item {
|
||||
a.dropdown-item,
|
||||
button.dropdown-item {
|
||||
padding-right: 3rem;
|
||||
white-space: nowrap; }
|
||||
a.dropdown-item:hover {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
width: 100%; }
|
||||
a.dropdown-item:hover,
|
||||
button.dropdown-item:hover {
|
||||
background-color: #0a0a0a;
|
||||
color: #0a0a0a; }
|
||||
a.dropdown-item.is-active {
|
||||
a.dropdown-item.is-active,
|
||||
button.dropdown-item.is-active {
|
||||
background-color: #00d1b2;
|
||||
color: #fff; }
|
||||
|
||||
.dropdown-divider {
|
||||
background-color: #ffdd57;
|
||||
background-color: #dbdbdb;
|
||||
border: none;
|
||||
display: block;
|
||||
height: 1px;
|
||||
@@ -3623,12 +3653,11 @@ a.dropdown-item {
|
||||
display: flex; }
|
||||
.level.is-mobile .level-left + .level-right {
|
||||
margin-top: 0; }
|
||||
.level.is-mobile .level-item {
|
||||
.level.is-mobile .level-item:not(:last-child) {
|
||||
margin-bottom: 0;
|
||||
margin-right: 0.75rem; }
|
||||
.level.is-mobile .level-item:not(:last-child) {
|
||||
margin-bottom: 0; }
|
||||
.level.is-mobile .level-item:not(.is-narrow) {
|
||||
flex-grow: 1; }
|
||||
.level.is-mobile .level-item:not(.is-narrow) {
|
||||
flex-grow: 1; }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.level {
|
||||
display: flex; }
|
||||
@@ -3679,6 +3708,32 @@ a.dropdown-item {
|
||||
.level-right {
|
||||
display: flex; } }
|
||||
|
||||
.list {
|
||||
background-color: white;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); }
|
||||
|
||||
.list-item {
|
||||
display: block;
|
||||
padding: 0.5em 1em; }
|
||||
.list-item:not(a) {
|
||||
color: whitesmoke; }
|
||||
.list-item:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px; }
|
||||
.list-item:last-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px; }
|
||||
.list-item:not(:last-child) {
|
||||
border-bottom: 1px solid #dbdbdb; }
|
||||
.list-item.is-active {
|
||||
background-color: #00d1b2;
|
||||
color: #fff; }
|
||||
|
||||
a.list-item {
|
||||
background-color: #0a0a0a;
|
||||
cursor: pointer; }
|
||||
|
||||
.media {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
@@ -3686,7 +3741,7 @@ a.dropdown-item {
|
||||
.media .content:not(:last-child) {
|
||||
margin-bottom: 0.75rem; }
|
||||
.media .media {
|
||||
border-top: 1px solid rgba(255, 221, 87, 0.5);
|
||||
border-top: 1px solid rgba(219, 219, 219, 0.5);
|
||||
display: flex;
|
||||
padding-top: 0.75rem; }
|
||||
.media .media .content:not(:last-child),
|
||||
@@ -3697,7 +3752,7 @@ a.dropdown-item {
|
||||
.media .media .media + .media {
|
||||
margin-top: 0.5rem; }
|
||||
.media + .media {
|
||||
border-top: 1px solid rgba(255, 221, 87, 0.5);
|
||||
border-top: 1px solid rgba(219, 219, 219, 0.5);
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem; }
|
||||
.media.is-large + .media {
|
||||
@@ -3722,6 +3777,10 @@ a.dropdown-item {
|
||||
flex-shrink: 1;
|
||||
text-align: left; }
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.media-content {
|
||||
overflow-x: auto; } }
|
||||
|
||||
.menu {
|
||||
font-size: 1rem; }
|
||||
.menu.is-small {
|
||||
@@ -3745,7 +3804,7 @@ a.dropdown-item {
|
||||
background-color: #00d1b2;
|
||||
color: #fff; }
|
||||
.menu-list li ul {
|
||||
border-left: 1px solid #ffdd57;
|
||||
border-left: 1px solid #dbdbdb;
|
||||
margin: 0.75em;
|
||||
padding-left: 0.75em; }
|
||||
|
||||
@@ -3876,7 +3935,7 @@ a.dropdown-item {
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.message-body {
|
||||
border-color: #ffdd57;
|
||||
border-color: #dbdbdb;
|
||||
border-radius: 4px;
|
||||
border-style: solid;
|
||||
border-width: 0 0 0 4px;
|
||||
@@ -3891,6 +3950,7 @@ a.dropdown-item {
|
||||
.modal {
|
||||
align-items: center;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
@@ -3927,7 +3987,8 @@ a.dropdown-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow: hidden; }
|
||||
overflow: hidden;
|
||||
-ms-overflow-y: visible; }
|
||||
|
||||
.modal-card-head,
|
||||
.modal-card-foot {
|
||||
@@ -3940,7 +4001,7 @@ a.dropdown-item {
|
||||
position: relative; }
|
||||
|
||||
.modal-card-head {
|
||||
border-bottom: 1px solid #ffdd57;
|
||||
border-bottom: 1px solid #dbdbdb;
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px; }
|
||||
|
||||
@@ -3954,7 +4015,7 @@ a.dropdown-item {
|
||||
.modal-card-foot {
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
border-top: 1px solid #ffdd57; }
|
||||
border-top: 1px solid #dbdbdb; }
|
||||
.modal-card-foot .button:not(:last-child) {
|
||||
margin-right: 10px; }
|
||||
|
||||
@@ -3984,6 +4045,8 @@ a.dropdown-item {
|
||||
color: #0a0a0a; }
|
||||
.navbar.is-white .navbar-brand .navbar-link::after {
|
||||
border-color: #0a0a0a; }
|
||||
.navbar.is-white .navbar-burger {
|
||||
color: #0a0a0a; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-white .navbar-start > .navbar-item,
|
||||
.navbar.is-white .navbar-start .navbar-link,
|
||||
@@ -4022,6 +4085,8 @@ a.dropdown-item {
|
||||
color: white; }
|
||||
.navbar.is-black .navbar-brand .navbar-link::after {
|
||||
border-color: white; }
|
||||
.navbar.is-black .navbar-burger {
|
||||
color: white; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-black .navbar-start > .navbar-item,
|
||||
.navbar.is-black .navbar-start .navbar-link,
|
||||
@@ -4060,6 +4125,8 @@ a.dropdown-item {
|
||||
color: #363636; }
|
||||
.navbar.is-light .navbar-brand .navbar-link::after {
|
||||
border-color: #363636; }
|
||||
.navbar.is-light .navbar-burger {
|
||||
color: #363636; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-light .navbar-start > .navbar-item,
|
||||
.navbar.is-light .navbar-start .navbar-link,
|
||||
@@ -4098,6 +4165,8 @@ a.dropdown-item {
|
||||
color: whitesmoke; }
|
||||
.navbar.is-dark .navbar-brand .navbar-link::after {
|
||||
border-color: whitesmoke; }
|
||||
.navbar.is-dark .navbar-burger {
|
||||
color: whitesmoke; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-dark .navbar-start > .navbar-item,
|
||||
.navbar.is-dark .navbar-start .navbar-link,
|
||||
@@ -4136,6 +4205,8 @@ a.dropdown-item {
|
||||
color: #fff; }
|
||||
.navbar.is-primary .navbar-brand .navbar-link::after {
|
||||
border-color: #fff; }
|
||||
.navbar.is-primary .navbar-burger {
|
||||
color: #fff; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-primary .navbar-start > .navbar-item,
|
||||
.navbar.is-primary .navbar-start .navbar-link,
|
||||
@@ -4174,6 +4245,8 @@ a.dropdown-item {
|
||||
color: #fff; }
|
||||
.navbar.is-link .navbar-brand .navbar-link::after {
|
||||
border-color: #fff; }
|
||||
.navbar.is-link .navbar-burger {
|
||||
color: #fff; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-link .navbar-start > .navbar-item,
|
||||
.navbar.is-link .navbar-start .navbar-link,
|
||||
@@ -4212,6 +4285,8 @@ a.dropdown-item {
|
||||
color: #fff; }
|
||||
.navbar.is-info .navbar-brand .navbar-link::after {
|
||||
border-color: #fff; }
|
||||
.navbar.is-info .navbar-burger {
|
||||
color: #fff; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-info .navbar-start > .navbar-item,
|
||||
.navbar.is-info .navbar-start .navbar-link,
|
||||
@@ -4250,6 +4325,8 @@ a.dropdown-item {
|
||||
color: #fff; }
|
||||
.navbar.is-success .navbar-brand .navbar-link::after {
|
||||
border-color: #fff; }
|
||||
.navbar.is-success .navbar-burger {
|
||||
color: #fff; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-success .navbar-start > .navbar-item,
|
||||
.navbar.is-success .navbar-start .navbar-link,
|
||||
@@ -4288,6 +4365,8 @@ a.dropdown-item {
|
||||
color: rgba(0, 0, 0, 0.7); }
|
||||
.navbar.is-warning .navbar-brand .navbar-link::after {
|
||||
border-color: rgba(0, 0, 0, 0.7); }
|
||||
.navbar.is-warning .navbar-burger {
|
||||
color: rgba(0, 0, 0, 0.7); }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-warning .navbar-start > .navbar-item,
|
||||
.navbar.is-warning .navbar-start .navbar-link,
|
||||
@@ -4326,6 +4405,8 @@ a.dropdown-item {
|
||||
color: #fff; }
|
||||
.navbar.is-danger .navbar-brand .navbar-link::after {
|
||||
border-color: #fff; }
|
||||
.navbar.is-danger .navbar-burger {
|
||||
color: #fff; }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.navbar.is-danger .navbar-start > .navbar-item,
|
||||
.navbar.is-danger .navbar-start .navbar-link,
|
||||
@@ -4395,6 +4476,7 @@ body.has-navbar-fixed-bottom {
|
||||
overflow-y: hidden; }
|
||||
|
||||
.navbar-burger {
|
||||
color: #4a4a4a;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: 3.25rem;
|
||||
@@ -4481,9 +4563,9 @@ a.navbar-item,
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1; }
|
||||
|
||||
.navbar-link {
|
||||
.navbar-link:not(.is-arrowless) {
|
||||
padding-right: 2.5em; }
|
||||
.navbar-link::after {
|
||||
.navbar-link:not(.is-arrowless)::after {
|
||||
border-color: #00d1b2;
|
||||
margin-top: -0.375em;
|
||||
right: 1.125em; }
|
||||
@@ -4564,8 +4646,8 @@ a.navbar-item,
|
||||
.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link {
|
||||
background-color: transparent !important; }
|
||||
.navbar.is-transparent .navbar-dropdown a.navbar-item:hover {
|
||||
background-color: #0a0a0a;
|
||||
color: #0a0a0a; }
|
||||
background-color: #363636;
|
||||
color: none; }
|
||||
.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active {
|
||||
background-color: #0a0a0a;
|
||||
color: #00d1b2; }
|
||||
@@ -4582,7 +4664,7 @@ a.navbar-item,
|
||||
.navbar-item.has-dropdown-up .navbar-link::after {
|
||||
transform: rotate(135deg) translate(0.25em, -0.25em); }
|
||||
.navbar-item.has-dropdown-up .navbar-dropdown {
|
||||
border-bottom: 2px solid #ffdd57;
|
||||
border-bottom: 1px solid #00d1b2;
|
||||
border-radius: 6px 6px 0 0;
|
||||
border-top: none;
|
||||
bottom: 100%;
|
||||
@@ -4604,10 +4686,10 @@ a.navbar-item,
|
||||
justify-content: flex-end;
|
||||
margin-left: auto; }
|
||||
.navbar-dropdown {
|
||||
background-color: white;
|
||||
background-color: #363636;
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
border-top: 2px solid #ffdd57;
|
||||
border-top: 1px solid #00d1b2;
|
||||
box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1);
|
||||
display: none;
|
||||
font-size: 0.875rem;
|
||||
@@ -4622,8 +4704,8 @@ a.navbar-item,
|
||||
.navbar-dropdown a.navbar-item {
|
||||
padding-right: 3rem; }
|
||||
.navbar-dropdown a.navbar-item:hover {
|
||||
background-color: #0a0a0a;
|
||||
color: #0a0a0a; }
|
||||
background-color: #363636;
|
||||
color: none; }
|
||||
.navbar-dropdown a.navbar-item.is-active {
|
||||
background-color: #0a0a0a;
|
||||
color: #00d1b2; }
|
||||
@@ -4645,10 +4727,10 @@ a.navbar-item,
|
||||
display: block; }
|
||||
.navbar > .container .navbar-brand,
|
||||
.container > .navbar .navbar-brand {
|
||||
margin-left: -1rem; }
|
||||
margin-left: -.75rem; }
|
||||
.navbar > .container .navbar-menu,
|
||||
.container > .navbar .navbar-menu {
|
||||
margin-right: -1rem; }
|
||||
margin-right: -.75rem; }
|
||||
.navbar.is-fixed-bottom-desktop, .navbar.is-fixed-top-desktop {
|
||||
left: 0;
|
||||
position: fixed;
|
||||
@@ -4808,13 +4890,13 @@ a.navbar-item,
|
||||
.panel-heading,
|
||||
.panel-tabs,
|
||||
.panel-block {
|
||||
border-bottom: 1px solid #ffdd57;
|
||||
border-left: 1px solid #ffdd57;
|
||||
border-right: 1px solid #ffdd57; }
|
||||
border-bottom: 1px solid #dbdbdb;
|
||||
border-left: 1px solid #dbdbdb;
|
||||
border-right: 1px solid #dbdbdb; }
|
||||
.panel-heading:first-child,
|
||||
.panel-tabs:first-child,
|
||||
.panel-block:first-child {
|
||||
border-top: 1px solid #ffdd57; }
|
||||
border-top: 1px solid #dbdbdb; }
|
||||
|
||||
.panel-heading {
|
||||
background-color: #0a0a0a;
|
||||
@@ -4831,7 +4913,7 @@ a.navbar-item,
|
||||
font-size: 0.875em;
|
||||
justify-content: center; }
|
||||
.panel-tabs a {
|
||||
border-bottom: 1px solid #ffdd57;
|
||||
border-bottom: 1px solid #dbdbdb;
|
||||
margin-bottom: -1px;
|
||||
padding: 0.5em; }
|
||||
.panel-tabs a.is-active {
|
||||
@@ -4895,7 +4977,7 @@ label.panel-block {
|
||||
white-space: nowrap; }
|
||||
.tabs a {
|
||||
align-items: center;
|
||||
border-bottom-color: #ffdd57;
|
||||
border-bottom-color: #dbdbdb;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
color: whitesmoke;
|
||||
@@ -4914,7 +4996,7 @@ label.panel-block {
|
||||
color: #00d1b2; }
|
||||
.tabs ul {
|
||||
align-items: center;
|
||||
border-bottom-color: #ffdd57;
|
||||
border-bottom-color: #dbdbdb;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
display: flex;
|
||||
@@ -4944,16 +5026,16 @@ label.panel-block {
|
||||
border-radius: 4px 4px 0 0; }
|
||||
.tabs.is-boxed a:hover {
|
||||
background-color: #0a0a0a;
|
||||
border-bottom-color: #ffdd57; }
|
||||
border-bottom-color: #dbdbdb; }
|
||||
.tabs.is-boxed li.is-active a {
|
||||
background-color: white;
|
||||
border-color: #ffdd57;
|
||||
border-color: #dbdbdb;
|
||||
border-bottom-color: transparent !important; }
|
||||
.tabs.is-fullwidth li {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0; }
|
||||
.tabs.is-toggle a {
|
||||
border-color: #ffdd57;
|
||||
border-color: #dbdbdb;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
margin-bottom: 0;
|
||||
@@ -5816,22 +5898,265 @@ label.panel-block {
|
||||
padding-right: var(--columnGap); }
|
||||
.columns.is-variable.is-0 {
|
||||
--columnGap: 0rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-0-mobile {
|
||||
--columnGap: 0rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-0-tablet {
|
||||
--columnGap: 0rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-0-tablet-only {
|
||||
--columnGap: 0rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-0-touch {
|
||||
--columnGap: 0rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-0-desktop {
|
||||
--columnGap: 0rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-0-desktop-only {
|
||||
--columnGap: 0rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-0-widescreen {
|
||||
--columnGap: 0rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-0-widescreen-only {
|
||||
--columnGap: 0rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-0-fullhd {
|
||||
--columnGap: 0rem; } }
|
||||
.columns.is-variable.is-1 {
|
||||
--columnGap: 0.25rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-1-mobile {
|
||||
--columnGap: 0.25rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-1-tablet {
|
||||
--columnGap: 0.25rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-1-tablet-only {
|
||||
--columnGap: 0.25rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-1-touch {
|
||||
--columnGap: 0.25rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-1-desktop {
|
||||
--columnGap: 0.25rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-1-desktop-only {
|
||||
--columnGap: 0.25rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-1-widescreen {
|
||||
--columnGap: 0.25rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-1-widescreen-only {
|
||||
--columnGap: 0.25rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-1-fullhd {
|
||||
--columnGap: 0.25rem; } }
|
||||
.columns.is-variable.is-2 {
|
||||
--columnGap: 0.5rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-2-mobile {
|
||||
--columnGap: 0.5rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-2-tablet {
|
||||
--columnGap: 0.5rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-2-tablet-only {
|
||||
--columnGap: 0.5rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-2-touch {
|
||||
--columnGap: 0.5rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-2-desktop {
|
||||
--columnGap: 0.5rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-2-desktop-only {
|
||||
--columnGap: 0.5rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-2-widescreen {
|
||||
--columnGap: 0.5rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-2-widescreen-only {
|
||||
--columnGap: 0.5rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-2-fullhd {
|
||||
--columnGap: 0.5rem; } }
|
||||
.columns.is-variable.is-3 {
|
||||
--columnGap: 0.75rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-3-mobile {
|
||||
--columnGap: 0.75rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-3-tablet {
|
||||
--columnGap: 0.75rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-3-tablet-only {
|
||||
--columnGap: 0.75rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-3-touch {
|
||||
--columnGap: 0.75rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-3-desktop {
|
||||
--columnGap: 0.75rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-3-desktop-only {
|
||||
--columnGap: 0.75rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-3-widescreen {
|
||||
--columnGap: 0.75rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-3-widescreen-only {
|
||||
--columnGap: 0.75rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-3-fullhd {
|
||||
--columnGap: 0.75rem; } }
|
||||
.columns.is-variable.is-4 {
|
||||
--columnGap: 1rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-4-mobile {
|
||||
--columnGap: 1rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-4-tablet {
|
||||
--columnGap: 1rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-4-tablet-only {
|
||||
--columnGap: 1rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-4-touch {
|
||||
--columnGap: 1rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-4-desktop {
|
||||
--columnGap: 1rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-4-desktop-only {
|
||||
--columnGap: 1rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-4-widescreen {
|
||||
--columnGap: 1rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-4-widescreen-only {
|
||||
--columnGap: 1rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-4-fullhd {
|
||||
--columnGap: 1rem; } }
|
||||
.columns.is-variable.is-5 {
|
||||
--columnGap: 1.25rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-5-mobile {
|
||||
--columnGap: 1.25rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-5-tablet {
|
||||
--columnGap: 1.25rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-5-tablet-only {
|
||||
--columnGap: 1.25rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-5-touch {
|
||||
--columnGap: 1.25rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-5-desktop {
|
||||
--columnGap: 1.25rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-5-desktop-only {
|
||||
--columnGap: 1.25rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-5-widescreen {
|
||||
--columnGap: 1.25rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-5-widescreen-only {
|
||||
--columnGap: 1.25rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-5-fullhd {
|
||||
--columnGap: 1.25rem; } }
|
||||
.columns.is-variable.is-6 {
|
||||
--columnGap: 1.5rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-6-mobile {
|
||||
--columnGap: 1.5rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-6-tablet {
|
||||
--columnGap: 1.5rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-6-tablet-only {
|
||||
--columnGap: 1.5rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-6-touch {
|
||||
--columnGap: 1.5rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-6-desktop {
|
||||
--columnGap: 1.5rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-6-desktop-only {
|
||||
--columnGap: 1.5rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-6-widescreen {
|
||||
--columnGap: 1.5rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-6-widescreen-only {
|
||||
--columnGap: 1.5rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-6-fullhd {
|
||||
--columnGap: 1.5rem; } }
|
||||
.columns.is-variable.is-7 {
|
||||
--columnGap: 1.75rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-7-mobile {
|
||||
--columnGap: 1.75rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-7-tablet {
|
||||
--columnGap: 1.75rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-7-tablet-only {
|
||||
--columnGap: 1.75rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-7-touch {
|
||||
--columnGap: 1.75rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-7-desktop {
|
||||
--columnGap: 1.75rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-7-desktop-only {
|
||||
--columnGap: 1.75rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-7-widescreen {
|
||||
--columnGap: 1.75rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-7-widescreen-only {
|
||||
--columnGap: 1.75rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-7-fullhd {
|
||||
--columnGap: 1.75rem; } }
|
||||
.columns.is-variable.is-8 {
|
||||
--columnGap: 2rem; }
|
||||
@media screen and (max-width: 768px) {
|
||||
.columns.is-variable.is-8-mobile {
|
||||
--columnGap: 2rem; } }
|
||||
@media screen and (min-width: 769px), print {
|
||||
.columns.is-variable.is-8-tablet {
|
||||
--columnGap: 2rem; } }
|
||||
@media screen and (min-width: 769px) and (max-width: 1087px) {
|
||||
.columns.is-variable.is-8-tablet-only {
|
||||
--columnGap: 2rem; } }
|
||||
@media screen and (max-width: 1087px) {
|
||||
.columns.is-variable.is-8-touch {
|
||||
--columnGap: 2rem; } }
|
||||
@media screen and (min-width: 1088px) {
|
||||
.columns.is-variable.is-8-desktop {
|
||||
--columnGap: 2rem; } }
|
||||
@media screen and (min-width: 1088px) and (max-width: 1279px) {
|
||||
.columns.is-variable.is-8-desktop-only {
|
||||
--columnGap: 2rem; } }
|
||||
@media screen and (min-width: 1280px) {
|
||||
.columns.is-variable.is-8-widescreen {
|
||||
--columnGap: 2rem; } }
|
||||
@media screen and (min-width: 1280px) and (max-width: 1471px) {
|
||||
.columns.is-variable.is-8-widescreen-only {
|
||||
--columnGap: 2rem; } }
|
||||
@media screen and (min-width: 1472px) {
|
||||
.columns.is-variable.is-8-fullhd {
|
||||
--columnGap: 2rem; } }
|
||||
|
||||
.tile {
|
||||
align-items: stretch;
|
||||
@@ -6356,16 +6681,18 @@ label.panel-block {
|
||||
.hero.is-large .hero-body {
|
||||
padding-bottom: 18rem;
|
||||
padding-top: 18rem; } }
|
||||
.hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body {
|
||||
.hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body, .hero.is-fullheight-with-navbar .hero-body {
|
||||
align-items: center;
|
||||
display: flex; }
|
||||
.hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container {
|
||||
.hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container, .hero.is-fullheight-with-navbar .hero-body > .container {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1; }
|
||||
.hero.is-halfheight {
|
||||
min-height: 50vh; }
|
||||
.hero.is-fullheight {
|
||||
min-height: 100vh; }
|
||||
.hero.is-fullheight-with-navbar {
|
||||
min-height: calc(100vh - 3.25rem); }
|
||||
|
||||
.hero-video {
|
||||
overflow: hidden; }
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="Слой_1" data-name="Слой 1" viewBox="0 0 320 76.71">
|
||||
<defs>
|
||||
<style>.cls-1{fill:#fff;}.cls-2{fill:#fffcef;}.cls-3{fill:#333;}</style>
|
||||
</defs>
|
||||
<title>hq__amsterdam</title>
|
||||
<rect class="cls-1" x="209.68" y="41.71" width="15.45" height="29.85"/>
|
||||
<rect class="cls-2" x="56.42" y="11.54" width="2.1" height="7.59"/>
|
||||
<ellipse class="cls-3" cx="8.25" cy="52.07" rx="0.57" ry="0.82"/>
|
||||
<path class="cls-3" d="M8.25,53.38a1.34,1.34,0,0,1,0-2.61,1.34,1.34,0,0,1,0,2.61Zm0-1.6a.53.53,0,0,0-.08.29.47.47,0,0,0,.1.33s0-.14,0-.33A.53.53,0,0,0,8.25,51.78Z"/>
|
||||
<ellipse class="cls-3" cx="13.72" cy="52.07" rx="0.57" ry="0.82"/>
|
||||
<path class="cls-3" d="M13.72,53.38a1.34,1.34,0,0,1,0-2.61,1.34,1.34,0,0,1,0,2.61Zm0-1.6a.53.53,0,0,0-.08.29.47.47,0,0,0,.1.33s0-.14,0-.33A.53.53,0,0,0,13.72,51.78Z"/>
|
||||
<ellipse class="cls-3" cx="19.15" cy="52.07" rx="0.57" ry="0.82"/>
|
||||
<path class="cls-3" d="M19.15,53.38a1.34,1.34,0,0,1,0-2.61,1.34,1.34,0,0,1,0,2.61Zm0-1.6a.53.53,0,0,0-.08.29.47.47,0,0,0,.1.33s0-.14,0-.33A.53.53,0,0,0,19.15,51.78Z"/>
|
||||
<ellipse class="cls-3" cx="24.59" cy="52.07" rx="0.57" ry="0.82"/>
|
||||
<path class="cls-3" d="M24.59,53.38a1.34,1.34,0,0,1,0-2.61,1.34,1.34,0,0,1,0,2.61Zm0-1.6a.54.54,0,0,0-.08.29.47.47,0,0,0,.1.33s0-.14,0-.33A.53.53,0,0,0,24.59,51.78Z"/>
|
||||
<ellipse class="cls-3" cx="30.05" cy="52.07" rx="0.57" ry="0.82"/>
|
||||
<path class="cls-3" d="M30.05,53.38a1.34,1.34,0,1,1,1.06-1.31A1.19,1.19,0,0,1,30.05,53.38Zm0-1.6a.53.53,0,0,0-.08.29.47.47,0,0,0,.1.33s0-.14,0-.33A.53.53,0,0,0,30.05,51.78Z"/>
|
||||
<ellipse class="cls-3" cx="35.49" cy="52.07" rx="0.57" ry="0.82"/>
|
||||
<path class="cls-3" d="M35.49,53.38a1.34,1.34,0,1,1,1.06-1.31A1.19,1.19,0,0,1,35.49,53.38Zm0-1.6a.53.53,0,0,0-.08.29.47.47,0,0,0,.1.33s0-.14,0-.33A.54.54,0,0,0,35.49,51.78Z"/>
|
||||
<ellipse class="cls-3" cx="41" cy="52.07" rx="0.57" ry="0.82"/>
|
||||
<path class="cls-3" d="M41,53.38a1.34,1.34,0,1,1,1.06-1.31A1.19,1.19,0,0,1,41,53.38Zm0-1.6a.53.53,0,0,0-.08.29.47.47,0,0,0,.1.33s0-.14,0-.33A.53.53,0,0,0,41,51.78Z"/>
|
||||
<ellipse class="cls-3" cx="46.21" cy="52.07" rx="0.57" ry="0.82"/>
|
||||
<path class="cls-3" d="M46.21,53.38a1.34,1.34,0,1,1,1.06-1.31A1.19,1.19,0,0,1,46.21,53.38Zm0-1.6a.53.53,0,0,0-.08.29.47.47,0,0,0,.1.33s0-.14,0-.33A.53.53,0,0,0,46.21,51.78Z"/>
|
||||
<circle class="cls-3" cx="73.17" cy="26.91" r="1.75"/>
|
||||
<path class="cls-3" d="M73.17,28.91a2,2,0,1,1,2-2A2,2,0,0,1,73.17,28.91Zm0-3.51a1.51,1.51,0,1,0,1.51,1.51A1.51,1.51,0,0,0,73.17,25.4Z"/>
|
||||
<path class="cls-3" d="M226.19,24.76a.49.49,0,0,0-.44-.49h-17a.5.5,0,0,0,0,1h17A.49.49,0,0,0,226.19,24.76Z"/>
|
||||
<path class="cls-3" d="M316,75.2l0-5.78-5,.07V64.55h-6.5L288.34,46.06l15.12,3,.4-2-29-5.73-.4,2,1.66.32-1.36,19,.32,0-.07.1.07,0-1.33-.12-.17,1.68,1.56.12h-5l1.56-.12-.17-1.71-1.11.12,0,0,0-.1.32,0-1.38-19.08,1.71-.35-.4-2L241.54,47l.4,2,15.15-3L240.55,64.94,235,64.6c0-.15,1-3.51-1.21-5.49h-1s-7.17-9.39-7.17-18H226V38.6h-.49V28.72h2.84l-2.13,4.42.67.49,2.59-5.41h-4v-2h1.61a1.39,1.39,0,0,0,.77-1.36,1.47,1.47,0,0,0-.77-1.36h-1.58l-7.73-8.4h-1l-7.73,8.4h-1.58a1.43,1.43,0,0,0-.77,1.36,1.39,1.39,0,0,0,.77,1.36H209v2h-3.68l2.94,6.15L209,34v4.62h-.49V41H209c0,6.92-4.57,14.33-6.43,17.05H161V36.55h0V33.39h0v-4h0V26.27h0V24a1.57,1.57,0,0,0,1.26-.89,1.53,1.53,0,0,0-.77-2.05,1.43,1.43,0,0,0-.52-.15V19.55h-.49V21a2,2,0,0,0-1.09.86,1.53,1.53,0,0,0,.72,2.05,3.07,3.07,0,0,1,.37.12V58.1h-4.2V33.63h1V32.4h-2.87l-3.19-12-1.66-6.3h-.47V9.93h-2.2v4.2h-.52l-1.66,6.3-3.16,12h-3.46c-5.78-4-5.86-14.33-5.86-14.33h-8.72c-.22,9.64-4.62,13.59-6.18,14.33h-.84V25h-1.24V20.56h-2V17.35h-2V13.89H109.1V7H105.4v6.92h-2.47v3.46h-2v3.21H99.22V25H98V19.08H95.29l-2.52-4.52L90,9.71l-2.74,4.87-2.52,4.5H81.4V30.94h-2V30h-.59l-2.57-8.77,1.68-6.3H68l1.68,6.25L67.12,30H66.06v1H63.83v-10a2.9,2.9,0,0,0,1.24.15V19.84s-3.46.17-3.46-5V6H53.23v8.87c0,5.16-3.71,5-3.71,5v1.24a3.34,3.34,0,0,0,1-.07V57.38H47.05V53.82a.75.75,0,0,0-1.48,0v3.56h-4V53.82c0-.25,0-.47-.25-.57V34.67h.84c.17,0,.15-.27.15-.42v-.17c0-.17,0-.15-.15-.15h-.35a1.39,1.39,0,0,0,0-.35V32a.93.93,0,0,0-.49-.72V29.75a2,2,0,0,1,4,0v5c-.74.22-1.14,1.21-1.36,2.2h-.17a.37.37,0,0,0,0,.74h.49a1.69,1.69,0,0,0,1.46,1.19,1.72,1.72,0,0,0,1.46-1.19h.47a.37.37,0,0,0,0-.74h-.12c-.22-1-.74-2.05-1.73-2.22V29.75a2.32,2.32,0,0,0-2.35-2.47h0a2.69,2.69,0,0,0-2.64,2,2.78,2.78,0,0,0-2.64-2.1h0a2.62,2.62,0,0,0-2.47,2.57v5a3.44,3.44,0,0,0-1.26,2.2h-.17a.37.37,0,0,0,0,.74h.49a1.69,1.69,0,0,0,1.46,1.19,1.72,1.72,0,0,0,1.46-1.19h.47a.37.37,0,1,0,0-.74H38c-.22-1-.84-2.05-1.58-2.22V29.75a1.85,1.85,0,1,1,3.71,0v1.51a1,1,0,0,0-.49.77V34h0c-.2,0-.52,0-.52.15v.17c0,.17.17.42.59.42h.4V57.43h-4V53.87a.62.62,0,1,0-1.24,0v3.56h-4.2V53.87c0-.37,0-.4-.4-.4h0c-.37,0-.82,0-.82.4v3.56h-4.2V53.87a.62.62,0,1,0-1.24,0v3.56h-4.2V53.87a.75.75,0,0,0-1.48,0v3.56h-4.2V53.87a.62.62,0,1,0-1.24,0v3.56H9V53.87c0-.37,0-.4-.4-.4h0c-.37,0-1.09,0-1.09.4v3.56h-1v1h1v1.24H7V69.79H3.53v5.68H0v1.24H161.2V75.47h-1V72s5.16-8.48,19.13-8.2,18.19,8.35,18.19,8.35v3.26h-1.24v1.24l11.19,0H320V75.22l-4,0ZM161,21.33a.85.85,0,0,1,.37.1,1.19,1.19,0,0,1,.57,1.58,1.07,1.07,0,0,1-.94.67Zm-141.11,37h4.2v1.24h-4.2Zm-5.68,0h4.2v1.24h-4.2ZM9,58.37h4v1.24H9ZM24.34,69.74H11.74v-.86c0-2.89,2.72-4.82,5.58-4.82h2.15a4.61,4.61,0,0,1,4.87,4.82v.86Zm6.43-11.37H35v1.24h-4.2Zm-5.44,0h4.2v1.24h-4.2ZM39.91,69.74H27.31v-.86c0-2.89,2.74-5.07,5.63-5.07h2.15a4.77,4.77,0,0,1,4.82,5.07Zm.25-10.13h-4V58.37h4Zm1.48-1.24h4v1.24h-4Zm8.9,11.37H42.88v-.86c0-2.89,2.77-4.82,5.66-4.82h2Zm0-10.13H47.08V58.37h3.46Zm3.71,7.17H52.76V58.86h1.48Zm0-9.14H52.76V50h1.48Zm0-8.9H52.76V40.58h1.48Zm0-9.14H52.76V31.68h1.48Zm0-8.9H52.76V22.54h1.48Zm5.68,36.08h-4.7v-8.4h4.7Zm0-9.14h-4.7V49.72h4.7Zm0-8.9h-4.7V40.58h4.7Zm0-9.14h-4.7V31.68h4.7Zm0-8.9h-4.7V22.54h4.7ZM57.21,15.37v3.46h-.49V15.37Zm-.49-.25V11.91h.49v3.21Zm1.48.25v3.46H57.7V15.37Zm-.49-.25V11.91h.49v3.21Zm4.2,51.65H60.67V58.86H61.9Zm0-9.14H60.67V50H61.9Zm0-8.9H60.67V40.58H61.9Zm0-9.14H60.67V31.68H61.9Zm0-8.9H60.67V22.54H61.9Zm-1.73-9.88V19.08H58.69V11.42H56.22v7.66H55v1.73H51.48C54.27,19.57,54.24,15,54.24,15V7.22h6.4V15s.07,4.6,2.84,5.83Zm10.6.49.1-.42-.07-.27-1.31-4.77h7.12L75.3,20.61l-.07.25.1.52L77.79,30H68.33Zm1.26,23V35.54A1.14,1.14,0,0,1,73.3,34.4h.2a1.14,1.14,0,0,1,1.26,1.16v8.72Zm2.72,4.84v8.75H72V49.1A1.12,1.12,0,0,1,73.3,48h.2A1.14,1.14,0,0,1,74.75,49.13Zm-5.44,8.75H66.6V49.1c0-.72.72-1.11,1.43-1.11h.2a1,1,0,0,1,1.09,1.14v8.75Zm0-13.59H66.6V35.54A1.29,1.29,0,0,1,68,34.4h.2a1,1,0,0,1,1.09,1.16v8.72ZM75.5,70.73H70.8V62.35a2.27,2.27,0,0,1,2.37-2h.32a2,2,0,0,1,2,2.05v8.33Zm4.45-12.85H77.23V49.1A1.18,1.18,0,0,1,78.56,48h.2a1.07,1.07,0,0,1,1.19,1.14v8.75Zm0-13.59H77.23V35.54a1.2,1.2,0,0,1,1.33-1.14h.2a1.08,1.08,0,0,1,1.19,1.16v8.72Zm7.91-28.17h4.2v4.7h-4.2Zm-3.46,6.18H96v1H84.39Zm9.64,22V38.6h2v5.68ZM96,51v5.93H94V51ZM94,31.68V26h2v5.68ZM92.79,28v4.94H87.36V28Zm-5.44-.49v-.84A2.44,2.44,0,0,1,90,24.27h.27a2.42,2.42,0,0,1,2.57,2.37v.84Zm2.57,9.14h.27a2.52,2.52,0,0,1,2.57,2.5v1H87.33v-1A2.56,2.56,0,0,1,89.93,36.62Zm2.87,4v4.94H87.36V40.58Zm-2.87,8.65h.27a2.43,2.43,0,0,1,2.57,2.4v.82H87.33v-.82A2.48,2.48,0,0,1,89.93,49.23Zm2.87,3.71v4.94H87.36V52.93Zm0,7.66v6.92H87.36V60.59ZM94,68v1.48H86.12V68ZM84.39,26h2v5.68h-2Zm0,12.6h2v5.68h-2Zm0,12.36h2v5.93h-2Zm0,19.28H95.76v1.48H84.39Zm13.34,4.45H82.17v-2H97.74ZM103.42,66H101.2V62.57h2.22Zm0-4H101.2V58.37h2.22Zm0-9.39H101.2V49.23h2.22Zm0-4H101.2V45h2.22Zm0-5.19H101.2V39.84h2.22Zm0-4.2H101.2V35.88h2.22Zm0-4.94H101.2V30.69h2.22Zm0-4H101.2V26.74h2.22ZM105.89,66h-1.73V62.57h1.73Zm0-4h-1.73V58.37h1.73Zm0-9.39h-1.73V49.23h1.73Zm0-4h-1.73V45h1.73Zm0-5.19h-1.73V39.84h1.73Zm0-4.2h-1.73V35.88h1.73Zm0-4.94h-1.73V30.69h1.73ZLine truncated
|
||||
<path class="cls-3" d="M215.62,33v4.82h3.46V33a1.75,1.75,0,0,0-3.46,0Zm3,.4v3.44h-2.47V33.44a1.26,1.26,0,0,1,1.24-1.31A1.27,1.27,0,0,1,218.58,33.44Z"/>
|
||||
<rect class="cls-3" x="55.73" y="45.03" width="3.71" height="3.21"/>
|
||||
<rect class="cls-3" x="55.73" y="35.88" width="3.71" height="3.21"/>
|
||||
<rect class="cls-3" x="55.73" y="32.18" width="3.71" height="3.21"/>
|
||||
<rect class="cls-3" x="55.73" y="23.28" width="3.71" height="2.97"/>
|
||||
<rect class="cls-3" x="55.73" y="41.07" width="3.71" height="3.21"/>
|
||||
<rect class="cls-3" x="55.73" y="59.11" width="3.71" height="3.21"/>
|
||||
<path class="cls-3" d="M128.18,70.68a1.28,1.28,0,0,1,.35-.52.82.82,0,0,0,0-.27l-.37-1.43h0v0h0l0,0h0a3.08,3.08,0,0,0-1.68,2.45c.37,0,.77,0,1.11,0A2.41,2.41,0,0,0,128.18,70.68Z"/>
|
||||
<path class="cls-3" d="M129.86,71.1a.47.47,0,0,0-.47-.47h-.07a.81.81,0,0,1-.37.62.49.49,0,0,0,.44.3A.45.45,0,0,0,129.86,71.1Z"/>
|
||||
<rect class="cls-3" x="89.83" y="17.1" width="1.73" height="1.24"/>
|
||||
<path class="cls-3" d="M127.86,67.51l-.15-.59a5.54,5.54,0,0,0-.86.59L126,68.68l-1.53,2.13c.22,0,.57,0,1,0A3.89,3.89,0,0,1,127.86,67.51Z"/>
|
||||
<rect class="cls-3" x="88.35" y="18.83" width="1.24" height="1.48"/>
|
||||
<rect class="cls-3" x="88.35" y="17.1" width="1.24" height="1.24"/>
|
||||
<rect class="cls-3" x="89.83" y="18.83" width="1.73" height="1.48"/>
|
||||
<path class="cls-3" d="M118.17,70.5a.82.82,0,0,1,.27.64.86.86,0,0,1-1.73,0,.85.85,0,0,1,.69-.84l.67-2.15a3.35,3.35,0,0,0-.49,0,3,3,0,1,0,3,3,3,3,0,0,0-1.78-2.74Z"/>
|
||||
<path class="cls-3" d="M129.37,68.11a4.8,4.8,0,0,0-.59,0l.35,1.31a1.6,1.6,0,0,1,.1.32l.17,0a1.31,1.31,0,1,1-1.26,1.66l-1.8,0a3,3,0,0,0,6-.27A3,3,0,0,0,129.37,68.11Z"/>
|
||||
<polygon class="cls-3" points="127.05 66.03 127.05 66.03 123.56 66.03 120.08 66.03 121.71 68.28 123.56 70.85 125.44 68.28 127.05 66.03"/>
|
||||
<rect class="cls-3" x="55.73" y="26.74" width="3.71" height="3.46"/>
|
||||
<rect class="cls-3" x="55.73" y="54.17" width="3.71" height="2.97"/>
|
||||
<rect class="cls-3" x="55.73" y="50.22" width="3.71" height="2.97"/>
|
||||
<rect class="cls-3" x="55.73" y="63.07" width="3.71" height="2.97"/>
|
||||
<path class="cls-3" d="M214.5,17.32,197.16,0,195.1,2.05l0,0-1.41,1.38L211,20.73l1.41-1.41,0,0ZM197.16,1.53l.52.52-.52.52-.52-.52Zm-.64.4L196,1.41l.52-.52.52.52Zm15.91,15.89-.52-.52.52-.52.52.52Zm.64-.4.52.52-.52.52-.52-.52Zm-1.8.52.52-.52.52.52-.52.52Zm-.15-1.43-.57-.57.52-.52.57.57Zm.64-.4.52.52-.52.52-.52-.52Zm-1.33-.3-.52-.52.52-.52.52.52Zm-.64-.64-.52-.52.52-.52.52.52Zm-.67-.67L208.6,14l.52-.52.52.52Zm-.64-.64-.52-.52.52-.52.52.52Zm-.67-.67-.57-.57.52-.52.57.57Zm-.69-.69L206.6,12l.52-.52.52.52Zm-.64-.64-.52-.52.52-.52.52.52Zm-.67-.67-.52-.52.52-.52.52.52Zm-.64-.64-.57-.57.52-.52.57.57Zm-.69-.69L204,9.34l.52-.52.52.52Zm-.67-.67-.52-.52.52-.52.52.52Zm-.67-.64L202.62,8l.52-.52.52.52Zm-.64-.67L202,7.36l.52-.52.52.52Zm-.67-.64-.57-.57.52-.52.57.57Zm-.69-.69L200.61,6l.52-.52.52.52Zm-.64-.67L200,5.36l.52-.52.52.52Zm-.67-.64-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.67-.64-.57-.57.52-.52.57.57Zm-.69-.69-.52-.52.52-.52.52.52Zm-.12.12-.52.52-.52-.52.52-.52Zm.12.12.57.57-.52.52L197.3,4Zm.69.69.52.52-.52.52L198,4.7Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52L199.3,6Zm.67.64.52.52-.52.52L200,6.65Zm.64.67.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52L201.31,8Zm.67.64.52.52-.52.52L202,8.65Zm.64.67.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.67.67.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.64.64.52.52-.52.52-.52-.52Zm.67.67.52.52-.52.52-.52-.52Zm.64.64.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.67.67.52.52-.52.52-.52-.52Zm.64.64.52.52-.52.52-.52-.52Zm.67.67.52.52-.52.52-.52-.52Zm.64.64.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm1.43-.1.52-.52.52.52-.52.52Zm-.12-.12-.52-.52.52-.52.52.52Zm-.67-.67-.57-.57.52-.52.57.57Zm-.69-.69-.52-.52.52-.52.52.52Zm-.64-.64-.52-.52.52-.52.52.52Zm-.67-.67-.52-.52.52-.52.52.52Zm-.64-.64-.52-.52.52-.52.52.52Zm-.67-.67-.57-.57.52-.52L209,12Zm-.69-.69-.52-.52.52-.52.52.52Zm-.64-.64-.52-.52.49-.54.52.52Zm-.67-.67-.52-.52.52-.52L207,10Zm-.64-.64-.57-.57.52-.52.57.57Zm-.69-.69-.52-.52.52-.52.52.52Zm-.67-.67L203.93,8l.52-.52L205,8Zm-.64-.64-.52-.52.52-.52.52.52Zm-.67-.67-.52-.52.52-.52.52.52Zm-.67-.64L201.9,6l.52-.52.57.57Zm-.67-.69-.52-.52.52-.52.52.52Zm-.67-.67-.52-.52.52-.52.52.52Zm-.67-.64-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.67-.64-.57-.57.52-.52.57.57Zm-.69-.69-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.77.77-.52.52L196,2.69l.52-.52Zm14.85,15.89.52-.52.52.52-.52.52Zm1.83-.74-.52-.52.52-.52.52.52ZM197.16.22l.52.52-.52.52-.52-.52Zm-1.29,1.31.52.52-.52.52-.52-.52Z"/>
|
||||
<path class="cls-3" d="M211.24,30.27l-2.05-2.05L191.87,45.57l2.05,2.05,0,0L195.38,49l17.25-17.25-1.41-1.41Zm-1.56,0-.52.52-.52-.52.52-.52Zm-.4-.67.52-.52.52.52-.52.52ZM194.56,46.71l-.52-.52.52-.52.52.52Zm.67-.64-.52-.52.52-.52.52.52Zm13.15-14.46-.57.57-.52-.52.57-.57ZM208,31l.52-.52L209,31l-.52.52Zm-.3,1.33-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.57.57L204,35l.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.57.57-.52-.52.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.57.57-.52-.52.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.57.57-.52-.52.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm.77.52-.52-.52.57-.57.52.52Zm.69-.69-.52-.52.52-.52.52.52Zm.67-.64-.52-.52.52-.52.52.52Zm.64-.67-.52-.52.52-.52.52.52Zm.67-.64-.52-.52.52-.52.52.52Zm.64-.67-.52-.52.57-.57.52.52Zm.69-.69-.52-.52.52-.52.52.52Zm.64-.64-.52-.52.52-.52.52.52Zm.67-.67-.52-.52.52-.52.52.52Zm.64-.64-.52-.52.52-.52.52.52Zm.67-.67-.52-.52.57-.57.52.52Zm.69-.69-.52-.52.52-.52.52.52Zm.64-.64-.52-.52.52-.52.52.52Zm.67-.67-.52-.52.52-.52.52.52Zm.64-.64-.52-.52.57-.57.52.52Zm.69-.69-.52-.52.52-.52.52.52Zm.67-.67-.52-.52.52-.52.52.52Zm.64-.64-.52-.52.52-.52.52.52Zm.67-.67-.52-.52.52-.52.52.52Zm.64-.64-.52-.52.57-.57.52.52Zm.69-.69-.52-.52.52-.52.52.52Zm.67-.67-.52-.52.52-.52.52.52Zm-1.29-1.29-.52-.52.52-.52.52.52Zm-.12.12-.52.52-.52-.52.52-.52Zm-.67.67-.57.57-.52-.52.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.57.57-.52-.52.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.57.57-.52-.52.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.57.57-.52-.52.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm-.64.64-.57.57-.52-.52.57-.57Zm-.69.69-.52.52-.52-.52.52-.52Zm-.67.67-.52.52-.52-.52.52-.52Zm.12.12.52.52-.52.52-.52-.52Zm-.12,1.16-.54.54-.52-.52.52-.52Zm.12.15.52.52-.52.52-.52-.52Zm16.53-15.52-.52-.52.52-.52.52.52Zm-1.26-2.35.52.52-.52.52-.52-.52ZM192.63,45l.52.52-.52.52-.52-.52Z"/>
|
||||
<path class="cls-3" d="M223.05,20l2.05,2.05L242.43,4.74l-2.05-2.05,0,0-1.41-1.41L221.67,18.58,223.08,20Zm1.56,0,.52-.52.52.52-.52.52Zm.4.64-.52.52-.52-.52.52-.52ZM239.73,3.61l.52.52-.52.52-.52-.52Zm-.67.64.52.52-.52.52-.52-.52ZM225.92,18.73l.57-.57.52.52-.57.57Zm.4.64-.52.52-.52-.52.52-.52Zm.3-1.33.52-.52.52.52-.52.52Zm.64-.67.52-.52.52.52-.52.52Zm.67-.64.52-.52.52.52-.52.52Zm.64-.67.52-.52.52.52-.52.52Zm.67-.67.57-.57.52.52-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm.64-.64.52-.52.52.52-.52.52Zm.67-.67.52-.52.52.52-.52.52Zm.64-.64.57-.57.52.52-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm.64-.67.52-.52.54.52-.52.52Zm.67-.64.52-.52.52.52-.52.52Zm.64-.67.52-.52.52.52-.52.52Zm.67-.64.57-.57.52.52-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm.64-.67.52-.52.52.52L237,8.6Zm.67-.64.52-.52.52.52-.52.52Zm.64-.67.52-.52.52.52-.52.52Zm.67-.64.57-.57.52.52-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm-.77-.52.52.52-.57.57-.52-.52Zm-.69.69.52.52-.52.52-.52-.52Zm-.67.64.52.52-.52.52-.52-.52Zm-.64.67.52.52-.52.52-.52-.52Zm-.67.64.52.52-.52.52-.52-.52Zm-.64.67.52.52-.57.57-.52-.52Zm-.69.69.52.52-.52.52-.52-.52Zm-.67.64.52.52-.52.52-.52-.52Zm-.64.67.52.52-.52.52-.52-.52Zm-.67.64.52.52-.52.52-.52-.52Zm-.64.67.52.52-.57.57-.52-.52Zm-.69.69.52.52-.52.52-.52-.52Zm-.67.64.52.52-.52.52-.52-.52Zm-.64.67.52.52-.52.52-.52-.52Zm-.67.67.52.52-.57.57-.52-.52Zm-.69.69.52.52-.52.52-.52-.52Zm-.64.64.52.52-.52.52-.52-.52Zm-.67.67.52.52-.52.52-.52-.52Zm-.64.64.52.52-.52.52-.52-.52Zm-.67.67.52.52-.57.57-.52-.52Zm-.69.69.52.52-.52.52-.52-.52Zm-.64.64.52.52-.52.52-.52-.52Zm1.29,1.29.52.52-.52.52-.52-.52Zm.12-.12.52-.52.52.52-.52.52Zm.67-.64.57-.57.52.52-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm.64-.67.52-.52.52.52-.52.52Zm.67-.64.52-.54.52.52-.52.52Zm.64-.67.52-.52.52.52-.52.52Zm.67-.64.57-.57L231,16l-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm.64-.67.52-.52.52.52-.52.52Zm.67-.64.52-.52.52.52-.52.52Zm.64-.67.57-.57.52.52-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm.67-.67.52-.52.52.52-.52.52Zm.64-.64.52-.52.52.52-.52.52Zm.67-.67.52-.52.52.52-.52.52Zm.64-.64.57-.57.52.52-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm.67-.67.52-.52.52.52-.52.52Zm.64-.64.52-.52.52.52-.52.52Zm.67-.67.52-.52.52.52-.52.52Zm.64-.64.57-.57.52.52-.57.57Zm.69-.69.52-.52.52.52-.52.52Zm.64-.67.52-.52.52.52-.52.52Zm-.12-.12-.52-.52.52-.52.52.52Zm.15-1.16.52-.52.52.52-.52.52ZM240.38,4l-.52-.52.52-.52.52.52ZM223.82,19.52l.52.52-.52.52L223.3,20Zm1.29,2.32-.52-.52.52-.52.52.52ZM241.66,5.29l-.52-.52.52-.52.52.52Z"/>
|
||||
<path class="cls-3" d="M223.89,30.22l-1.41,1.41,0,0-2.05,2.05L237.73,51l2.05-2.05,0,0,1.41-1.41Zm13.81,19.23-.52-.52.52-.52.52.52Zm.64-.4.52.52-.52.52-.52-.52Zm-14.58-14.6.57.57-.52.52-.57-.57Zm-.64.4-.52-.52.52-.52.52.52Zm1.33.3.52.52-.52.52-.52-.52Zm.64.67.52.52-.49.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52-.52-.52Zm.67.64.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.12-.12.52-.52.52.52-.52.52Zm-.12-.15-.57-.57.52-.52.57.57Zm-.69-.67-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52ZM235,45.5l-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.67-.64-.57-.57.52-.52.57.57Zm-.69-.69-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.67-.64-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.67-.64-.57-.57.52-.52.57.57Zm-.69-.69-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.67-.64-.52-.52.52-.52.52.52Zm-.64-.67-.57-.57.52-.52.57.57Zm-.69-.69-.52-.52.52-.52.52.52Zm-.67-.64-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.67-.64-.52-.52.52-.52.52.52Zm-.64-.67-.57-.57.52-.52.57.57Zm-.69-.69-.52-.52.52-.52.52.52Zm-.67-.64-.52-.52.52-.52.52.52Zm-.64-.67-.52-.52.52-.52.52.52Zm-.15.12-.52.52-.52-.52.52-.52Zm.15.12.52.52-.52.52-.52-.52Zm-.12,1.19-.52.52-.52-.52.52-.52Zm.12.12L223,35l-.52.52-.52-.52Zm.67.64.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.64.67L225,37l-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52-.52-.52Zm.67.64L227,39l-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67L233,45l-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.64.67.57.57-.52.52-.57-.57Zm.69.69.52.52-.52.52-.52-.52Zm.67.64.52.52-.52.52-.52-.52Zm.77-.77.52-.52.52.52-.52.52ZM221.15,33.14l.52.52-.52.52-.52-.52Zm16.58,17.6-.52-.52.52-.52.52.52ZM239,49.45l-.52-.52.52-.52.52.52Z"/>
|
||||
<path class="cls-3" d="M128.87,22.17h-1.36s0,4.28-2.22,6.38v2.77H131V28.54C129,26.47,128.87,22.17,128.87,22.17Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 24 KiB |
@@ -1,5 +1,5 @@
|
||||
(ns skirmish.rest.bookkeeper
|
||||
(:require [skirmish.exchange.exchange :refer [empty-book create-exchange-for-security]]
|
||||
(ns skirmish.bookkeeper.bookkeeper
|
||||
(:require [skirmish.exchange.exchange :refer [empty-book]]
|
||||
[org.httpkit.server :refer [run-server with-channel send! close on-close]]
|
||||
[compojure.route :refer [not-found]]
|
||||
[compojure.handler :refer [api]]
|
||||
@@ -7,17 +7,20 @@
|
||||
[skirmish.order] ;; for spec side effect
|
||||
[skirmish.rest.util :refer [build-response build-response-body]]
|
||||
[clojure.spec.alpha :as s]
|
||||
[kinsky.client]
|
||||
[slingshot.slingshot :refer [try+ throw+]]
|
||||
[clojure.core.async :refer [chan go-loop close! <! sub]]))
|
||||
|
||||
|
||||
(def order-id (atom -1))
|
||||
|
||||
(defn endpoint [name description path]
|
||||
{:name name :description description :url path})
|
||||
|
||||
(def endpoints [(endpoint "securities" "list all securities." "/api/1/securities")])
|
||||
|
||||
|
||||
(defn api-description [req]
|
||||
(let [body {"/api/1/securities" "list all securities."
|
||||
"/api/1/book" "For all information about the book."}]
|
||||
(let [body endpoints]
|
||||
(build-response req body)))
|
||||
|
||||
(defn subscribe-to-orders-publisher [exchange-api status-to-listen-on]
|
||||
@@ -42,9 +45,9 @@
|
||||
ret))
|
||||
|
||||
|
||||
(defn securities [exchange-apis]
|
||||
(defn securities [exchange-apis config]
|
||||
(fn [request]
|
||||
(build-response request {:securities (keys exchange-apis)})))
|
||||
(build-response request {:securities (:securities config)})))
|
||||
|
||||
|
||||
(defn get-security [exchange-apis]
|
||||
@@ -70,14 +73,14 @@
|
||||
(fn [{{sec-id-str :sec-id} :route-params :as request}]
|
||||
(with-channel request ws-chan
|
||||
(let [status-to-listen-on (get-status-to-listen-on request)
|
||||
order-channel (get-new-order-channel exchange-apis (keyword sec-id-str) status-to-listen-on)]
|
||||
order-channel (get-new-order-channel @exchange-apis (keyword sec-id-str) status-to-listen-on)]
|
||||
(chan-to-websocket request order-channel ws-chan)))))
|
||||
|
||||
|
||||
(defn listen-to-trades [exchange-apis]
|
||||
(fn [{{sec-id-str :sec-id} :route-params :as request}]
|
||||
(with-channel request ws-chan
|
||||
(let [order-channel (get-new-trades-channel exchange-apis (keyword sec-id-str))]
|
||||
(let [order-channel (get-new-trades-channel @exchange-apis (keyword sec-id-str))]
|
||||
(chan-to-websocket request order-channel ws-chan)))))
|
||||
|
||||
|
||||
@@ -87,7 +90,6 @@
|
||||
(go-loop [order (<! new-book-order-channel)]
|
||||
(let [order-id (:book.order/id order)
|
||||
to-remove (contains? #{:withdrawn :totally-fulfilled} (:book.order/status order))]
|
||||
(println ret)
|
||||
(swap! ret (fn [book]
|
||||
(if to-remove
|
||||
(dissoc book order-id)
|
||||
@@ -98,21 +100,20 @@
|
||||
(defn map-values [f m]
|
||||
(into {} (for [[k v] m] [k (f v)])))
|
||||
|
||||
(defn get-books [exchange-apis]
|
||||
(let [books (map-values #(create-book %) exchange-apis)]
|
||||
(fn [{{sec-id-str :sec-id} :route-params body :body :as request}]
|
||||
(let [sec-id (keyword sec-id-str)]
|
||||
(build-response request @(get books sec-id))))))
|
||||
(defn get-books [exchange-apis books]
|
||||
(fn [{{sec-id-str :sec-id} :route-params body :body :as request}]
|
||||
(let [sec-id (keyword sec-id-str)]
|
||||
(build-response request @(get books sec-id)))))
|
||||
|
||||
|
||||
(defn create-routes-for-bookkeeper [exchange-apis]
|
||||
(let [get-book (get-books exchange-apis)]
|
||||
(defn create-routes-for-bookkeeper [exchange-apis config]
|
||||
(let [books (map-values #(create-book %) @exchange-apis)]
|
||||
(routes
|
||||
(context "/api/1" []
|
||||
(GET "/" [] api-description)
|
||||
(GET "/securities" [] (securities exchange-apis))
|
||||
(GET "/securities" [] (securities exchange-apis config))
|
||||
(GET "/securities/:sec-id" [] (get-security exchange-apis))
|
||||
(GET "/securities/:sec-id/trades" [] (listen-to-trades exchange-apis))
|
||||
(GET "/securities/:sec-id/orders" [] (listen-to-orders exchange-apis))
|
||||
(GET "/securities/:sec-id/book" [] get-book))
|
||||
(GET "/securities/:sec-id/book" [] (get-books exchange-apis books)))
|
||||
(not-found "not found"))))
|
||||
@@ -0,0 +1,20 @@
|
||||
; This is the service that broadcast market data to the
|
||||
; world. The users need to expect websocket and REST api.
|
||||
|
||||
|
||||
(ns skirmish.bookkeeper.core
|
||||
(:require [org.httpkit.server :refer [run-server]]
|
||||
[compojure.handler :refer [api]]
|
||||
[taoensso.timbre :as timbre]
|
||||
[skirmish.middleware.core :refer [create-map-exchange-apis]]
|
||||
[skirmish.bookkeeper.bookkeeper :refer [create-routes-for-bookkeeper]]
|
||||
[skirmish.rest.util :refer [cors-middleware]]))
|
||||
|
||||
(defn -main [config securities-api exchange-apis-mult-chan]
|
||||
(let [bookkeeper-config (:api-bookkeeper config)
|
||||
exchange-apis (create-map-exchange-apis exchange-apis-mult-chan)
|
||||
api-routes (create-routes-for-bookkeeper exchange-apis config)]
|
||||
(timbre/info "Running skirmish.bookkeeper.core server with config: " bookkeeper-config)
|
||||
(run-server
|
||||
(-> api-routes api cors-middleware)
|
||||
bookkeeper-config)))
|
||||
@@ -0,0 +1,102 @@
|
||||
(ns skirmish.broker.broker
|
||||
(:require [compojure.core :refer :all]
|
||||
[compojure.route :refer [not-found]]
|
||||
[datomic.api :as d]
|
||||
[slingshot.slingshot :refer [try+ throw+]]
|
||||
[skirmish.rest.util :refer [build-response not-found-resp get-body]]
|
||||
[taoensso.timbre :as timbre]
|
||||
[skirmish.routes.core :as routes]
|
||||
[clj-http.client :as http-client]))
|
||||
|
||||
(defn generate-amount-for-new-user [seed]
|
||||
(let [random (new java.util.Random seed)
|
||||
random-fn #(. random nextInt 20000)]
|
||||
(* 100 (reduce + (take 100 (repeatedly random-fn))))))
|
||||
|
||||
(defn create-account [account-id sec-id]
|
||||
#:skirmish.broker.account{:id account-id
|
||||
:sec-id sec-id
|
||||
:private-key (str account-id)})
|
||||
|
||||
(defn create-user-account [seed default-sec-id]
|
||||
(let [url (routes/get-path-for :ledger/security {:sec-id (name default-sec-id)})
|
||||
account-id (java.util.UUID/randomUUID)
|
||||
amount (generate-amount-for-new-user seed)
|
||||
payload [amount (str account-id)]]
|
||||
(timbre/info "Creating new account " account-id " with ammount " amount " of " default-sec-id)
|
||||
(timbre/info url)
|
||||
(http-client/post url {:body (str payload)})
|
||||
(create-account account-id default-sec-id)))
|
||||
|
||||
(defn create-user-seed-from-email [email]
|
||||
(let [hasher (java.security.MessageDigest/getInstance "SHA-256")
|
||||
salt (. "this should be private and set in config" getBytes "utf-8")
|
||||
msg (. email getBytes "utf-8")
|
||||
_ (doto hasher (.update salt) (.update msg))
|
||||
hash (. hasher digest)]
|
||||
(int (mod (new BigInteger 1 hash) (biginteger Integer/MAX_VALUE)))))
|
||||
|
||||
|
||||
(defn create-user [conn default-sec-id]
|
||||
(fn [{body :body :as request}]
|
||||
(try+
|
||||
(let [email (-> body get-body :email)
|
||||
_ (timbre/info "creating new user" email)
|
||||
seed (create-user-seed-from-email email)
|
||||
account (create-user-account seed default-sec-id)]
|
||||
@(d/transact conn [[:skirmish.broker.user/create-user email [account]]])
|
||||
(build-response request {:status 201 :headers {"location" (str "/api/1/users/" email)}}))
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
|
||||
(defn add-account-urls [user]
|
||||
(let [accounts (:skirmish.broker.user/accounts user)
|
||||
url #(->> % :skirmish.broker.account/id (str "http://localhost:1604/api/1/ledger/accounts/"))
|
||||
ret (map #(assoc % :skirmish.broker.account/url (url %)) accounts)]
|
||||
(assoc user :skirmish.broker.user/accounts ret)))
|
||||
|
||||
|
||||
(defn get-user [conn]
|
||||
(fn [{{email :email} :route-params :as request}]
|
||||
(try+
|
||||
(timbre/info "getting user with email" email)
|
||||
(let [db (d/db conn)
|
||||
users (d/q '[:find (pull ?e [:skirmish.broker.user/email
|
||||
{:skirmish.broker.user/accounts [:skirmish.broker.account/id
|
||||
:skirmish.broker.account/sec-id]}]) .
|
||||
:in $ ?email
|
||||
:where [?e :skirmish.broker.user/email ?email]] db email)]
|
||||
(if (nil? users)
|
||||
(build-response request {:status 404 :body {:error (str "cannot find user with email " email)}})
|
||||
(build-response request (add-account-urls users))))
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
|
||||
(defn get-all-users [conn]
|
||||
(fn [{{email :email} :route-params :as request}]
|
||||
(try+
|
||||
(timbre/info "getting user with email" email)
|
||||
(let [db (d/db conn)
|
||||
emails (d/q '[:find ?email
|
||||
:where [_ :skirmish.broker.user/email ?email]] db)
|
||||
xf (comp cat (map #(hash-map :email % :url (str "/api/1/users/" %))))]
|
||||
(build-response request
|
||||
{:users (doall (sequence xf emails))}))
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
|
||||
(defn get-account [conn]
|
||||
(fn [email account]))
|
||||
|
||||
|
||||
(defn create-routes [conn config]
|
||||
(routes
|
||||
(context "/api/1" []
|
||||
(POST "/users" [] (create-user conn (:default-sec-id config)))
|
||||
(GET "/users" [] (get-all-users conn))
|
||||
(GET "/users/:email" [email] (get-user conn))
|
||||
(GET "/users/:email/accounts/:account" [email account] (get-account conn)))
|
||||
not-found-resp))
|
||||
@@ -0,0 +1,20 @@
|
||||
; The backend of the skirmish web user interface.
|
||||
|
||||
(ns skirmish.broker.core
|
||||
(:require [org.httpkit.server :refer [run-server]]
|
||||
[compojure.handler :refer [api]]
|
||||
[skirmish.broker.broker :refer [create-routes]]
|
||||
[taoensso.timbre :as timbre]
|
||||
[skirmish.middleware.core :refer [create-map-exchange-apis]]
|
||||
[skirmish.broker.db :refer [create-connection]]
|
||||
[skirmish.rest.util :refer [cors-middleware]]))
|
||||
|
||||
|
||||
(defn -main [config securities-api exchange-apis]
|
||||
(let [webserver-config (:api-broker config)
|
||||
conn (create-connection (-> webserver-config :datomic :transactor-url))
|
||||
api-routes (create-routes conn webserver-config)]
|
||||
(timbre/info "Running skirmish.broker.core server with config: " webserver-config)
|
||||
(run-server
|
||||
(-> api-routes api cors-middleware)
|
||||
webserver-config)))
|
||||
@@ -0,0 +1,61 @@
|
||||
(ns skirmish.broker.db
|
||||
(:require [datomic.api :as d]
|
||||
[slingshot.slingshot :refer [throw+]]))
|
||||
|
||||
(def create-user
|
||||
[
|
||||
{:db/ident :skirmish.broker.user/create-user
|
||||
:db/doc "Create a new user in the system."
|
||||
:db/fn (d/function {:lang "clojure"
|
||||
:requires ['[slingshot.slingshot]]
|
||||
:params '[db email accounts]
|
||||
:code '(let [existing-user (d/pull db '[:db/id] [:skirmish.broker.user/email email])]
|
||||
(when (-> existing-user :db/id some?)
|
||||
(slingshot.slingshot/throw+ {:error-type :4XX :status 400 :body {:error "A user with this email already exists."}}))
|
||||
[#:skirmish.broker.user{:email email :accounts accounts}])})}])
|
||||
|
||||
|
||||
(def accounts-schema [
|
||||
{
|
||||
:db/ident :skirmish.broker.account/id
|
||||
:db/unique :db.unique/identity
|
||||
:db/valueType :db.type/uuid
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The id of an account."}
|
||||
{
|
||||
:db/ident :skirmish.broker.account/sec-id
|
||||
:db/valueType :db.type/keyword
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The security id of the account."}
|
||||
{
|
||||
:db/ident :skirmish.broker.account/private-key
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The private key of the account."}])
|
||||
|
||||
|
||||
(def user-schema [
|
||||
{
|
||||
:db/ident :skirmish.broker.user/email
|
||||
:db/unique :db.unique/identity
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The email of the user; used as id."}
|
||||
{
|
||||
:db/ident :skirmish.broker.user/accounts
|
||||
:db/valueType :db.type/ref
|
||||
:db/cardinality :db.cardinality/many
|
||||
:db/doc "The list of the accounts own by the user."}])
|
||||
|
||||
|
||||
(def schema (-> []
|
||||
(concat user-schema)
|
||||
(concat create-user)
|
||||
(concat accounts-schema)))
|
||||
|
||||
(defn create-connection [uri]
|
||||
(let [_ (d/create-database uri)
|
||||
conn (d/connect uri)]
|
||||
@(d/transact conn schema)
|
||||
conn))
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
(ns skirmish.cli.benchmark
|
||||
(:require [clojure.math.combinatorics :refer [cartesian-product]]
|
||||
[clojure.core.async :refer [go chan <! >! close! to-chan close!] :as async]
|
||||
[gniazdo.core :as ws]
|
||||
[clj-http.client :as client]
|
||||
[com.stuartsierra.frequencies :as freq]
|
||||
[clojure.edn :as edn]))
|
||||
|
||||
|
||||
(def ids (atom 0))
|
||||
|
||||
|
||||
(defn web-socket-to-channel [url output-ch]
|
||||
(let [on-receive #(go (>! output-ch %))
|
||||
headers {"accept" "application/edn"}]
|
||||
(ws/connect url :headers headers :on-receive on-receive)))
|
||||
|
||||
|
||||
(defn create-orders-channel [securities]
|
||||
(let [output (chan 1 (map edn/read-string))
|
||||
url #(format "ws://localhost:%s/api/1/securities/%s/orders" 8080 %)
|
||||
xf (comp (map :sec-id)
|
||||
(map name)
|
||||
(map url)
|
||||
(map #(web-socket-to-channel % output)))]
|
||||
(doall (sequence xf securities))
|
||||
(async/pub output :book.order/id)))
|
||||
|
||||
|
||||
|
||||
(defn create-requests-payload-for-security [i security id]
|
||||
(let [rd (new java.util.Random i)
|
||||
rand-bool (= (mod (. rd nextInt) 2) 0) ;; java random number generator REALLY sucks
|
||||
type (if rand-bool :sell :buy)
|
||||
price (+ (* 3 (. rd nextGaussian)) 30)
|
||||
int-price (int (* price 100))
|
||||
quantity (reduce + 1 (map #(. rd nextInt (inc %)) (range 100)))]
|
||||
|
||||
{:type type :quantity quantity :price int-price :security security :benchmark/id id}))
|
||||
|
||||
|
||||
(defn create-requests-for-security [[i security]]
|
||||
(let [req-id (swap! ids inc)
|
||||
payload (create-requests-payload-for-security i (str (:sec-id security)) req-id)
|
||||
sec-id-str (-> security :sec-id name)
|
||||
params {:throw-exceptions false :content-type :edn :headers {"accept" "application/edn"}}
|
||||
url (format "http://localhost:%s/api/1/securities/%s" 8080 sec-id-str)]
|
||||
(fn []
|
||||
(let [now (System/nanoTime)]
|
||||
(client/post url (assoc params :form-params (assoc payload :benchmark/request-time now)))))))
|
||||
|
||||
|
||||
(defn make-requests [n securities]
|
||||
(map create-requests-for-security (cartesian-product (range n) securities)))
|
||||
|
||||
|
||||
(defn no-more-then-n-simultaneously [f input-chan n]
|
||||
(let [buffer (chan)]
|
||||
(go (async/pipeline n buffer (map f) input-chan))
|
||||
buffer))
|
||||
|
||||
(defn decode-response [response]
|
||||
(let [now (System/nanoTime)
|
||||
ret {}
|
||||
ret (assoc ret :status (:status response))
|
||||
ret (assoc ret :order (edn/read-string (:body response)))
|
||||
ret (assoc ret :duration (/ (- now (get-in ret [:order :benchmark/request-time])) (Math/pow 10 9)))]
|
||||
ret))
|
||||
|
||||
|
||||
(defn benchmark [requests orders]
|
||||
(let [decoded-responses (chan 1 (map decode-response))
|
||||
responses (no-more-then-n-simultaneously #(%) (to-chan requests) 10)]
|
||||
(go (async/pipe responses decoded-responses))
|
||||
decoded-responses))
|
||||
|
||||
|
||||
(defn compute-result [results new-result]
|
||||
(let [status-code (:status new-result)
|
||||
duration (:duration new-result)
|
||||
old-status-code-count (get-in results [:status status-code] 0)
|
||||
ret results
|
||||
ret (assoc-in ret [:status status-code] (inc old-status-code-count))
|
||||
ret (assoc ret :durations (conj (:durations ret) duration))]
|
||||
ret))
|
||||
|
||||
(defn pp-durations [durations]
|
||||
(let [freq-map (frequencies durations)]
|
||||
(print (freq/stats freq-map))))
|
||||
|
||||
(defn display-results [results]
|
||||
(println results)
|
||||
(println "number of request: " (:n results))
|
||||
(println "status map: " (:status results))
|
||||
(pp-durations (:durations results)))
|
||||
|
||||
(defn -main [config exchange-apis]
|
||||
(let [benchmark-config (:benchmark config)
|
||||
requests (-> benchmark-config :number-of-requests-per-securities (make-requests (:securities config)))
|
||||
orders (create-orders-channel (:securities config))
|
||||
results (benchmark requests orders)]
|
||||
(display-results (async/<!! (async/reduce compute-result {} results)))))
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
(ns skirmish.cli.core)
|
||||
@@ -1,56 +0,0 @@
|
||||
(ns skirmish.cli.exchange
|
||||
(:require [skirmish.exchange.match :refer [sell?]]
|
||||
[skirmish.util :refer :all]
|
||||
[skirmish.exchange.exchange :refer [empty-book create-exchange-for-security]]
|
||||
[skirmish.order] ;; for spec side effect
|
||||
[slingshot.slingshot :refer [try+ throw+]]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.core.async :refer [chan go >!! <!!]]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
|
||||
(def incoming-order-channel (chan))
|
||||
|
||||
;(def trades-channel (chan))
|
||||
;
|
||||
;(def new-book-order-channel (chan))
|
||||
|
||||
(defn print-chan [prefix c]
|
||||
(loop [shit (<!! c)]
|
||||
(println prefix shit)
|
||||
(recur (<!! c))))
|
||||
|
||||
;(def master-book {:sell (create-sell-book)
|
||||
; :buy (create-buy-book)})
|
||||
|
||||
;;; repl things.
|
||||
(defn read-order []
|
||||
(try
|
||||
(print "$ ")
|
||||
(let [order (edn/read-string (read-line))
|
||||
valid? (s/valid? :book.order/order order)]
|
||||
(if valid? order nil))
|
||||
(catch Exception e nil)))
|
||||
|
||||
(def order-ids (atom -1))
|
||||
|
||||
|
||||
(defn add-id-to-order [order]
|
||||
(assoc order :book.order/id (swap! order-ids inc)))
|
||||
|
||||
|
||||
(defn -main [& args]
|
||||
(let [initial-book empty-book
|
||||
incoming-order-channel (chan)
|
||||
[trades-channel new-book-order-channel] (create-exchange-for-security initial-book incoming-order-channel)]
|
||||
(go (print-chan "trade > " trades-channel))
|
||||
(go (print-chan "order > " new-book-order-channel))
|
||||
(loop [order (read-order)]
|
||||
(if (some? order)
|
||||
(do
|
||||
(let [order-with-id (add-id-to-order order)]
|
||||
(>!! incoming-order-channel order-with-id)
|
||||
(println "\n\norder accepted with id: " (:book.order/id order-with-id))))
|
||||
|
||||
(println "invalid order"))
|
||||
(recur (read-order)))))
|
||||
+26
-20
@@ -1,37 +1,43 @@
|
||||
(ns skirmish.core
|
||||
(:require [skirmish.cli.core]
|
||||
[skirmish.rest.core]
|
||||
[skirmish.cli.benchmark]
|
||||
[skirmish.exchange.core]
|
||||
(:require [skirmish.exchange.core]
|
||||
[skirmish.wui.server]
|
||||
[skirmish.middleware.core :refer [create-exchange-apis-for]]
|
||||
[aero.core :refer (read-config)]
|
||||
[skirmish.bookkeeper.core]
|
||||
[skirmish.exchange-gateway.core]
|
||||
[skirmish.ledger.core]
|
||||
[taoensso.timbre :as timbre]
|
||||
[skirmish.broker.core]
|
||||
[skirmish.middleware.core :refer [create-exchange-apis-for
|
||||
create-securities-api-for]]
|
||||
[aero.core :refer [read-config]]
|
||||
[orchestra.spec.test :as st]
|
||||
[clojure.core.async :as async])
|
||||
(:gen-class))
|
||||
|
||||
(def targets ;; a target is a function that blocks the thread and takes two
|
||||
;; arguments: the config map and the "exchange-api"
|
||||
{:api-server skirmish.rest.core/api-main
|
||||
{:api-server skirmish.exchange-gateway.core/-main
|
||||
:exchange-core skirmish.exchange.core/-main ;; should be skirmish.exchange.core/api-main
|
||||
:api-bookkeeper skirmish.rest.core/bookkeeper-main
|
||||
:api-bookkeeper skirmish.bookkeeper.core/-main
|
||||
:ledger skirmish.ledger.core/-main
|
||||
:broker skirmish.broker.core/-main
|
||||
:wui skirmish.wui.server/-main})
|
||||
|
||||
(defn run-all-targets-in-separate-threads [target-fns config exchange-apis]
|
||||
(println "running multiple targets. This is okay in dev but horrible in production")
|
||||
(println target-fns)
|
||||
(let [threads (map #(async/thread (% config exchange-apis)) target-fns)
|
||||
(defn run-all-targets-in-separate-threads [target-fns config securities-api exchange-apis]
|
||||
(timbre/warn "running multiple targets. This is okay in dev but horrible in production")
|
||||
(timbre/info (clojure.string/join "\n" target-fns))
|
||||
(let [threads (map #(async/thread (% config securities-api exchange-apis)) target-fns)
|
||||
finished-threads (async/merge threads)]
|
||||
(loop [finished-thread (async/<!! finished-threads)]
|
||||
(when (some? finished-thread)
|
||||
(recur (async/<!! finished-threads))))))
|
||||
|
||||
|
||||
(defn run-all-targets [target-fns config]
|
||||
(let [exchange-apis (create-exchange-apis-for config)]
|
||||
(let [securities-api (create-securities-api-for config)
|
||||
exchange-apis (create-exchange-apis-for config securities-api)]
|
||||
(if (= (count target-fns) 1)
|
||||
((first target-fns) config exchange-apis)
|
||||
(run-all-targets-in-separate-threads target-fns config exchange-apis))))
|
||||
((first target-fns) config securities-api exchange-apis)
|
||||
(run-all-targets-in-separate-threads target-fns config securities-api exchange-apis))
|
||||
(skirmish.util/block-thread)))
|
||||
|
||||
(defn -main [& argv]
|
||||
(let [config (-> "config.edn" clojure.java.io/resource read-config)
|
||||
@@ -42,7 +48,7 @@
|
||||
(if (seq target-fns)
|
||||
(run-all-targets target-fns config)
|
||||
(do
|
||||
(println argv)
|
||||
(println "target" target-fns "not found")
|
||||
(println "all known targets are...")
|
||||
(println (keys targets))))))
|
||||
(timbre/warn argv)
|
||||
(timbre/warn "target" target-fns "not found")
|
||||
(timbre/warn "all known targets are...")
|
||||
(timbre/warn (keys targets))))))
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns skirmish.exchange.core
|
||||
(:require [skirmish.util :refer [block-thread]]
|
||||
[clojure.core.async :as async]
|
||||
[skirmish.middleware.core :refer [create-exchange-apis-for]]
|
||||
[skirmish.exchange.exchange :refer [create-exchange-for-security empty-book]]
|
||||
[kinsky.async]
|
||||
[kinsky.client]))
|
||||
[skirmish.exchange.exchange :refer [create-exchange-for-security empty-book]]))
|
||||
|
||||
|
||||
(defn create-exchange-for [exchange-api]
|
||||
(let [initial-book empty-book
|
||||
@@ -16,7 +16,10 @@
|
||||
trades-submitter
|
||||
orders-submitter)))
|
||||
|
||||
(defn -main [config exchange-apis]
|
||||
(doseq [{sec-id :sec-id} (:securities config)]
|
||||
(create-exchange-for (get exchange-apis sec-id)))
|
||||
|
||||
(defn -main [config securities-api exchange-apis-mult-chan]
|
||||
(let [ch (async/chan)]
|
||||
(async/tap exchange-apis-mult-chan ch)
|
||||
(async/go-loop [exchange-api (async/<! ch)]
|
||||
(create-exchange-for exchange-api)))
|
||||
(block-thread))
|
||||
@@ -82,7 +82,7 @@
|
||||
(defn get-processed-orders [order leftover-order trades book]
|
||||
"Computes all the intermediary orders that took place during
|
||||
a the trade.
|
||||
The interal logic is very complicated. Probably too complicated."
|
||||
The internal logic is very complicated. Probably too complicated."
|
||||
(let [ret [(assoc order :book.order/status :received)]
|
||||
ret (into ret (get-processed-orders-in-trades order book trades))
|
||||
ret (if (seq leftover-order)
|
||||
@@ -106,6 +106,3 @@
|
||||
(<! orders-copy)
|
||||
(<! trades-copy)
|
||||
(recur (<! new-order-publisher) new-book)))))
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
(ns skirmish.exchange-gateway.core
|
||||
(:require [org.httpkit.server :refer [run-server]]
|
||||
[compojure.handler :refer [api]]
|
||||
[skirmish.util :refer [block-thread]]
|
||||
[skirmish.exchange-gateway.exchange-gateway :refer [create-routes-for-exchange]]
|
||||
[skirmish.middleware.core :refer [create-map-exchange-apis]]
|
||||
[taoensso.timbre :as timbre]
|
||||
[ring.middleware.cors :refer [wrap-cors]]))
|
||||
|
||||
|
||||
(defn -main [config securities-api exchange-apis]
|
||||
(let [webserver-config (:api-server config)
|
||||
api-routes (-> exchange-apis create-map-exchange-apis create-routes-for-exchange)]
|
||||
(timbre/info "Running skirmish.exchange-gateway.core server with config:" webserver-config)
|
||||
(run-server (api api-routes) webserver-config)))
|
||||
|
||||
|
||||
+5
-16
@@ -1,16 +1,12 @@
|
||||
(ns skirmish.rest.exchange
|
||||
(:require [skirmish.exchange.exchange :refer [empty-book create-exchange-for-security]]
|
||||
[org.httpkit.server :refer [run-server with-channel send! close on-close]]
|
||||
[compojure.route :refer [not-found]]
|
||||
[compojure.handler :refer [api]]
|
||||
(ns skirmish.exchange-gateway.exchange-gateway
|
||||
(:require [compojure.route :refer [not-found]]
|
||||
[compojure.core :refer :all]
|
||||
[skirmish.order] ;; for spec side effect
|
||||
[skirmish.rest.util :refer [build-response build-response-body]]
|
||||
[skirmish.rest.util :refer [build-response get-body]]
|
||||
[clojure.spec.alpha :as s]
|
||||
[kinsky.client]
|
||||
[slingshot.slingshot :refer [try+ throw+]]
|
||||
[clojure.core.async :refer [chan go go-loop close! <! >!! sub]]
|
||||
[clojure.edn :as edn]))
|
||||
[clojure.core.async :refer [>!!]]))
|
||||
|
||||
|
||||
(def order-id (atom -1))
|
||||
@@ -28,13 +24,6 @@
|
||||
:book.order/entry-timestamp now})))
|
||||
|
||||
|
||||
(defn get-body [body]
|
||||
(try+
|
||||
(-> body clojure.java.io/reader slurp edn/read-string)
|
||||
(catch Exception e
|
||||
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid body format. Body must be edn format."}}))))
|
||||
|
||||
|
||||
(defn get-exchange-api [sec-id exchange-apis]
|
||||
(if (contains? exchange-apis sec-id)
|
||||
(get exchange-apis sec-id)
|
||||
@@ -45,7 +34,7 @@
|
||||
(fn [{{sec-id-str :sec-id} :route-params body :body :as request}]
|
||||
(try+
|
||||
(let [asked-order (get-body body)
|
||||
exchange-api (get-exchange-api (keyword sec-id-str) exchange-apis)
|
||||
exchange-api (get-exchange-api (keyword sec-id-str) @exchange-apis)
|
||||
incoming-order-channel (:new-order-submitter exchange-api)
|
||||
order (validate-order asked-order (:sec-id exchange-api))]
|
||||
(>!! incoming-order-channel order)
|
||||
@@ -0,0 +1,183 @@
|
||||
(ns skirmish.ledger.accounts
|
||||
(:require [datomic.api :as d]
|
||||
[slingshot.slingshot :refer [throw+]]))
|
||||
|
||||
(def db-uri "datomic:free://localhost:4334/skirmish")
|
||||
|
||||
(def create-securities
|
||||
[
|
||||
{:db/ident :skirmish.ledger/create-security
|
||||
:db/doc "Create a security in the system."
|
||||
:db/fn (d/function {:lang "clojure"
|
||||
:requires ['[slingshot.slingshot]]
|
||||
:params '[db sec-id interest-rate]
|
||||
:code '(let [security (d/pull db '[:db/id] [:skirmish.security/sec-id sec-id])]
|
||||
(when (-> security :db/id some?)
|
||||
(slingshot.slingshot/throw+ {:error-type :4XX :status 400 :body {:error "The security already exists."}}))
|
||||
[#:skirmish.security{:sec-id sec-id :interest-rate interest-rate}])})}])
|
||||
|
||||
(def print-securities
|
||||
[
|
||||
{:db/ident :skirmish.ledger/emit-securities
|
||||
:db/doc "Print securities fresh from the press."
|
||||
:db/fn (d/function {:lang "clojure"
|
||||
:requires ['[slingshot.slingshot]]
|
||||
:params '[db sec-id amount account-public-key]
|
||||
:code '(let [security (d/pull db '[:db/id] [:skirmish.security/sec-id sec-id])
|
||||
account (d/pull db '[:skirmish.ledger/amount :skirmish.security/sec] [:skirmish.ledger/owner-public-key account-public-key])
|
||||
base-amount (get account :skirmish.ledger/amount 0)
|
||||
entity (:db/id account "new-account")]
|
||||
(when (-> security :db/id nil?)
|
||||
(slingshot.slingshot/throw+ {:error-type :4XX :status 404 :body {:error "No security with such id."}}))
|
||||
(when (and (not= (:skirmish.security/sec account) (:db/id security)) (some? (:db/id account)))
|
||||
(slingshot.slingshot/throw+ {:error-type :4XX :status 400 :body {:error "The security emitted does not match the account security."}}))
|
||||
[[:db/add entity :skirmish.ledger/amount (+ base-amount amount)]
|
||||
[:db/add entity :skirmish.ledger/owner-public-key account-public-key]
|
||||
[:db/add entity :skirmish.ledger/sec (:db/id security)]])})}])
|
||||
|
||||
(def create-transactions
|
||||
[{:db/ident :skirmish.ledger/create-transactions
|
||||
:db/doc "Move money from one account to the other."
|
||||
:db/fn (d/function {:lang "clojure"
|
||||
:requires ['[slingshot.slingshot]]
|
||||
:params '[db transactions]
|
||||
:code '(let [from-account-id (map :from-account-id transactions)
|
||||
from-accounts (d/pull-many db '[*] (for [] [:skirmish.ledger/owner-public-key "2-sec-2"]))]
|
||||
[])})}])
|
||||
|
||||
;; there are different types of securities...
|
||||
;; 1. currencies, which pays interest rates in their one sec-id.
|
||||
;; 2. equities, which do not pay interest rates.
|
||||
;; 3. bonds, which pays interest rates in another currency.
|
||||
|
||||
(def schema-securities
|
||||
[
|
||||
{
|
||||
:db/ident :skirmish.security/sec-id
|
||||
:db/valueType :db.type/keyword
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/unique :db.unique/identity
|
||||
:db/doc "The security id."}
|
||||
{
|
||||
:db/ident :skirmish.security/name
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The usual name of the security."}
|
||||
{
|
||||
:db/ident :skirmish.security/type
|
||||
:db/valueType :db.type/keyword
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The type of security. For instance :equity or :currency."}
|
||||
{
|
||||
:db/ident :skirmish.security/description
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The description of the currency. Please be verbose."}
|
||||
{
|
||||
:db/ident :skirmish.security/emitter
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The public key of the emmiter. This is not yet supported."}
|
||||
{
|
||||
:db/ident :skirmish.security/number-of-decimal
|
||||
:db/valueType :db.type/long
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The number of decimal to show in the pretty printing."}
|
||||
{
|
||||
:db/ident :skirmish.security/symbol
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The symbol of the security for pretty printing."}
|
||||
{
|
||||
:db/ident :skirmish.security/interest-rate
|
||||
:db/valueType :db.type/long
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The daily interest-rate payed by the security as a multiple of 0.01% (100 is 1% interest rate)."}
|
||||
{
|
||||
:db/ident :skirmish.security/inflation
|
||||
:db/valueType :db.type/long
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The daily inflation as a multiple of 0.01% (100 is 1%)."}])
|
||||
|
||||
(def ledger-schema
|
||||
[
|
||||
{
|
||||
:db/ident :skirmish.ledger/owner-public-key
|
||||
:db/unique :db.unique/identity
|
||||
:db/valueType :db.type/string
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The public key of the owner"}
|
||||
{
|
||||
:db/ident :skirmish.ledger/amount
|
||||
:db/index false
|
||||
:db/valueType :db.type/long
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The quantity of currency owned by this account."}
|
||||
{
|
||||
:db/ident :skirmish.ledger/sec
|
||||
:db/index false
|
||||
:db/valueType :db.type/ref
|
||||
:db/cardinality :db.cardinality/one
|
||||
:db/doc "The sec kept in this account."}])
|
||||
|
||||
(def schema (-> []
|
||||
(concat schema-securities)
|
||||
(concat ledger-schema)
|
||||
(concat create-securities)
|
||||
(concat print-securities)
|
||||
(concat create-transactions)))
|
||||
|
||||
|
||||
(defn add-default-currencies [conn]
|
||||
(let [dapm #:skirmish.security{:sec-id :dapm
|
||||
:name "didier amyot paper money"
|
||||
:type :currency
|
||||
:description "The official currency of the 'Skirmish Shitty Exchange'."
|
||||
:emitter "dapm private key"
|
||||
:number-of-decimal 2
|
||||
:symbol "რ"
|
||||
:interest-rate (* 100 10)
|
||||
:inflation (* 100 9)}
|
||||
apbm #:skirmish.security{:sec-id :apbm
|
||||
:name "apache beam"
|
||||
:type :equity
|
||||
:description "Unified programming model to define and execute data processing pipelines, including ETL, batch and stream (continuous) processing."
|
||||
:emitter "apbm private key"
|
||||
:number-of-decimal 0}
|
||||
apac #:skirmish.security{:sec-id :apac
|
||||
:name "apache accumulo"
|
||||
:type :equity
|
||||
:description "A sorted, distributed key/value store that provides robust, scalable data storage and retrieval."
|
||||
:emitter "apac private key"
|
||||
:number-of-decimal 0}
|
||||
apax #:skirmish.security{:sec-id :apax
|
||||
:name "apache apex"
|
||||
:type :equity
|
||||
:description "Enterprise-grade unified stream and batch processing engine."
|
||||
:emitter ":apax private key"
|
||||
:number-of-decimal 0}
|
||||
apdr #:skirmish.security{:sec-id :apdr
|
||||
:name "apache drill"
|
||||
:type :equity
|
||||
:description "Schema-free SQL Query Engine for Hadoop, NoSQL and Cloud Storage."
|
||||
:emitter ":apdr private key"
|
||||
:number-of-decimal 0}
|
||||
apmh #:skirmish.security{:sec-id :apmh
|
||||
:name "apache mahout"
|
||||
:type :equity
|
||||
:description "For Creating Scalable Performant Machine Learning Applications."
|
||||
:emitter ":apmh private key"
|
||||
:number-of-decimal 0}]
|
||||
@(d/transact conn [dapm apbm apac apax apdr apmh])))
|
||||
|
||||
(defn create-connection
|
||||
([uri init-when-new?]
|
||||
(let [new-db? (d/create-database uri)
|
||||
conn (d/connect uri)]
|
||||
@(d/transact conn schema)
|
||||
(if (and init-when-new? new-db?)
|
||||
(add-default-currencies conn))
|
||||
conn))
|
||||
([uri]
|
||||
(create-connection uri true)))
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
(ns skirmish.ledger.controllers
|
||||
(:require [skirmish.rest.util :refer [build-response get-body cors-middleware]]
|
||||
[skirmish.ledger.data-layer :as data-layer]
|
||||
[skirmish.routes.core :as routes]
|
||||
[compojure.core :as compojure]
|
||||
[compojure.route :refer [not-found]]
|
||||
[clojure.spec.alpha :as s]
|
||||
[datomic.api :as d]
|
||||
[slingshot.slingshot :refer [try+ throw+]]))
|
||||
|
||||
|
||||
|
||||
(defn get-api-description [request]
|
||||
(let [body [{:url "ledger/accounts" :name "accounts"}
|
||||
{:url "ledger/securities" :name "securities"}]]
|
||||
(build-response request body)))
|
||||
|
||||
(defn get-available-accounts-body [accounts]
|
||||
(let [sec-id->url #(routes/get-path-for :ledger/account {:account-id (name %)})
|
||||
to-security-description #(hash-map :account-public-key % :url (sec-id->url %))
|
||||
xf (comp cat (map to-security-description))
|
||||
securities-info (sequence xf accounts)]
|
||||
{:accounts securities-info}))
|
||||
|
||||
|
||||
(defn get-available-accounts [conn]
|
||||
(fn [request]
|
||||
(let [db (d/db conn)
|
||||
resp (get-available-accounts-body (data-layer/get-all-account-public-key db))]
|
||||
(build-response request resp))))
|
||||
|
||||
(defn get-account-body [request {sec-id :sec-id amount :amount account-public-key :account-public-key}]
|
||||
(if (nil? sec-id)
|
||||
(build-response request {:status 404})
|
||||
(let [sec-url (str "/api/1/ledger/securities/" (name sec-id))
|
||||
beautify-account { :amount amount
|
||||
:sec-id sec-id
|
||||
:account-public-key account-public-key}
|
||||
ret {:account beautify-account :sec-url sec-url}]
|
||||
(build-response request ret))))
|
||||
|
||||
(defn get-account [conn]
|
||||
"Returns the value of an account."
|
||||
(fn [{{account-id :account-id} :route-params :as request}]
|
||||
(let [db (d/db conn)
|
||||
account-info (data-layer/get-amount-in-account db account-id)]
|
||||
(get-account-body request account-info))))
|
||||
|
||||
(defn get-account [conn]
|
||||
"Returns the value of an account."
|
||||
(fn [{{account-id :account-id} :route-params :as request}]
|
||||
(let [db (d/db conn)
|
||||
account-info (data-layer/get-amount-in-account db account-id)]
|
||||
(get-account-body request account-info))))
|
||||
|
||||
(defn get-transactions [conn]
|
||||
(fn [request]
|
||||
(let [all-pending-transactions []]
|
||||
(build-response request all-pending-transactions))))
|
||||
|
||||
(defn create-transactions [conn]
|
||||
(fn [{body :body :as request}]
|
||||
(try+
|
||||
(build-response request {:message "merci beaucoup"})
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
(defn get-available-securities-body [securities]
|
||||
(let [sec-id->url #(routes/get-path-for :ledger/security {:sec-id (name %)})
|
||||
to-security-description #(hash-map :sec-id % :url (sec-id->url %))
|
||||
xf (comp cat (map to-security-description))
|
||||
securities-info (sequence xf securities)];;
|
||||
{:securities securities-info}))
|
||||
|
||||
|
||||
(defn get-available-securities [conn]
|
||||
(fn [request]
|
||||
(let [db (d/db conn)
|
||||
securities (data-layer/get-all-securities-id db)]
|
||||
(build-response request (get-available-securities-body securities)))))
|
||||
|
||||
(defn get-new-security [raw-securities]
|
||||
(if (s/valid? :skirmish.ledger.core/security raw-securities)
|
||||
raw-securities
|
||||
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid security format."}})))
|
||||
|
||||
(defn create-security [conn]
|
||||
"Create a fresh new security."
|
||||
(fn [{body :body :as request}]
|
||||
(try+
|
||||
(let [[sec-id interest-rate] (-> body get-body get-new-security)
|
||||
new-sec @(data-layer/create-security conn sec-id interest-rate)]
|
||||
(build-response request {:body {:success true}
|
||||
:headers {"location" (str "/api/1" "/ledger/securities/" (name sec-id))}}))
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
|
||||
(defn prettify-security [e db]
|
||||
(let [{interest-rate :skirmish.security/interest-rate
|
||||
description :skirmish.security/description
|
||||
id :db/id
|
||||
sec-id :skirmish.security/sec-id
|
||||
symbol :skirmish.security/symbol
|
||||
name :skirmish.security/name
|
||||
number-of-decimal :skirmish.security/number-of-decimal
|
||||
type_ :skirmish.security/type} e
|
||||
interest-rate-history (data-layer/get-interest-rate-history db id)
|
||||
volumes (d/q '[:find ?amount ?date
|
||||
:in $ ?id
|
||||
:where [?e :skirmish.ledger/sec ?id]
|
||||
[?e :skirmish.ledger/amount ?amount ?tx]
|
||||
[?tx :db/txInstant ?date]]
|
||||
db id)
|
||||
now (new java.util.Date)
|
||||
volume (reduce + 0 (map #(data-layer/compute-face-value (first %) interest-rate-history (second %) now) volumes))]
|
||||
{:sec-id sec-id
|
||||
:interest-rate interest-rate
|
||||
:volume (or volume 0)
|
||||
:name name
|
||||
:interest-rate-history interest-rate-history
|
||||
:symbol symbol
|
||||
:number-of-decimal number-of-decimal
|
||||
:type type_
|
||||
:description description}))
|
||||
|
||||
(defn get-security-from-db [conn sec-id]
|
||||
(let [db (d/db conn)
|
||||
e (d/pull db '[*] [:skirmish.security/sec-id sec-id])]
|
||||
(if (-> e :db/id nil?)
|
||||
(throw+ {:error-type :4XX :status 404 :body {:error "Security not found."}})
|
||||
(prettify-security e db))))
|
||||
|
||||
(defn get-security [conn]
|
||||
"Returns the security."
|
||||
(fn [{{sec-id-str :sec-id} :route-params :as request}]
|
||||
(try+
|
||||
(let [sec-id (keyword sec-id-str)]
|
||||
(build-response request (get-security-from-db conn sec-id)))
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
(defn update-security [conn]
|
||||
"Update a security with new features."
|
||||
(fn [request]
|
||||
(try+
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
(defn get-emit-securities-request [[amount account] sec-id]
|
||||
(if (s/valid? :skirmish.ledger.core/emit-securities [sec-id amount account])
|
||||
[:skirmish.ledger/emit-securities sec-id amount account]
|
||||
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid emit request."}})))
|
||||
|
||||
|
||||
(defn emit-securities [conn]
|
||||
"Emit securities in the specified wallet. This is the only way to
|
||||
create securities.
|
||||
|
||||
payload
|
||||
[:amount :account]"
|
||||
(fn [{{sec-id-str :sec-id} :route-params body :body :as request}]
|
||||
(try+
|
||||
(let [emit-request (-> body get-body (get-emit-securities-request (keyword sec-id-str)))]
|
||||
@(d/transact conn [emit-request])
|
||||
(build-response request {}))
|
||||
(catch [:error-type :4XX] e (build-response request e))
|
||||
(catch [:error-type :5XX] e (build-response request e)))))
|
||||
|
||||
(defn create-routes-for-ledger [conn]
|
||||
(compojure/routes
|
||||
(routes/context :ledger []
|
||||
(routes/GET :ledger/home [] get-api-description)
|
||||
(routes/GET :ledger/accounts [] (get-available-accounts conn))
|
||||
(routes/GET :ledger/account [] (get-account conn))
|
||||
(routes/GET :ledger/transactions [] (get-transactions conn))
|
||||
(routes/POST :ledger/transactions [] (create-transactions conn))
|
||||
(routes/GET :ledger/securities [] (get-available-securities conn))
|
||||
(routes/POST :ledger/securities [] (create-security conn))
|
||||
(routes/GET :ledger/security [] (get-security conn))
|
||||
(routes/PUT :ledger/security [] (update-security conn)) ;; TODO
|
||||
(routes/POST :ledger/security [] (emit-securities conn)))
|
||||
(not-found "not found")))
|
||||
@@ -0,0 +1,36 @@
|
||||
(ns skirmish.ledger.core
|
||||
(:require [org.httpkit.server :refer [run-server]]
|
||||
[skirmish.ledger.controllers :as controllers]
|
||||
[compojure.handler :refer [api]]
|
||||
[skirmish.rest.util :refer [cors-middleware]]
|
||||
[skirmish.ledger.accounts]
|
||||
[taoensso.timbre :as timbre]
|
||||
[clojure.spec.alpha :as s]))
|
||||
|
||||
(s/def ::transaction (s/cat :type #{:transfer-immediately}
|
||||
:from-account-id string?
|
||||
:to-account-id string?
|
||||
:amount int?))
|
||||
|
||||
(s/def ::transactions (s/coll-of ::transaction))
|
||||
|
||||
(s/def ::security (s/cat :sec-id keyword?
|
||||
:interest-rate nat-int?
|
||||
:type #{:equity :currency}
|
||||
:description string?
|
||||
:emitter string?
|
||||
:symbol (s/? string?)))
|
||||
|
||||
(s/def ::emit-securities (s/cat :sec-id keyword?
|
||||
:amount nat-int?
|
||||
:account string?))
|
||||
|
||||
(defn -main [config securities-api exchange-apis]
|
||||
(let [ledger-config (:ledger-server config)
|
||||
conn (skirmish.ledger.accounts/create-connection (-> config :datomic :transactor-url))
|
||||
api-routes (controllers/create-routes-for-ledger conn)]
|
||||
(timbre/info "Running skirmish.ledger.core server with config: " ledger-config)
|
||||
(run-server
|
||||
(-> api-routes api cors-middleware)
|
||||
ledger-config)))
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
(ns skirmish.ledger.data-layer
|
||||
(:require [datomic.api :as d]
|
||||
[infix.macros :refer [infix]]
|
||||
[slingshot.slingshot :refer [throw+]]))
|
||||
|
||||
(defn get-all-account-public-key [db]
|
||||
(d/q '[:find ?pk :where [?e :skirmish.ledger/owner-public-key ?pk]] db))
|
||||
|
||||
(defn compute-simple-face-value [amount daily-interest-rate deposit-date value-date]
|
||||
(let [min-in-milliseconds (infix 60 * 1000)
|
||||
minute-interest-rate (infix daily-interest-rate / (24 * 60. * 10000.))
|
||||
ite (quot (- (. value-date getTime) (. deposit-date getTime)) min-in-milliseconds)
|
||||
base (infix 1 + minute-interest-rate)]
|
||||
(infix amount * base ** ite)))
|
||||
|
||||
(defn- in-interval? [[_ start end] x]
|
||||
(let [x-time (. x getTime)]
|
||||
(and (<= (. start getTime) x-time)
|
||||
(< x-time (. end getTime)))))
|
||||
|
||||
(defn- larger-then-interval? [[ _ start end] x]
|
||||
(and (<= (. x getTime) (. end getTime))
|
||||
(<= (. x getTime) (. start getTime))))
|
||||
|
||||
(defn- split-interest-rate-intervals [interest-rates-intervals deposit-date value-date]
|
||||
(let [xf (comp (drop-while #((comp not in-interval?) % deposit-date))
|
||||
(take-while #((comp not larger-then-interval?) % value-date)))
|
||||
ret (into [] xf interest-rates-intervals)
|
||||
ret (assoc-in ret [0 1] deposit-date)
|
||||
ret (assoc-in ret [(-> ret count dec) 2] value-date)]
|
||||
ret))
|
||||
|
||||
(defn- find-interest-rate-for [interest-rates-intervals d]
|
||||
(if (in-interval? (first interest-rates-intervals) d)
|
||||
(ffirst interest-rates-intervals)
|
||||
(recur (rest interest-rates-intervals) d)))
|
||||
|
||||
(defn split-interest-rates [interest-rates deposit-date value-date]
|
||||
(let [interest-rates (into [[0 (new java.util.Date 0)]] interest-rates)
|
||||
interest-rates (conj interest-rates [0 (new java.util.Date Long/MAX_VALUE)])
|
||||
interest-rates-intervals (partition 2 1 interest-rates)
|
||||
interest-rates-intervals (map (juxt ffirst (comp second first) (comp second second)) interest-rates-intervals)]
|
||||
(if (= deposit-date value-date)
|
||||
[[(find-interest-rate-for interest-rates-intervals deposit-date) deposit-date value-date]]
|
||||
(split-interest-rate-intervals interest-rates-intervals deposit-date value-date))))
|
||||
|
||||
(defn compute-face-value [amount interest-rates deposit-date value-date]
|
||||
(loop [interest-rates (split-interest-rates interest-rates deposit-date value-date)
|
||||
amount amount]
|
||||
(let [[interest-rate start end] (first interest-rates)
|
||||
amount (compute-simple-face-value amount interest-rate start end)]
|
||||
(if (empty? (rest interest-rates))
|
||||
(long amount)
|
||||
(recur (rest interest-rates) amount)))))
|
||||
|
||||
(defn get-interest-rate-history [db sec-id]
|
||||
(let [history (d/history db)
|
||||
interest-rates (d/q '[:find ?interest-rate ?v
|
||||
:in $ ?eid
|
||||
:where [?e :skirmish.security/interest-rate ?interest-rate ?tx]
|
||||
[?e :skirmish.security/sec-id ?sec-id]
|
||||
[?tx :db/txInstant ?v]]
|
||||
history sec-id)]
|
||||
(sort-by second interest-rates)))
|
||||
|
||||
(defn compute-face-value-from-db [db amount sec-id date]
|
||||
(compute-face-value amount
|
||||
(get-interest-rate-history db sec-id)
|
||||
date
|
||||
(new java.util.Date)))
|
||||
|
||||
(defn get-amount-in-account [db account-id]
|
||||
(let [[amount sec-id pk date] (d/q '[:find [?amount ?sec-id ?pk ?v]
|
||||
:in $ ?account-id
|
||||
:where [?e :skirmish.ledger/owner-public-key ?account-id]
|
||||
[?e :skirmish.ledger/amount ?amount ?tx]
|
||||
[?e :skirmish.ledger/sec ?sec]
|
||||
[?sec :skirmish.security/sec-id ?sec-id]
|
||||
[?e :skirmish.ledger/owner-public-key ?pk]
|
||||
[?tx :db/txInstant ?v]]
|
||||
db account-id)]
|
||||
{:amount (when (some? sec-id) (compute-face-value-from-db db amount sec-id date))
|
||||
:sec-id sec-id
|
||||
:account-public-key pk}))
|
||||
|
||||
(defn get-all-securities-id [db]
|
||||
(d/q '[:find ?s :where [?e :skirmish.security/sec-id ?s]] db))
|
||||
|
||||
(defn create-security [conn sec-id interest-rate]
|
||||
(d/transact conn [[:skirmish.ledger/create-security sec-id interest-rate]]))
|
||||
|
||||
(defn get-account [db account-id]
|
||||
(d/pull db '[*] [:skirmish.ledger/owner-public-key account-id]))
|
||||
|
||||
(defn assoc-accounts [db transaction]
|
||||
(let [from-account (get-account db (:from-account-id transaction))
|
||||
to-account (get-account db (:to-account-id transaction))
|
||||
ret (assoc transaction :from-account from-account)
|
||||
ret (assoc ret :to-account to-account)]
|
||||
ret))
|
||||
|
||||
(defn get-new-from-account-value [{amount :amount from-account :from-account} old-change]
|
||||
(if (some? old-change)
|
||||
(assoc old-change 3 (- (get old-change 3) amount))
|
||||
[:db/add
|
||||
(:db/id from-account)
|
||||
:skirmish.ledger/amount
|
||||
(- (:skirmish.ledger/amount from-account) amount)]))
|
||||
|
||||
(defn get-new-to-account-value [{amount :amount to-account :to-account} old-change]
|
||||
(if (some? old-change)
|
||||
(assoc old-change 3 (+ (get old-change 3) amount))
|
||||
[:db/add
|
||||
(:db/id to-account)
|
||||
:skirmish.ledger/amount
|
||||
(+ (:skirmish.ledger/amount to-account) amount)]))
|
||||
|
||||
(defn compute-transactions [res transaction]
|
||||
(let [res-from-account (get res (:from-account-id transaction))
|
||||
from-account (get-new-from-account-value transaction res-from-account)
|
||||
res (assoc res (:from-account-id transaction) from-account)
|
||||
res-to-account (get res (:to-account-id transaction))
|
||||
to-account (get-new-to-account-value transaction res-to-account)
|
||||
res (assoc res (:to-account-id transaction) to-account)]
|
||||
res))
|
||||
|
||||
(defn validate-transactions [transactions]
|
||||
(loop [transactions transactions]
|
||||
(when (seq transactions)
|
||||
(let [transaction (first transactions)]
|
||||
(when (not= (-> transaction :from-account :skirmish.ledger/sec)
|
||||
(-> transaction :to-account :skirmish.ledger/sec))
|
||||
(throw+ {:error-type :4XX
|
||||
:status 400
|
||||
:body {:error "Part of the transaction includes a transaction between two wallets of different underlying securities."}}))
|
||||
(recur (rest transactions)))))
|
||||
transactions)
|
||||
|
||||
(defn validate-resulting-transactions [transactions]
|
||||
(loop [transactions transactions]
|
||||
(when (seq transactions)
|
||||
(let [transaction (first transactions)]
|
||||
(when (neg? (get transaction 3))
|
||||
(throw+ {:error-type :4XX
|
||||
:status 400
|
||||
:body {:error "Transaction would result in a negative amount in a wallet."}})))
|
||||
(recur (rest transactions))))
|
||||
transactions)
|
||||
|
||||
(defn create-transactions [db transactions]
|
||||
(let [transactions (map #(assoc-accounts db %) transactions)
|
||||
transactions (validate-transactions transactions)
|
||||
ret (vals (reduce compute-transactions {} transactions))]
|
||||
(validate-resulting-transactions ret)))
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns skirmish.middleware.core
|
||||
(:require [clojure.core.async :as async]
|
||||
[skirmish.exchange.exchange :refer [empty-book create-exchange-for-security]] ;; remove this import.
|
||||
[kinsky.async]
|
||||
[clojure.core.async :refer [go-loop <! sub chan]]
|
||||
[kinsky.client]))
|
||||
|
||||
(defn create-chan-based-exchange-api-for [sec-id]
|
||||
@@ -9,6 +8,7 @@
|
||||
trades (async/chan)
|
||||
orders (async/chan)]
|
||||
{:sec-id sec-id
|
||||
:disabled false
|
||||
:new-order-publisher new-order ;; anything published here will be processed as
|
||||
:new-order-submitter new-order
|
||||
:trades-publisher (async/pub trades :book.order/type)
|
||||
@@ -16,12 +16,44 @@
|
||||
:orders-publisher (async/pub orders :book.order/status)
|
||||
:orders-submitter orders}))
|
||||
|
||||
(def api-creators {})
|
||||
|
||||
(defn create-exchange-apis-for [config]
|
||||
;; todo: spec this function
|
||||
(let [security-definitions (map :sec-id (:securities config))
|
||||
create-exchange-api-for (get api-creators (:middleware config) create-chan-based-exchange-api-for)
|
||||
f (fn [sec] [sec (create-exchange-api-for sec)])
|
||||
ret (into {} (map f security-definitions))]
|
||||
(defn create-chan-based-security-api [config]
|
||||
(let [securities (async/chan)]
|
||||
{:securities-publisher (async/mult securities)
|
||||
:securities-submitter securities}))
|
||||
|
||||
(def security-api-creators {})
|
||||
|
||||
(defn create-securities-api-for [config]
|
||||
(let [creator (get security-api-creators (:middleware config) create-chan-based-security-api)]
|
||||
(creator config)))
|
||||
|
||||
(defn update-exchange-apis [create-exchange-api-for sec]
|
||||
(let [sec-id (:sec-id sec)
|
||||
disabled? (get sec :disabled false)]
|
||||
(if disabled?
|
||||
{:sec-id sec-id :disabled true}
|
||||
(create-exchange-api-for sec-id))))
|
||||
|
||||
(def exchange-api-creators {})
|
||||
|
||||
(defn create-exchange-apis-for [config securities-api]
|
||||
(let [ret (async/chan)
|
||||
securities-ch (async/chan)
|
||||
securities-publisher (:securities-publisher securities-api)
|
||||
create-exchange-api-for (get exchange-api-creators (:middleware config) create-chan-based-exchange-api-for)]
|
||||
(async/tap securities-publisher securities-ch)
|
||||
(go-loop [sec (<! securities-ch)]
|
||||
(async/>! ret (update-exchange-apis create-exchange-api-for sec))
|
||||
(recur (<! securities-ch)))
|
||||
(async/mult ret)))
|
||||
|
||||
(defn create-map-exchange-apis [exchange-apis-mult-chan]
|
||||
(let [c (async/chan)
|
||||
ret (atom {})]
|
||||
(async/tap exchange-apis-mult-chan chan)
|
||||
(async/go-loop [exchange-api (async/<! c)]
|
||||
(if (:disabled? exchange-api)
|
||||
(swap! ret #(dissoc % (:sec-id exchange-api)))
|
||||
(swap! ret #(assoc % (:sec-id exchange-api) exchange-api))))
|
||||
ret))
|
||||
@@ -1,23 +0,0 @@
|
||||
(ns skirmish.rest.core
|
||||
(:require [org.httpkit.server :refer [run-server]]
|
||||
[compojure.handler :refer [api]]
|
||||
[skirmish.util :refer [block-thread]]
|
||||
[skirmish.middleware.core :refer [create-exchange-apis-for]]
|
||||
[skirmish.rest.bookkeeper :refer [create-routes-for-bookkeeper]]
|
||||
[skirmish.rest.exchange :refer [create-routes-for-exchange]]))
|
||||
|
||||
|
||||
(defn api-main [config exchange-apis]
|
||||
(let [webserver-config (:api-server config)
|
||||
api-routes (create-routes-for-exchange exchange-apis)]
|
||||
(println "Running server with bellow config")
|
||||
(println webserver-config)
|
||||
(run-server (api api-routes) webserver-config)))
|
||||
|
||||
|
||||
(defn bookkeeper-main [config exchange-apis]
|
||||
(let [webserver-config (:api-bookkeeper config)
|
||||
api-routes (create-routes-for-bookkeeper exchange-apis)]
|
||||
(println "Running server with bellow config")
|
||||
(println webserver-config)
|
||||
(run-server (api api-routes) webserver-config)))
|
||||
@@ -1,13 +1,21 @@
|
||||
(ns skirmish.rest.util
|
||||
(:require [cheshire.core :refer [generate-string]]
|
||||
[slingshot.slingshot :refer [try+ throw+]]
|
||||
[clojure.edn :as edn]
|
||||
[ring.middleware.cors :refer [wrap-cors]]
|
||||
[clojure.string :refer [split starts-with? ends-with?]]))
|
||||
|
||||
|
||||
;; Access-Control-Allow-Origin
|
||||
|
||||
(def mime-types
|
||||
[["application/json" generate-string]
|
||||
["application/edn" str]])
|
||||
|
||||
(defn cors-middleware [handler]
|
||||
(wrap-cors handler
|
||||
:access-control-allow-origin #"http://localhost:3449"
|
||||
:access-control-allow-credentials true
|
||||
:access-control-allow-methods [:get :put :post :delete]))
|
||||
|
||||
|
||||
(defn create-mime-type-predicate [accept]
|
||||
@@ -40,8 +48,27 @@
|
||||
(let [[_ serializer] (get-best-serializer request)]
|
||||
(serializer body)))
|
||||
|
||||
(defn build-response [request {status :status body :body :as response}]
|
||||
(let [[content-type serializer] (get-best-serializer request)]
|
||||
(defn build-response [request {status :status body :body headers :headers :as response}]
|
||||
(let [[content-type serializer] (get-best-serializer request)
|
||||
ret-headers (if (some? headers) headers {})]
|
||||
{:body (serializer (if (nil? body) response body))
|
||||
:headers {"Content-Type" content-type}
|
||||
:headers (into {"Content-Type" content-type} ret-headers)
|
||||
:status (get-status status request)}))
|
||||
|
||||
(defn not-found-resp [request]
|
||||
(build-response request {:status 404 :body {:error "not found"}}))
|
||||
|
||||
(defn get-body [body]
|
||||
(try+
|
||||
(-> body clojure.java.io/reader slurp edn/read-string)
|
||||
(catch Exception e
|
||||
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid body format. Body must be edn format."}}))))
|
||||
|
||||
(defn string->stream
|
||||
([s] (string->stream s "UTF-8"))
|
||||
([s encoding]
|
||||
(-> s
|
||||
(.getBytes encoding)
|
||||
(java.io.ByteArrayInputStream.))))
|
||||
|
||||
(def edn->stream (comp string->stream str))
|
||||
@@ -0,0 +1,46 @@
|
||||
(ns skirmish.routes.api)
|
||||
|
||||
(defn get-app-for [all-routes k]
|
||||
"An app consists on a name, a prefix and some routes."
|
||||
(let [app-name (-> k namespace keyword)
|
||||
app (first (filter #(= app-name (:name %)) all-routes))]
|
||||
app))
|
||||
|
||||
(defn- get-route-for [all-routes k]
|
||||
(let [app (get-app-for all-routes k)
|
||||
route-name (-> k name keyword)
|
||||
route (first (filter #(= route-name (:name %)) (:routes app)))]
|
||||
route))
|
||||
|
||||
(defn get-compojure-path [all-routes k]
|
||||
"Returns what compojure expects to have."
|
||||
(->> k (get-route-for all-routes) :path))
|
||||
|
||||
(defn- replace-part [part params]
|
||||
(if (clojure.string/starts-with? part ":")
|
||||
(-> part (subs 1) keyword params)
|
||||
part))
|
||||
|
||||
(defn- path-for [p params]
|
||||
(let [parts (clojure.string/split p #"/")]
|
||||
(clojure.string/join "/" (map #(replace-part % params) parts))))
|
||||
|
||||
(defn get-context [all-routes c]
|
||||
(let [get-app #(get-app-for all-routes %)]
|
||||
(-> c
|
||||
name
|
||||
(keyword "some-name")
|
||||
get-app
|
||||
:path)))
|
||||
|
||||
(defn get-path-for
|
||||
"Returns a link to a location by name."
|
||||
([all-routes k]
|
||||
(get-path-for all-routes k {}))
|
||||
([all-routes k params]
|
||||
(let [app (get-app-for all-routes k)
|
||||
route (get-route-for all-routes k)
|
||||
p (str (:path app) (:path route))
|
||||
domain (get app :domain "")]
|
||||
(str domain (path-for p params)))))
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
(ns skirmish.routes.core
|
||||
(:require [skirmish.routes.api :as routes-api]
|
||||
[compojure.core :as compojure]))
|
||||
|
||||
|
||||
(def ledger-routes {
|
||||
:name :ledger
|
||||
:domain "http://localhost:1604" ;; should somehow be in some config
|
||||
:path "/api/1/ledger"
|
||||
:routes [{:name :home :path "/"}
|
||||
{:name :accounts :path "/accounts"}
|
||||
{:name :account :path "/accounts/:account-id"}
|
||||
{:name :securities :path "/securities"}
|
||||
{:name :security :path "/securities/:sec-id"}
|
||||
{:name :transactions :path "/transactions"}]})
|
||||
|
||||
(def all-routes [ledger-routes])
|
||||
|
||||
(def get-context (partial routes-api/get-context all-routes))
|
||||
|
||||
(def get-compojure-path (partial routes-api/get-compojure-path all-routes))
|
||||
|
||||
(def get-path-for (partial routes-api/get-path-for all-routes))
|
||||
|
||||
(defmacro GET [path args & body]
|
||||
(compojure/compile-route :get
|
||||
(get-compojure-path path)
|
||||
args
|
||||
body))
|
||||
|
||||
(defmacro POST [path args & body]
|
||||
(compojure/compile-route :post
|
||||
(get-compojure-path path)
|
||||
args
|
||||
body))
|
||||
|
||||
(defmacro PUT [path args & body]
|
||||
(compojure/compile-route :put
|
||||
(get-compojure-path path)
|
||||
args
|
||||
body))
|
||||
|
||||
(defmacro context [path args & routes]
|
||||
(let [resolved-path (get-context path)]
|
||||
(concat `(compojure/context ~resolved-path ~args) routes)))
|
||||
@@ -0,0 +1,39 @@
|
||||
(ns skirmish.strategies.core
|
||||
(:require [clojure.core.async :as async :refer [>! <!]]))
|
||||
|
||||
|
||||
(defn strategy-one [])
|
||||
|
||||
(defprotocol SimpleStrategy
|
||||
"Implement this protocol if you wish to make a strategy"
|
||||
(get-urls-to-fetch [strategy msecs]
|
||||
"returns a list of all the url to fetch.")
|
||||
(get-wished-trades [strategy msec data]
|
||||
""))
|
||||
|
||||
(defrecord TheBananaStrategy [sec-id look-back-in-days period])
|
||||
|
||||
(extend-type TheBananaStrategy
|
||||
SimpleStrategy
|
||||
(get-urls-to-fetch [strat msecs]
|
||||
(let [sec-id (-> strat :sec-id name)
|
||||
one-day (* 24 3600 1000)
|
||||
from (- msecs (-> strat :look-back-in-days (* one-day)))
|
||||
period (:period strat)
|
||||
to msecs]
|
||||
(format "/api/v1/securities/%s/l1?from=%s&to=%s&period=period" sec-id from to period))))
|
||||
|
||||
|
||||
(defn get-data-for-strategy [strategy])
|
||||
|
||||
|
||||
(defn make-trades [wanted-trades])
|
||||
|
||||
|
||||
(defn framework [strategy msecs]
|
||||
(async/go-loop [_ (<! (async/timeout msecs))]
|
||||
(let [data-for-strategy (<! (get-data-for-strategy strategy))
|
||||
wanted-trades (strategy data-for-strategy)
|
||||
results (<! (make-trades wanted-trades))])
|
||||
(recur (<! (async/timeout msecs)))))
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
(ns skirmish.util
|
||||
(:require [clojure.core.async :as async])
|
||||
(:import [skirmish.PersistentSortedList]))
|
||||
(:import [ skirmish PersistentSortedList]))
|
||||
|
||||
(defn sorted-list [& keys]
|
||||
(skirmish.PersistentSortedList/create (seq keys)))
|
||||
(PersistentSortedList/create (seq keys)))
|
||||
|
||||
(defn sorted-list-by [comparator & keys]
|
||||
(skirmish.PersistentSortedList/create comparator (seq keys)))
|
||||
(PersistentSortedList/create comparator (seq keys)))
|
||||
|
||||
(defn block-thread []
|
||||
"Block the current thread until chuck norris gets weaker."
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
(:require [compojure.core :refer [GET defroutes]]
|
||||
[compojure.route :refer [not-found resources]]
|
||||
[hiccup.page :refer [include-js include-css html5]]
|
||||
[skirmish.wui.middleware :refer [wrap-middleware]]))
|
||||
[skirmish.wui.middleware :refer [wrap-middleware]])
|
||||
(:gen-class))
|
||||
|
||||
(def mount-target
|
||||
[:div#app
|
||||
@@ -14,6 +15,7 @@
|
||||
(defn head []
|
||||
[:head
|
||||
[:meta {:charset "utf-8"}]
|
||||
[:title "Skirmish"]
|
||||
[:meta {:name "viewport"
|
||||
:content "width=device-width, initial-scale=1"}]
|
||||
(include-css "/css/site.css"); use "/css/site.min.css" in production
|
||||
@@ -25,7 +27,8 @@
|
||||
(head)
|
||||
[:body.body-container
|
||||
mount-target
|
||||
(include-js "/js/app.js")]))
|
||||
(include-js "/js/app.js")
|
||||
(include-js "https://sidecar.gitter.im/dist/sidecar.v1.js")]))
|
||||
|
||||
(defn loading-page []
|
||||
(html5
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns skirmish.wui.server
|
||||
(:require [skirmish.wui.handler :refer [app]]
|
||||
[ring.adapter.jetty :refer [run-jetty]])
|
||||
[org.httpkit.server :refer [run-server]])
|
||||
(:gen-class))
|
||||
|
||||
(defn -main [config exchange-apis]
|
||||
(defn -main [config securities-api exchange-apis]
|
||||
(let [port 3000]
|
||||
(run-jetty app {:port port :join? false})))
|
||||
(run-server app {:port port :join? false})))
|
||||
@@ -0,0 +1,3 @@
|
||||
(ns skirmish.wui-util)
|
||||
|
||||
(defn pp-number [n])
|
||||
@@ -0,0 +1,50 @@
|
||||
(ns skirmish.wui.components.create-order-page
|
||||
(:require [reagent.core :refer [atom]]))
|
||||
|
||||
(defn set-value-in-atom [atm key evt]
|
||||
(swap! atm #(assoc % key (-> evt .-target .-value))))
|
||||
|
||||
|
||||
|
||||
(defn select-type [order]
|
||||
[:div.control
|
||||
[:div.select
|
||||
[:select {:on-change (partial set-value-in-atom order :type)}
|
||||
[:option {:value :buy} "Buy"]
|
||||
[:option {:value :sell} "Sell"]]]])
|
||||
|
||||
(defn select-securities [order]
|
||||
[:div.control
|
||||
[:div.select
|
||||
[:select {:on-change (partial set-value-in-atom order :sec-id)}
|
||||
[:option {:value :nype} ":nype"]
|
||||
[:option {:value :osko} ":osko"]
|
||||
[:option {:value :oops} ":oops"]]]])
|
||||
|
||||
(defn select-quantities [order]
|
||||
[:div.control
|
||||
[:input.input {:type "number"
|
||||
:on-change (partial set-value-in-atom order :quantity)}]])
|
||||
|
||||
(def action-button
|
||||
[:div.control
|
||||
[:button.button.is-primary "Submit"]])
|
||||
|
||||
|
||||
(defn page []
|
||||
(let [order (atom {})]
|
||||
(fn []
|
||||
[:div
|
||||
[:div.columns
|
||||
[:div.column.content
|
||||
[:div.columns.is-centered
|
||||
[:div
|
||||
[:div.field.has-addons
|
||||
(select-type order)
|
||||
(select-securities order)
|
||||
(select-quantities order)
|
||||
action-button]]]]]
|
||||
[:div.columns
|
||||
[:div.column.content
|
||||
[:pre (str @order)]]]])))
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
(ns skirmish.wui.components.face-value
|
||||
(:require [skirmish.wui.components.secunit :refer [secunit]]))
|
||||
|
||||
(defn face-value [amount sec-id]
|
||||
(when (= sec-id :dapm)
|
||||
(secunit amount sec-id)))
|
||||
@@ -1,4 +1,45 @@
|
||||
(ns skirmish.wui.components.home-page)
|
||||
(ns skirmish.wui.components.home-page
|
||||
(:require [cljs-http.client :as http]
|
||||
[reagent.core :refer [atom]]
|
||||
[skirmish.wui.util :refer [email?]]
|
||||
[cljs.core.async :refer [<!] :refer-macros [go]]
|
||||
[secretary.core :as secretary]))
|
||||
|
||||
(defn create-user [email]
|
||||
(go
|
||||
(let [url "http://localhost:1605/api/1/users"
|
||||
resp (<! (http/post url {:edn-params {:email email}}))]
|
||||
(secretary/dispatch! (str "/home/" email)))))
|
||||
|
||||
|
||||
(defn login [state]
|
||||
(let [login-field (atom (get-in state [:user :skirmish.broker.user/email] ""))
|
||||
on-change #(reset! login-field (-> % .-target .-value))]
|
||||
(fn []
|
||||
(let [disabled? (-> @login-field email? not)
|
||||
href (if (not disabled?) (str "/home/" @login-field) nil)]
|
||||
[:div.field
|
||||
[:div.control
|
||||
[:label.label "Email"]
|
||||
[:div.field.is-grouped
|
||||
[:input.input.is-success {:type "email"
|
||||
:value @login-field
|
||||
:on-change on-change
|
||||
:placeholder "boris.johnson@redneck.co.uk"
|
||||
:style {:margin-right "1em"}}]
|
||||
[:div.control
|
||||
[:a.button.is-link.has-background-primary {:href href
|
||||
:disabled disabled?} "login"]]
|
||||
[:div.control
|
||||
[:button.button.is-link.has-background-primary {:disabled disabled?
|
||||
:on-click #(create-user @login-field)} "create"]]]]]))))
|
||||
|
||||
|
||||
(defn page [state]
|
||||
[:h1 "Hello world sdjjksd dsklsd"])
|
||||
[:div
|
||||
[:section.section
|
||||
[:div.columns
|
||||
[:div.container
|
||||
[:img {:src "/images/amsterdam.svg"}]]]
|
||||
[:div.columns.is-centered
|
||||
[login state]]]])
|
||||
@@ -0,0 +1,67 @@
|
||||
(ns skirmish.wui.components.otc-page
|
||||
(:require [reagent.core :refer [atom]]
|
||||
[skirmish.wui.components.securities-page :refer [get-securities]]
|
||||
[skirmish.wui.util :refer [email?]]))
|
||||
|
||||
|
||||
(defn set-amount [state event]
|
||||
(let [inserted-value (-> event .-target .-value)
|
||||
new-value (first (re-find #"^\d+(\.\d*)?" inserted-value))]
|
||||
(swap! state #(assoc % :value new-value))))
|
||||
|
||||
(defn set-email [state event]
|
||||
(let [new-email (-> event .-target .-value)]
|
||||
(swap! state #(assoc % :email new-email))))
|
||||
|
||||
(defn set-sec-id [state event]
|
||||
(let [sec-id (-> event .-target .-value)]
|
||||
(swap! state #(assoc % :sec-id sec-id))))
|
||||
|
||||
|
||||
|
||||
(defn ready-to-transfer? [state]
|
||||
(and (-> state :value js/parseInt pos?)
|
||||
(-> state :email email?)))
|
||||
|
||||
|
||||
(defn select-securities-for [securities on-change]
|
||||
[:select {:on-change on-change}
|
||||
(for [security securities]
|
||||
[:option {:value (:sec-id security) :key (:sec-id security)} (:sec-id security)])])
|
||||
|
||||
|
||||
(defn select-security [on-change]
|
||||
(let [securities (atom [])]
|
||||
(get-securities securities)
|
||||
#(select-securities-for @securities on-change)))
|
||||
|
||||
(defn direct-send []
|
||||
(let [state (atom {})]
|
||||
(fn []
|
||||
[:div
|
||||
[:div.content
|
||||
[:p "Send securities to another person."]]
|
||||
[:form.form
|
||||
[:div.field.has-addons.has-addons-centered
|
||||
[:div.control
|
||||
[:span.select
|
||||
[select-security (partial set-sec-id state)]]]
|
||||
[:div.control
|
||||
[:input.input {:type "text"
|
||||
:value (:value @state)
|
||||
:on-change (partial set-amount state)
|
||||
:placeholder "110.90"}]]
|
||||
[:div.control
|
||||
[:input.input {:type "text"
|
||||
:value (:email @state)
|
||||
:on-change (partial set-email state)
|
||||
:placeholder "boris.johnson@redneck.co.uk"}]]
|
||||
[:a.button.is-primary {:style {:marginLeft "1em"}
|
||||
:disabled (-> @state ready-to-transfer? not)} "transfer"]]]])))
|
||||
|
||||
(defn page [state]
|
||||
[:div
|
||||
[:div.content
|
||||
[:h5 "Do transaction without passing by the exchange."]]
|
||||
|
||||
[direct-send]])
|
||||
@@ -0,0 +1,36 @@
|
||||
(ns skirmish.wui.components.portfolio-page
|
||||
(:require [reagent.core :refer [atom]]
|
||||
[cljs-http.client :as http]
|
||||
[skirmish.wui.components.face-value :refer [face-value]]
|
||||
[cljs.core.async :refer [<!] :refer-macros [go] :as async]
|
||||
[skirmish.wui.components.secunit :refer [secunit]]))
|
||||
|
||||
(defn make-portfolio-summary-table [portfolio]
|
||||
[:table
|
||||
[:thead
|
||||
[:tr [:th "Security"] [:th "Amount"] [:th "Face Value"]]]
|
||||
[:tbody
|
||||
(for [{sec-summary :account} portfolio]
|
||||
[:tr {:key (:account-public-key sec-summary)}
|
||||
[:td (:sec-id sec-summary)]
|
||||
[:td [secunit (:amount sec-summary) (-> sec-summary :sec-id keyword)]]
|
||||
[:td [face-value (:amount sec-summary) (-> sec-summary :sec-id keyword)]]])]])
|
||||
|
||||
|
||||
(defn get-accounts-information [urls a-accounts]
|
||||
(go
|
||||
(let [ar (async/merge (map #(http/get % {:with-credentials? false}) urls))
|
||||
accounts (map :body (<! (async/into [] ar)))]
|
||||
(reset! a-accounts accounts))))
|
||||
|
||||
(defn page-wrapper [accounts]
|
||||
[:div.content
|
||||
[:h5 "View all the assets you own."]
|
||||
[make-portfolio-summary-table accounts]])
|
||||
|
||||
|
||||
(defn page [{{accounts :skirmish.broker.user/accounts} :user}]
|
||||
(let [urls (map :skirmish.broker.account/url accounts)
|
||||
a-accounts (atom [])]
|
||||
(get-accounts-information urls a-accounts)
|
||||
#(page-wrapper @a-accounts)))
|
||||
@@ -0,0 +1,25 @@
|
||||
(ns skirmish.wui.components.secunit
|
||||
(:require [reagent.core :refer [atom]]
|
||||
[skirmish.wui.util :refer [pp-int]]
|
||||
[cljs-http.client :as http]
|
||||
[cljs.core.async :refer [<!] :refer-macros [go] :as async]))
|
||||
|
||||
|
||||
(defn get-security-definition [sec sec-id]
|
||||
(go
|
||||
(let [url (str "http://localhost:1604/api/1/ledger/securities/" (name sec-id))
|
||||
resp (<! (http/get url {:with-credentials? false}))]
|
||||
(reset! sec (:body resp)))))
|
||||
|
||||
|
||||
(defn- pp-amount [amount sec]
|
||||
(when (seq sec)
|
||||
(let [{sec-id :sec-id number-of-decimal :number-of-decimal symbol :symbol} sec
|
||||
href (str "/securities/" sec-id)]
|
||||
[:a {:href href} (pp-int amount (or number-of-decimal 0)) " "
|
||||
(or symbol "")])))
|
||||
|
||||
(defn secunit [amount sec-id]
|
||||
(let [sec (atom {})]
|
||||
(get-security-definition sec sec-id)
|
||||
#(pp-amount amount @sec)))
|
||||
@@ -1,4 +1,8 @@
|
||||
(ns skirmish.wui.components.securities-page)
|
||||
(ns skirmish.wui.components.securities-page
|
||||
(:require [cljs-http.client :as http]
|
||||
[cljs.core.async :refer [<!] :as async]
|
||||
[reagent.core :refer [atom]])
|
||||
(:require-macros [cljs.core.async.macros :refer [go]]))
|
||||
|
||||
(def table-head
|
||||
[:thead.has-background-grey-dark
|
||||
@@ -14,9 +18,71 @@
|
||||
[:td (:name sec)]
|
||||
[:td (:description sec)]]))
|
||||
|
||||
(defn get-all-securities-urls []
|
||||
(let [ret (async/chan)]
|
||||
(go (let [url "http://localhost:1604/api/1/ledger/securities"
|
||||
response (<! (http/get url {:with-credentials? false}))
|
||||
urls (map :url (get-in response [:body :securities]))]
|
||||
(async/onto-chan ret urls)))
|
||||
ret))
|
||||
|
||||
(defn get-all-securities []
|
||||
(let [ret (async/chan)
|
||||
urls (get-all-securities-urls)]
|
||||
(async/go-loop [url (async/<! urls)]
|
||||
(when-let [url (async/<! urls)]
|
||||
(async/go
|
||||
(let [sec (:body (<! (http/get url {:with-credentials? false})))]
|
||||
(println sec)
|
||||
(async/>! ret sec)))
|
||||
(recur url)))
|
||||
ret))
|
||||
|
||||
(defn get-securities [a-securities]
|
||||
(let [securities (get-all-securities)]
|
||||
(async/go-loop [security (async/<! securities)]
|
||||
(when (some? security)
|
||||
(swap! a-securities #(conj % security))
|
||||
(recur (async/<! securities))))))
|
||||
|
||||
|
||||
(defn create-currencies-table [securities]
|
||||
[:div
|
||||
[:div.content
|
||||
[:h3 "Currencies"]
|
||||
[:p "A " [:em "currency"] " is currency that pays interest rate in
|
||||
its own nomination."]]
|
||||
[:table.table.is-hoverable.is-fullwidth
|
||||
table-head
|
||||
[:tbody
|
||||
(for [sec securities :when (= (:type sec) "currency")] (create-row sec))]]])
|
||||
|
||||
(defn create-equities-table [securities]
|
||||
[:div
|
||||
[:div.content
|
||||
[:h3 "Equities"]
|
||||
[:p "An " [:em "equity"] " is a type of security that pays dividends. In
|
||||
real life, an equity (or stock) is a share in a company ownership.
|
||||
When the company make profits, it shares the its profits between its stock
|
||||
holder in a pro rata fashion."]]
|
||||
[:table.table.is-hoverable.is-fullwidth
|
||||
table-head
|
||||
[:tbody
|
||||
(for [sec securities :when (= (:type sec) "equity")] (create-row sec))]]])
|
||||
|
||||
(defn create-securities-table [securities]
|
||||
[:div
|
||||
[create-currencies-table securities]
|
||||
[:br]
|
||||
[create-equities-table securities]])
|
||||
|
||||
(defn security-table []
|
||||
(let [securities (atom [])]
|
||||
(get-securities securities)
|
||||
#(create-securities-table @securities)))
|
||||
|
||||
(defn page [state]
|
||||
(let [securities [{:sec-id :foo} {:sec-id :bar} {:sec-id :toto}]]
|
||||
[:table.table.is-hoverable.is-fullwidth
|
||||
table-head
|
||||
[:tbody
|
||||
(for [sec securities] (create-row sec))]]))
|
||||
[:div
|
||||
[:div.content
|
||||
[:h5 "View the available securities for trading."]]
|
||||
[security-table]])
|
||||
@@ -1,4 +1,42 @@
|
||||
(ns skirmish.wui.components.security-page)
|
||||
(ns skirmish.wui.components.security-page
|
||||
(:require [skirmish.wui.util :refer [pp-int]]
|
||||
[reagent.core :refer [atom]]
|
||||
[cljs-http.client :as http]
|
||||
[cljs.core.async :refer [<!] :refer-macros [go]]))
|
||||
|
||||
|
||||
(defn get-ledget-information [sec-info sec-id]
|
||||
(go
|
||||
(let [url (str "http://localhost:1604/api/1/ledger/securities/" (name sec-id))
|
||||
resp (<! (http/get url {:with-credentials? false}))]
|
||||
(reset! sec-info (:body resp)))))
|
||||
|
||||
|
||||
(defn create-ledger-table [sec-info]
|
||||
[:div
|
||||
[:h1 (:name sec-info)]
|
||||
[:cite (:description sec-info)]
|
||||
[:table
|
||||
[:tbody
|
||||
[:tr
|
||||
[:td "Security ID"] [:td (:sec-id sec-info)]]
|
||||
[:tr
|
||||
[:td "Type"] [:td (:type sec-info)]]
|
||||
(when-let [symbol (:symbol sec-info)]
|
||||
[:tr
|
||||
[:td "Symbol"] [:td symbol]])
|
||||
[:tr
|
||||
[:td "Interest Rate"] [:td (-> sec-info :interest-rate (pp-int 2) (str " %"))]]
|
||||
[:tr
|
||||
[:td "Total Volume"] [:td (-> sec-info :volume (pp-int (:number-of-decimal sec-info)) (str " " (:symbol sec-info)))]]]]])
|
||||
|
||||
|
||||
(defn ledger-table [sec-id]
|
||||
(let [sec-info (atom {})]
|
||||
(get-ledget-information sec-info sec-id)
|
||||
#(create-ledger-table @sec-info)))
|
||||
|
||||
|
||||
(defn page [state]
|
||||
[:h1 (str "this is a security page for " (:sec-id state))])
|
||||
[:div.content
|
||||
[ledger-table (:sec-id state)]])
|
||||
@@ -6,27 +6,53 @@
|
||||
|
||||
(def done {:style {:text-decoration "line-through"}})
|
||||
|
||||
|
||||
(defn filter-out-done [n]
|
||||
(let [state (volatile! n)]
|
||||
(fn [item]
|
||||
(when (= (second item) done)
|
||||
(vswap! state dec))
|
||||
(or (not= (second item) done) (neg? @state)))))
|
||||
|
||||
|
||||
(defn todo-list [& items]
|
||||
(let [filter-fn (filter-out-done (- (count items) 20))
|
||||
item-to-show (filter filter-fn items)]
|
||||
[:ol
|
||||
(for [item item-to-show]
|
||||
item)]))
|
||||
|
||||
(defn page []
|
||||
[:div.content
|
||||
[:ul
|
||||
[:li "shits"
|
||||
[:ul
|
||||
[:li "add a list of bogus securities"]]]
|
||||
[:li "kafka"
|
||||
[:ul
|
||||
[:li done "setup kafka"]
|
||||
[:li "try kafka streams"]
|
||||
[:li done "pass every order in kafka"]]]
|
||||
[:li "Logic"
|
||||
[:ul
|
||||
[:li done "les orders doivent inclurent les bornes"]
|
||||
[:li done "simplifier le spec des ordres en enlevant " [:code ":order/"]]
|
||||
[:li "finish insertion logic and test with spec"]
|
||||
[:li "link insertion logic to application"]]]
|
||||
[:li "User interface"
|
||||
[:ul
|
||||
[:li "Add logo"]
|
||||
[:li "Faire un ui pour sell limit order"]
|
||||
[:li "Faire un ui pour buy limit order"]
|
||||
[:li "Faire un ui pour sell market order"]
|
||||
[:li "Faire un ui pour buy market order"]]]]])
|
||||
[:h5 "This still to do in this project. This is a jira for the poor (or for the geek)."]
|
||||
[:ol
|
||||
[:li "Broker"
|
||||
[:p "the brooker should use the exchange-gateway and ledge as apis. Nothing else."]
|
||||
[todo-list
|
||||
[:li done "implement basic login in the wui"]
|
||||
[:li done "implement basic web server"]
|
||||
[:li done "implement stupid login on server side."]
|
||||
[:li done "link the logic of the client-server login logic"]
|
||||
[:li done "add the notion of 'accounts' in the server. An
|
||||
user should have many accounts; one for each security
|
||||
he owns"]
|
||||
[:li done "make the " [:a {:href "/portfolio"} "portfolio"] " page representing the use accounts"]
|
||||
[:li done "make a somewhat pretty " [:a {:href "/securities/dapm"} "security"] " page"]
|
||||
[:li done "create two stocks"]
|
||||
[:li done "add stocks to didier@gmail.com"]
|
||||
[:li done "make something for urls on the backend"]
|
||||
[:li done "add a wui for OTC"]
|
||||
[:li "fix the stupid chat. This is an important feature for OTC users."]
|
||||
[:li "make something that allows to send securities from one user to another"]
|
||||
[:li "move 'routes' in 'rest'"]
|
||||
[:li "add a little bit of professionalism on top of the broker api"]
|
||||
[:li "make the api support transit and edn"]
|
||||
[:li done "implements interest rate in ledger."]
|
||||
[:li done "Make sure the ledger can have accounts"]
|
||||
[:li done "when a new user signs in, he should receive some sort of money"]
|
||||
[:li "implement send securities to friends"]
|
||||
[:li "implement buy/sell securities."]
|
||||
[:li "Use ledger as source of through in each sub server."]
|
||||
[:li "Update web ui for integrating securities with ledger."]
|
||||
[:li "implement transactions in ledger."]
|
||||
[:li "implement escrow."]]]]])
|
||||
@@ -10,14 +10,38 @@
|
||||
"is-active"))
|
||||
|
||||
|
||||
(defn- user-dropdown [state]
|
||||
(when (:user @state)
|
||||
(let [icon [:i.fa.fa-sign-out {:aria-hidden true}]
|
||||
email (get-in @state [:user :skirmish.broker.user/email])]
|
||||
[:div.navbar-item.has-dropdown.is-hoverable
|
||||
[:a.navbar-link {} (str "[ " email " ]")]
|
||||
[:div.navbar-dropdown
|
||||
[:a.navbar-item {:href "/home/"} icon " logout"]]])))
|
||||
|
||||
|
||||
(defn- login [state]
|
||||
(let [icon [:i.fa.fa-sign-out {:aria-hidden true}]]
|
||||
[:a.navbar-item.is-tab {:href "/"} icon " login"]))
|
||||
|
||||
|
||||
(defn user-placeholder [state]
|
||||
(if (:user @state)
|
||||
[user-dropdown state]
|
||||
[login state]))
|
||||
|
||||
|
||||
(defn top-bar [state]
|
||||
[:nav.navbar.is-dark.is-boxed {:style {:margin-bottom "1em"}}
|
||||
[:div.container
|
||||
[:div.navbar-start
|
||||
[:a.navbar-item.is-tab {:href "/" :class (top-bar-class state :home)} "Home"]
|
||||
[:a.navbar-item.is-tab {:href "/securities" :class (top-bar-class state :securities)} "Securities"]
|
||||
[:a.navbar-item.is-tab {:href "/create-order" :class (top-bar-class state :create-order)} "Create order"]
|
||||
[:a.navbar-item.is-tab {:href "/portfolio" :class (top-bar-class state :view-portfolio)} "View Portfolio"]
|
||||
[:a.navbar-item.is-tab {:href "/create-order" :class (top-bar-class state :create-order)} "Create Order"]
|
||||
[:a.navbar-item.is-tab {:href "/otc" :class (top-bar-class state :otc)} "Over The Counter"]
|
||||
[:a.navbar-item.is-tab {:href "/portfolio" :class (top-bar-class state :view-portfolio)} "Portfolio"]
|
||||
[:a.navbar-item.is-tab {:href "/users" :class (top-bar-class state :users)} "Users"]
|
||||
[:a.navbar-item.is-tab {:href "/todo" :class (top-bar-class state :todo)} "Todo"]]
|
||||
[:div.navbar-end
|
||||
[:a.navbar-item.is-tab {} "Skirmish Shitty Exchange"]]]])
|
||||
[:a.navbar-item {} "Skirmish Shitty Exchange"]
|
||||
[user-placeholder state]]]])
|
||||
@@ -0,0 +1,41 @@
|
||||
(ns skirmish.wui.components.users-page
|
||||
(:require [cljs-http.client :as http]
|
||||
[cljs.core.async :refer [<!] :as async]
|
||||
[reagent.core :refer [atom]])
|
||||
(:require-macros [cljs.core.async.macros :refer [go]]))
|
||||
|
||||
|
||||
(def users-table-headers
|
||||
[:thead.has-background-grey-dark
|
||||
[:tr
|
||||
[:th.has-text-white-bis "User email"]
|
||||
[:th.has-text-white-bis "Public wallet id"]]])
|
||||
|
||||
|
||||
(defn create-row [user]
|
||||
[:tr.has-text-white-bis {:key (:email user)}
|
||||
[:td (:email user)]
|
||||
[:td "key"]])
|
||||
|
||||
(defn create-users-table [users]
|
||||
[:table.table.is-hoverable.is-fullwidth
|
||||
users-table-headers
|
||||
[:tbody
|
||||
(map create-row users)]])
|
||||
|
||||
(defn get-users [users-a]
|
||||
(go
|
||||
(let [url "http://localhost:1605/api/1/users"
|
||||
resp (<! (http/get url))]
|
||||
(reset! users-a (-> resp :body :users)))))
|
||||
|
||||
(defn users-table []
|
||||
(let [users (atom [])]
|
||||
(get-users users)
|
||||
#(create-users-table @users)))
|
||||
|
||||
(defn page [state]
|
||||
[:div
|
||||
[:div.content
|
||||
[:h5 "Users"]
|
||||
[users-table]]])
|
||||
@@ -3,6 +3,8 @@
|
||||
[skirmish.wui.pages :as pages]
|
||||
[skirmish.wui.components.topbar :refer [top-bar]]
|
||||
[reagent.session :as session]
|
||||
[cljs-http.client :as http]
|
||||
[cljs.core.async :refer [<!] :refer-macros [go]]
|
||||
[secretary.core :as secretary :include-macros true]
|
||||
[accountant.core :as accountant]))
|
||||
|
||||
@@ -12,7 +14,16 @@
|
||||
|
||||
(defonce state (atom {}))
|
||||
|
||||
|
||||
(defn login [email]
|
||||
(go (let [resp (<! (http/get (str "http://localhost:1605/api/1/users/" email)))]
|
||||
(if (= (:status resp) 200)
|
||||
(do
|
||||
(println "Logging in as:" (-> resp :body type))
|
||||
(session/put! :current-page #'pages/home-page)
|
||||
(swap! state #(into % {:page :home :user (:body resp)})))
|
||||
(do
|
||||
(println "Cannot log in as" email)
|
||||
(swap! state #(dissoc % :user)))))))
|
||||
|
||||
;; -------------------------
|
||||
;; Routes
|
||||
@@ -26,10 +37,37 @@
|
||||
(session/put! :current-page #'pages/home-page)
|
||||
(swap! state #(into % {:page :home})))
|
||||
|
||||
(secretary/defroute "/home/:email" [email]
|
||||
(login email))
|
||||
|
||||
(secretary/defroute "/home/" []
|
||||
(session/put! :current-page #'pages/home-page)
|
||||
(swap! state #(into % {:page :home :user nil})))
|
||||
|
||||
(secretary/defroute "/users" []
|
||||
(session/put! :current-page #'pages/users-page)
|
||||
(swap! state #(into % {:page :users})))
|
||||
|
||||
(secretary/defroute "/securities" []
|
||||
(session/put! :current-page #'pages/securities-page)
|
||||
(swap! state #(into % {:page :securities})))
|
||||
|
||||
(secretary/defroute "/portfolio" []
|
||||
(session/put! :current-page #'pages/portfolio-page)
|
||||
(swap! state #(into % {:page :portfolio})))
|
||||
|
||||
(secretary/defroute "/otc" []
|
||||
(session/put! :current-page #'pages/otc-page)
|
||||
(swap! state #(into % {:page :otc})))
|
||||
|
||||
|
||||
|
||||
(secretary/defroute "/create-order" []
|
||||
(session/put! :current-page #'pages/create-order-page)
|
||||
(swap! state #(into % {:page :create-order})))
|
||||
|
||||
|
||||
|
||||
(secretary/defroute "/securities/:sec-id" [sec-id]
|
||||
(session/put! :current-page #'pages/security-page)
|
||||
(swap! state #(into % {:page :securities :sec-id (keyword sec-id)})))
|
||||
@@ -41,13 +79,14 @@
|
||||
(defn current-page []
|
||||
"This is the basic page setup."
|
||||
[:div
|
||||
(top-bar state)
|
||||
[top-bar state]
|
||||
[:div
|
||||
[:div.columns
|
||||
[:div.column.is-8.is-offset-2
|
||||
[(session/get :current-page) @state]]]]])
|
||||
|
||||
|
||||
|
||||
(defn mount-root []
|
||||
(reagent/render [current-page] (.getElementById js/document "app")))
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
(ns skirmish.wui.pages
|
||||
(:require [skirmish.wui.components.todo-page]
|
||||
[skirmish.wui.components.home-page]
|
||||
[skirmish.wui.components.portfolio-page]
|
||||
[skirmish.wui.components.create-order-page]
|
||||
[skirmish.wui.components.securities-page]
|
||||
[skirmish.wui.components.security-page]))
|
||||
[skirmish.wui.components.security-page]
|
||||
[skirmish.wui.components.otc-page]
|
||||
[skirmish.wui.components.users-page]))
|
||||
|
||||
(def home-page skirmish.wui.components.home-page/page)
|
||||
|
||||
@@ -10,4 +14,12 @@
|
||||
|
||||
(def securities-page skirmish.wui.components.securities-page/page)
|
||||
|
||||
(def create-order-page skirmish.wui.components.create-order-page/page)
|
||||
|
||||
(def portfolio-page skirmish.wui.components.portfolio-page/page)
|
||||
|
||||
(def security-page skirmish.wui.components.security-page/page)
|
||||
|
||||
(def otc-page skirmish.wui.components.otc-page/page)
|
||||
|
||||
(def users-page skirmish.wui.components.users-page/page)
|
||||
@@ -0,0 +1,34 @@
|
||||
(ns skirmish.wui.util)
|
||||
|
||||
(defn right-pad [s o n]
|
||||
"right pad s with o until length is greater or
|
||||
equal to n."
|
||||
(if (<= n (count s))
|
||||
s
|
||||
(recur (str s o) o n)))
|
||||
|
||||
(defn left-pad [s o n]
|
||||
"left pad s with o until length is greater or
|
||||
equal to n."
|
||||
(if (<= n (count s))
|
||||
s
|
||||
(recur (str o s) o n)))
|
||||
|
||||
(defn pp-int
|
||||
"returns the string representing n with the spaces at
|
||||
the proper place."
|
||||
([n]
|
||||
(cond
|
||||
(neg? n) (str "-" (pp-int (- n)))
|
||||
(< n 1000) (str n)
|
||||
:else (str (pp-int (quot n 1000)) " " (left-pad (str (mod n 1000)) "0" 3))))
|
||||
([n dec]
|
||||
(if (<= dec 0)
|
||||
(pp-int n)
|
||||
(let [i (int (Math/pow 10 dec))]
|
||||
(str (pp-int (quot n i)) "," (right-pad (str (mod n i)) "0" dec))))))
|
||||
|
||||
(defn email? [s]
|
||||
(let [email-pattern #"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"]
|
||||
(->> s str (re-matches email-pattern) some?)))
|
||||
|
||||
+13
-1
@@ -8,15 +8,27 @@
|
||||
|
||||
@import "../../node_modules/bulma/sass/utilities/_all";
|
||||
|
||||
// main color changes
|
||||
$background: $black;
|
||||
$body-background-color: $black;
|
||||
$text: $white-ter;
|
||||
$link: $turquoise;
|
||||
|
||||
// navbar color change
|
||||
$navbar-dropdown-background-color: $grey-darker;
|
||||
$navbar-dropdown-border-top: 1px solid $turquoise !default;
|
||||
$navbar-dropdown-item-hover-color: none;
|
||||
$navbar-dropdown-item-hover-background-color: $grey-darker;
|
||||
|
||||
// table color changes
|
||||
$table-background-color: $grey-dark;
|
||||
$table-cell-heading-color: $grey-darker;
|
||||
$border: $yellow;
|
||||
$table-row-hover-background-color: $black-ter;
|
||||
|
||||
// box
|
||||
$box-background-color: $grey;
|
||||
$box-color: $white;
|
||||
$box-shadow: 0 2px 3px $grey-light, 0 0 0 1px $grey-light;// $red;
|
||||
|
||||
@import "../../node_modules/bulma/sass/base/_all";
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
(ns skirmish.broker.broker-test
|
||||
(:require [midje.sweet :refer :all]
|
||||
[orchestra.spec.test :as st]
|
||||
[skirmish.broker.broker :refer [add-account-urls
|
||||
create-user-seed-from-email
|
||||
generate-amount-for-new-user]]))
|
||||
|
||||
(st/instrument)
|
||||
|
||||
|
||||
(facts "the broker util functions"
|
||||
(fact "it should be able to add url to accounts"
|
||||
(let [user {:skirmish.broker.user/accounts [{:skirmish.broker.account/id "foo"}]}
|
||||
ret {:skirmish.broker.user/accounts [{:skirmish.broker.account/id "foo"
|
||||
:skirmish.broker.account/url "http://localhost:1604/api/1/ledger/accounts/foo"}]}]
|
||||
(add-account-urls user) => ret)))
|
||||
|
||||
(facts "about the new users"
|
||||
(fact "we should add some random amount of damp in their account"
|
||||
(let [random-values (map generate-amount-for-new-user (range 10000))
|
||||
sum (reduce + random-values)
|
||||
mean (/ sum (count random-values))
|
||||
min-data (apply min random-values)
|
||||
max-data (apply max random-values)]
|
||||
(int mean) => 100027427
|
||||
min-data => 78422400
|
||||
max-data => 120128000))
|
||||
|
||||
(fact "we should generate the random seed by the email"
|
||||
(create-user-seed-from-email "foo@gmail.com") => 399122929
|
||||
(create-user-seed-from-email "boo@gmail.com") => 1433675645))
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
(ns skirmish.broker.db-test
|
||||
(:require [midje.sweet :refer :all]
|
||||
[orchestra.spec.test :as st]
|
||||
[datomic.api :as d]
|
||||
[skirmish.broker.db :refer [create-connection]]
|
||||
[skirmish.broker.broker :refer [create-account]]))
|
||||
|
||||
(st/instrument)
|
||||
|
||||
(defn create-conn []
|
||||
(let [mem-url "datomic:mem://skirmish"]
|
||||
(d/delete-database mem-url)
|
||||
(create-connection mem-url)))
|
||||
|
||||
(facts "about the db functions."
|
||||
(fact "should be able to create new users"
|
||||
(let [conn (create-conn)
|
||||
email "foo@gmail.com"
|
||||
account-id #uuid"dc0d1123-e659-4e8a-b38b-ece520f4c4d0"
|
||||
account (create-account account-id :dapm)
|
||||
_ @(d/transact conn [[:skirmish.broker.user/create-user email account]])
|
||||
db (d/db conn)
|
||||
user (d/pull db '[* {:skirmish.broker.user/accounts [*]}] [:skirmish.broker.user/email email])]
|
||||
(:skirmish.broker.user/email user) => email
|
||||
(-> user :skirmish.broker.user/accounts first :skirmish.broker.account/id) => account-id)))
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
(ns skirmish.exchange.exchange-test
|
||||
(:import [skirmish.PersistentSortedList])
|
||||
(:import (skirmish PersistentSortedList))
|
||||
(:require [midje.sweet :refer :all]
|
||||
[orchestra.spec.test :as st]
|
||||
[skirmish.order]
|
||||
[skirmish.exchange.exchange :refer :all]
|
||||
[skirmish.exchange.match :refer [create-buy-book
|
||||
create-sell-book
|
||||
@@ -9,7 +10,7 @@
|
||||
|
||||
(st/instrument)
|
||||
|
||||
(def PersistentSortedList? (comp #(= % skirmish.PersistentSortedList) type))
|
||||
(def PersistentSortedList? (comp #(= % PersistentSortedList) type))
|
||||
|
||||
(facts "the exchange as an whole"
|
||||
(fact "process-sell-order should work when book empty"
|
||||
File renamed without changes.
@@ -0,0 +1,316 @@
|
||||
(ns skirmish.ledger.test-core
|
||||
(:require [midje.sweet :refer :all]
|
||||
[skirmish.ledger.data-layer :as data-layer]
|
||||
[skirmish.ledger.controllers :as controllers]
|
||||
[skirmish.ledger.accounts :refer [create-connection schema]]
|
||||
[skirmish.rest.util :refer [build-response]]
|
||||
[skirmish.ledger.core :refer :all]
|
||||
[skirmish.rest.util :refer [edn->stream]]
|
||||
[datomic.api :as d]
|
||||
[clojure.edn]
|
||||
[clojure.spec.alpha :as s]
|
||||
[infix.macros :refer [infix]]))
|
||||
|
||||
|
||||
(defn spec-check [spec]
|
||||
#(s/valid? spec %))
|
||||
|
||||
(defn body [resp]
|
||||
(-> resp :body clojure.edn/read-string))
|
||||
|
||||
(s/def ::ok #(<= 200 (:status %) 299))
|
||||
|
||||
(s/def ::status-404 #(= (:status %) 404))
|
||||
|
||||
(s/def ::status-400 #(= (:status %) 400))
|
||||
|
||||
|
||||
(defn create-conn []
|
||||
(let [mem-url "datomic:mem://skirmish"]
|
||||
(d/delete-database mem-url)
|
||||
(create-connection mem-url false)))
|
||||
|
||||
|
||||
|
||||
(defn location? [path]
|
||||
#(-> % :headers (get "location") (clojure.string/ends-with? path)))
|
||||
|
||||
|
||||
(def sec->hash-set #(apply hash-set %))
|
||||
|
||||
(def mock-securities [[:sec-1 100 :equity "first equity" "rot13"]
|
||||
[:sec-2 200 :equity "second equity" "rot13"]
|
||||
[:sec-3 300 :equity "third equity" "rot13"]])
|
||||
|
||||
(def mock-currencies [[:zimbabwean-dollar 1000000 :currency "zimbabwean dollar" "rot13" "zd"]])
|
||||
|
||||
;;
|
||||
(defn create-some-securities [conn]
|
||||
(let [cs (controllers/create-security conn)
|
||||
create-security-1 {:body (edn->stream (get mock-securities 0)) :headers {"accept" "application/edn"}}
|
||||
create-security-2 {:body (edn->stream (get mock-securities 1)) :headers {"accept" "application/edn"}}
|
||||
create-security-3 {:body (edn->stream (get mock-securities 2)) :headers {"accept" "application/edn"}}
|
||||
create-security-4 {:body (edn->stream (first mock-currencies)) :headers {"accept" "application/edn"}}]
|
||||
(->> create-security-1 cs (s/assert ::ok))
|
||||
(->> create-security-2 cs (s/assert ::ok))
|
||||
(->> create-security-3 cs (s/assert ::ok))
|
||||
(->> create-security-4 cs (s/assert ::ok))
|
||||
conn))
|
||||
|
||||
(defn create-some-accounts [conn n]
|
||||
(let [create-emit-req (fn [amount account-id sec-id] {:body (edn->stream [amount account-id]) :route-params {:sec-id sec-id}})
|
||||
sec-1-reqs (for [i (range 1 (inc n))] (create-emit-req (* i 100) (str i "-sec-1") "sec-1"))
|
||||
sec-2-reqs (for [i (range 1 (inc n))] (create-emit-req (* i 100) (str i "-sec-2") "sec-2"))
|
||||
reqs (concat sec-1-reqs sec-2-reqs)]
|
||||
(loop [reqs reqs]
|
||||
(when (seq reqs)
|
||||
(let [es (controllers/emit-securities conn)
|
||||
req (first reqs)]
|
||||
(->> req es (s/assert ::ok))
|
||||
(recur (rest reqs)))))
|
||||
conn))
|
||||
|
||||
|
||||
(defn create-some-securities-and-accounts [conn n-accounts-by-currency]
|
||||
(-> conn create-some-securities (create-some-accounts n-accounts-by-currency)))
|
||||
|
||||
|
||||
(facts "about the securities"
|
||||
(fact "We should be able to create a security"
|
||||
(let [conn (create-conn)
|
||||
security [:new-currency 100 :currency "currency for test" "rot13" "NC"]
|
||||
request {:body (edn->stream security) :headers {"accept" "application/edn"}}
|
||||
resp ((controllers/create-security conn) request)]
|
||||
resp => (spec-check ::ok)
|
||||
resp => (location? "/api/1/ledger/securities/new-currency")))
|
||||
|
||||
(fact "We should not be able to create a security that already exists"
|
||||
(let [conn (create-conn)
|
||||
security [:new-currency 100 :currency "currency for test" "rot13" "NC"]
|
||||
request {:body (edn->stream security) :headers {"accept" "application/edn"}}
|
||||
resp-1 ((controllers/create-security conn) request)
|
||||
resp-2 ((controllers/create-security conn) request)]
|
||||
resp-1 => (spec-check ::ok)
|
||||
resp-2 => (spec-check ::status-400)))
|
||||
|
||||
(fact "We should be able to update a security when it exists"
|
||||
:todo => :todo)
|
||||
|
||||
(fact "we should be able to get-security if it does exists"
|
||||
(let [conn (create-conn)
|
||||
security [:new-currency 100 :currency "currency for test" "rot13" "NC"]
|
||||
create-request {:body (edn->stream security) :headers {"accept" "application/edn"}}
|
||||
_ ((controllers/create-security conn) create-request)
|
||||
request {:route-params {:sec-id :new-currency} :headers {"accept" "application/edn"}}
|
||||
resp ((controllers/get-security conn) request)
|
||||
expt {:sec-id :new-currency
|
||||
:interest-rate 100
|
||||
:name nil
|
||||
:description nil
|
||||
:number-of-decimal nil
|
||||
:symbol nil
|
||||
:type nil
|
||||
:volume 0}]
|
||||
resp => (spec-check ::ok)
|
||||
(body resp) => (contains expt)))
|
||||
|
||||
(fact "we should not be able to get-security if it does not exists"
|
||||
(let [conn (create-conn)
|
||||
request {:route-params {:sec-id :new-currency} :headers {"accept" "application/edn"}}
|
||||
resp ((controllers/get-security conn) request)]
|
||||
resp => (spec-check ::status-404)
|
||||
resp => #(-> % :sec-id nil?)))
|
||||
|
||||
(fact "we should be able to get a list of all securities"
|
||||
(let [conn (create-conn)
|
||||
request {:route-params {} :headers {"accept" "application/edn"}}
|
||||
empty-res ((controllers/get-available-securities conn) request)
|
||||
new-currency [:new-currency 100 :currency "currency for test" "rot13" "NC"]
|
||||
create-security-1 {:body (edn->stream new-currency) :headers {"accept" "application/edn"}}
|
||||
_ ((controllers/create-security conn) create-security-1)
|
||||
one-res ((controllers/get-available-securities conn) request)]
|
||||
empty-res => (spec-check ::ok)
|
||||
one-res => (spec-check ::ok)
|
||||
(body empty-res) => {:securities []}
|
||||
(body one-res) => {:securities [{:sec-id :new-currency :url "http://localhost:1604/api/1/ledger/securities/new-currency"}]}))
|
||||
|
||||
(fact "it should add default currencies when creating new db"
|
||||
(let [mem-url "datomic:mem://skirmish-in-test"
|
||||
_ (d/delete-database mem-url)
|
||||
conn (create-connection mem-url true)
|
||||
request {:route-params {} :headers {"accept" "application/edn"}}
|
||||
resp ((controllers/get-available-securities conn) request)]
|
||||
(->> resp body :securities (map :sec-id) sort) => [:apac :apax :apbm :apdr :apmh :dapm])))
|
||||
|
||||
|
||||
(facts "about the emitting securities"
|
||||
(fact "should not work if invalid request"
|
||||
(let [conn (create-some-securities (create-conn))
|
||||
req-1 {:body (edn->stream [10 :not-a-string]) :route-params {:sec-id "sec-1"} :headers {"accept" "application/edn"}}
|
||||
req-2 {:body (edn->stream [-10 "foo"]) :route-params {:sec-id "sec-1"} :headers {"accept" "application/edn"}}
|
||||
req-3 {:body (edn->stream [90 "account-id"]) :route-params {:sec-id "invalid-sec-id"} :headers {"accept" "application/edn"}}]
|
||||
((controllers/emit-securities conn) req-1) => (spec-check ::status-400)
|
||||
((controllers/emit-securities conn) req-2) => (spec-check ::status-400)
|
||||
((controllers/emit-securities conn) req-3) => (spec-check ::status-404)))
|
||||
|
||||
(fact "should create new account if targeted account does not exists"
|
||||
(let [conn (create-some-securities (create-conn))
|
||||
get-account-req {:route-params {:account-id "new-account-id"} :headers {"accept" "application/edn"}}
|
||||
emit-sec-req {:body (edn->stream [90 "new-account-id"]) :route-params {:sec-id "sec-1"} :headers {"accept" "application/edn"}}]
|
||||
((controllers/get-account conn) get-account-req) => (spec-check ::status-404)
|
||||
((controllers/emit-securities conn) emit-sec-req) => (spec-check ::ok)
|
||||
(body ((controllers/get-account conn) get-account-req)) => #(-> % :account :amount (= 90))))
|
||||
|
||||
(fact "should add to account if targeted account exists"
|
||||
(let [conn (create-some-securities (create-conn))
|
||||
get-account-req {:route-params {:account-id "new-account-id"} :headers {"accept" "application/edn"}}
|
||||
emit-sec-req-1 {:body (edn->stream [90 "new-account-id"]) :route-params {:sec-id "sec-1"} :headers {"accept" "application/edn"}}
|
||||
emit-sec-req-2 {:body (edn->stream [100 "new-account-id"]) :route-params {:sec-id "sec-1"} :headers {"accept" "application/edn"}}]
|
||||
((controllers/get-account conn) get-account-req) => (spec-check ::status-404)
|
||||
((controllers/emit-securities conn) emit-sec-req-1) => (spec-check ::ok)
|
||||
((controllers/emit-securities conn) emit-sec-req-2) => (spec-check ::ok)
|
||||
(body ((controllers/get-account conn) get-account-req)) => #(-> % :account :amount (= 190)))))
|
||||
|
||||
|
||||
(facts "about accounts"
|
||||
(fact "we should be able to get list of all accounts"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 2)
|
||||
req {:route-params {} :headers {"accept" "application/edn"}}
|
||||
expt #{{:account-public-key "1-sec-1" :url "http://localhost:1604/api/1/ledger/accounts/1-sec-1"}
|
||||
{:account-public-key "1-sec-2" :url "http://localhost:1604/api/1/ledger/accounts/1-sec-2"}
|
||||
{:account-public-key "2-sec-1" :url "http://localhost:1604/api/1/ledger/accounts/2-sec-1"}
|
||||
{:account-public-key "2-sec-2" :url "http://localhost:1604/api/1/ledger/accounts/2-sec-2"}}]
|
||||
((controllers/get-available-accounts conn) req) => (spec-check ::ok)
|
||||
(-> ((controllers/get-available-accounts conn) req) body :accounts) => (just expt)))
|
||||
|
||||
(fact "we should be able to get account"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||
req {:route-params {:account-id "2-sec-1"} :headers {"accept" "application/edn"}}]
|
||||
((controllers/get-account conn) req) => (spec-check ::ok)
|
||||
(body ((controllers/get-account conn) req)) => {:account {:account-public-key "2-sec-1" :amount 200 :sec-id :sec-1}
|
||||
:sec-url "/api/1/ledger/securities/sec-1"}))
|
||||
|
||||
(fact "the interest should be payed when getting the account"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||
req {:route-params {:account-id "2-sec-1"} :headers {"accept" "application/edn"}}]
|
||||
((controllers/get-account conn) req) => (spec-check ::ok)
|
||||
(body ((controllers/get-account conn) req)) => {:account {:account-public-key "2-sec-1" :amount 200 :sec-id :sec-1}
|
||||
:sec-url "/api/1/ledger/securities/sec-1"}))
|
||||
|
||||
|
||||
(fact "we should not get an account if it does not exists"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||
req {:route-params {:account-id "2-sec-10"} :headers {"accept" "application/edn"}}]
|
||||
((controllers/get-account conn) req) => (spec-check ::status-404))))
|
||||
|
||||
|
||||
(facts "about interest computation"
|
||||
(fact "about very basic interest rates"
|
||||
(let [amount 1000
|
||||
interest-rate (* 10 100) ;; daily 10% interest rates
|
||||
negative-interest-rate (- interest-rate)
|
||||
start #inst"2020-09-05T00:00:00.000-00:00"
|
||||
start+1d #inst"2020-09-06T00:00:00.000-00:00"
|
||||
start+2d #inst"2020-09-07T00:00:00.000-00:00"]
|
||||
(data-layer/compute-simple-face-value amount interest-rate start start) => (roughly amount)
|
||||
(data-layer/compute-simple-face-value amount interest-rate start start+1d) => (roughly 1105.1670808)
|
||||
(data-layer/compute-simple-face-value amount interest-rate start start+2d) => (roughly 1221.3942766)
|
||||
(data-layer/compute-simple-face-value amount negative-interest-rate start start+2d) => (roughly 818.7250672)
|
||||
(data-layer/compute-simple-face-value amount 0 start start+2d) => (roughly amount)))
|
||||
(fact "split-interest-rates"
|
||||
(let [d-1d #inst"2020-09-04T00:00:00.000-00:00"
|
||||
d-½d #inst"2020-09-04T12:00:00.000-00:00"
|
||||
d #inst"2020-09-05T00:00:00.000-00:00"
|
||||
d+½d #inst"2020-09-05T12:00:00.000-00:00"
|
||||
d+1d #inst"2020-09-06T00:00:00.000-00:00"
|
||||
d+1½d #inst"2020-09-06T12:00:00.000-00:00"
|
||||
d+2d #inst"2020-09-07T00:00:00.000-00:00"
|
||||
d+2½d #inst"2020-09-07T12:00:00.000-00:00"
|
||||
d+3d #inst"2020-09-08T00:00:00.000-00:00"
|
||||
d+3½d #inst"2020-09-08T12:00:00.000-00:00" ;;
|
||||
interest-rates [[10 d] [15 d+1d] [20 d+2d]]]
|
||||
(data-layer/split-interest-rates interest-rates d+½d d+3d) => [[10 d+½d d+1d] [15 d+1d d+2d] [20 d+2d d+3d]]
|
||||
(data-layer/split-interest-rates interest-rates d+3d d+3½d) => [[20 d+3d d+3½d]]
|
||||
(data-layer/split-interest-rates interest-rates d-1d d-½d) => [[0 d-1d d-½d]]
|
||||
(data-layer/split-interest-rates interest-rates d d+½d) => [[10 d d+½d]]
|
||||
(data-layer/split-interest-rates interest-rates d+2½d d+2½d) => [[20 d+2½d d+2½d]]))
|
||||
(fact "compute-face-value"
|
||||
(let [d-1d #inst"2020-09-04T00:00:00.000-00:00"
|
||||
d-½d #inst"2020-09-04T12:00:00.000-00:00"
|
||||
d #inst"2020-09-05T00:00:00.000-00:00"
|
||||
d+½d #inst"2020-09-05T12:00:00.000-00:00"
|
||||
d+1d #inst"2020-09-06T00:00:00.000-00:00"
|
||||
d+1½d #inst"2020-09-06T12:00:00.000-00:00"
|
||||
d+2d #inst"2020-09-07T00:00:00.000-00:00"
|
||||
d+2½d #inst"2020-09-07T12:00:00.000-00:00"
|
||||
d+3d #inst"2020-09-08T00:00:00.000-00:00"
|
||||
d+3½d #inst"2020-09-08T12:00:00.000-00:00"
|
||||
amount 10000000
|
||||
interest-rates [[10 d] [15 d+1d] [20 d+2d]]]
|
||||
(data-layer/compute-face-value amount interest-rates d+½d d+½d) => amount
|
||||
(data-layer/compute-face-value amount interest-rates d-1d d-½d) => amount
|
||||
(data-layer/compute-face-value amount interest-rates d-1d d+3d) => 10045101))
|
||||
(fact "we had bugs... we need to fix them"
|
||||
(let [deposit-date #inst"2020-09-09T18:49:47.205-00:00"
|
||||
value-date #inst"2020-09-09T18:52:56.760-00:00"
|
||||
amount 105402100
|
||||
interest-rates (list [1000 #inst "2020-09-09T18:47:34.152-00:00"])]
|
||||
(data-layer/compute-face-value amount interest-rates deposit-date value-date) => 105424060)))
|
||||
|
||||
|
||||
;; 4. transfer sec from one account to the other.
|
||||
|
||||
(defn get-account-eids [db & owner-public-keys]
|
||||
(let [q (map #(vector :skirmish.ledger/owner-public-key %) owner-public-keys)
|
||||
ret (d/pull-many db '[:db/id] q)]
|
||||
(map :db/id ret)))
|
||||
|
||||
(facts "about transactions"
|
||||
(fact "about transferring an amount from one wallet to another"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||
transaction {:from-account-id "1-sec-1"
|
||||
:to-account-id "2-sec-1"
|
||||
:amount 50}
|
||||
db (d/db conn)
|
||||
[eid1 eid2] (get-account-eids db "1-sec-1" "2-sec-1")
|
||||
expt #{[:db/add eid1 :skirmish.ledger/amount 50]
|
||||
[:db/add eid2 :skirmish.ledger/amount 250]}]
|
||||
(data-layer/create-transactions db [transaction]) => (just expt)))
|
||||
(fact "about transferring an amount from one wallet to another"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||
transaction {:from-account-id "1-sec-1"
|
||||
:to-account-id "1-sec-1"
|
||||
:amount 45}
|
||||
db (d/db conn)
|
||||
[eid1] (get-account-eids db "1-sec-1")
|
||||
expt #{[:db/add eid1 :skirmish.ledger/amount 100]}]
|
||||
(data-layer/create-transactions db [transaction]) => (just expt)))
|
||||
(fact "about transferring amounts between three wallets"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||
transaction-1 {:from-account-id "1-sec-1"
|
||||
:to-account-id "2-sec-1"
|
||||
:amount 50}
|
||||
transaction-2 {:from-account-id "2-sec-1"
|
||||
:to-account-id "3-sec-1"
|
||||
:amount 250}
|
||||
db (d/db conn)
|
||||
[eid1 eid2 eid3] (get-account-eids db "1-sec-1" "2-sec-1" "3-sec-1")
|
||||
expt #{[:db/add eid1 :skirmish.ledger/amount 50]
|
||||
[:db/add eid2 :skirmish.ledger/amount 0]
|
||||
[:db/add eid3 :skirmish.ledger/amount 550]}]
|
||||
(data-layer/create-transactions db [transaction-1 transaction-2]) => (just expt)))
|
||||
(fact "about transaction between different assets types"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||
transaction {:from-account-id "1-sec-1"
|
||||
:to-account-id "1-sec-2"
|
||||
:amount 50}
|
||||
db (d/db conn)]
|
||||
(data-layer/create-transactions db [transaction]) => (throws #"different underlying securities")))
|
||||
(fact "about transaction with negative results"
|
||||
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||
transaction {:from-account-id "1-sec-1"
|
||||
:to-account-id "2-sec-1"
|
||||
:amount 500}
|
||||
db (d/db conn)]
|
||||
(data-layer/create-transactions db [transaction]) => (throws #"negative amount in a wallet"))))
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
(ns skirmish.middleware.test-core
|
||||
(:require [midje.sweet :refer :all]
|
||||
[clojure.core.async :refer [>!! <!!] :as async]
|
||||
[skirmish.middleware.core :refer :all]))
|
||||
|
||||
(defn all? [xf]
|
||||
#(every? true? (sequence xf %)))
|
||||
|
||||
(facts "we should have a async/chan base middleware for developing."
|
||||
(fact "It should exchanges for each security in the config"
|
||||
(let [config {}
|
||||
securities [{:sec-id :molly :type :equity} {:sec-id :pepper :type :currency} {:sec-id :molly :type :equity :disabled true}]
|
||||
securities-exchange (create-securities-api-for config)
|
||||
securities-submitter (:securities-submitter securities-exchange)
|
||||
exchanges-mult (create-exchange-apis-for config securities-exchange)
|
||||
exchanges (async/chan)
|
||||
sec-id-and-disabled (juxt :sec-id :disabled)]
|
||||
(async/tap exchanges-mult exchanges)
|
||||
(>!! securities-submitter (first securities))
|
||||
|
||||
(-> exchanges <!! sec-id-and-disabled) => [:molly false]
|
||||
(>!! securities-submitter (second securities))
|
||||
(-> exchanges <!! sec-id-and-disabled) => [:pepper false]
|
||||
(>!! securities-submitter (last securities))
|
||||
(-> exchanges <!! sec-id-and-disabled) => [:molly true])))
|
||||
File renamed without changes.
@@ -0,0 +1,30 @@
|
||||
(ns skirmish.routes.test-api
|
||||
(:require [midje.sweet :refer :all]
|
||||
[skirmish.routes.api :refer :all]))
|
||||
|
||||
(def my-ledger-routes {
|
||||
:name :ledger
|
||||
:path "/api/1/ledger"
|
||||
:routes [{:name :home :path "/"}
|
||||
{:name :accounts :path "/accounts"}
|
||||
{:name :account :path "/accounts/:account-id"}]})
|
||||
(def wui-routes {
|
||||
:name :wui
|
||||
:domain "http://localhost:1534"
|
||||
:path "/api/1/wui"
|
||||
:routes [{:name :home :path "/home"}]})
|
||||
|
||||
|
||||
(def my-all-routes [my-ledger-routes wui-routes])
|
||||
|
||||
(facts "About routes"
|
||||
(fact "it should be easy to get routes"
|
||||
(get-compojure-path my-all-routes :ledger/accounts) => "/accounts")
|
||||
|
||||
(fact "it should be able to retrieve routes"
|
||||
(get-path-for my-all-routes :ledger/accounts) => "/api/1/ledger/accounts"
|
||||
(get-path-for my-all-routes :ledger/account {:account-id "one-two"}) => "/api/1/ledger/accounts/one-two"
|
||||
(get-path-for my-all-routes :wui/home) => "http://localhost:1534/api/1/wui/home")
|
||||
|
||||
(fact "it should be able to retrieve the contect"
|
||||
(get-context my-all-routes :ledger) => "/api/1/ledger"))
|
||||
File renamed without changes.
@@ -0,0 +1,6 @@
|
||||
(ns skirmish.test-util
|
||||
(:require [midje.sweet :refer :all]
|
||||
[skirmish.util :refer :all]))
|
||||
|
||||
|
||||
;; midje testing
|
||||
@@ -0,0 +1,9 @@
|
||||
(ns skirmish.wui.components.test-home-page
|
||||
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
|
||||
|
||||
|
||||
|
||||
|
||||
(deftest test-numbers
|
||||
(is (= 1 2)))
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
(ns skirmish.cli.benchmark-test
|
||||
(:require [skirmish.cli.benchmark :refer :all]
|
||||
[midje.sweet :refer :all]
|
||||
[clojure.core.async :as async]))
|
||||
|
||||
(facts "creating simple orders"
|
||||
(fact "buy order"
|
||||
(let [buy-order (create-requests-payload-for-security 666 (str :equity/ibm) 1)
|
||||
expt {:benchmark/id 1 :price 2922 :quantity 2476 :security ":equity/ibm" :type :buy}]
|
||||
buy-order => expt));;
|
||||
(fact "sell order"
|
||||
(let [buy-order (create-requests-payload-for-security 667 (str :equity/ibm) 2)
|
||||
expt {:benchmark/id 2 :price 2740 :quantity 2516 :security ":equity/ibm" :type :sell}]
|
||||
buy-order => expt)))
|
||||
|
||||
(facts "the utility functions"
|
||||
(fact "no-more-then-n-simultaneously"
|
||||
(let [simultatious (atom [])
|
||||
input-chan (async/to-chan (range 10))
|
||||
sleep-time #(+ (mod (+ (* 5142 %) 8765) 200) 50)
|
||||
f (fn [i]
|
||||
(swap! simultatious #(conj % {:id i :status :start :value 1}))
|
||||
(Thread/sleep (sleep-time i))
|
||||
(swap! simultatious #(conj % {:id i :status :end :value -1}))
|
||||
i)
|
||||
res (async/<!! (async/into [] (no-more-then-n-simultaneously f input-chan 3)))
|
||||
simultatious-over-time (reductions #(+ %1 (:value %2)) 0 @simultatious)]
|
||||
(apply max simultatious-over-time) => 3
|
||||
(first simultatious-over-time) => 0
|
||||
(last simultatious-over-time) => 0)))
|
||||
@@ -1,13 +0,0 @@
|
||||
(ns skirmish.middleware.test-core
|
||||
(:require [midje.sweet :refer :all]
|
||||
[skirmish.middleware.core :refer :all]))
|
||||
|
||||
(defn all? [xf]
|
||||
#(every? true? (sequence xf %)))
|
||||
|
||||
(facts "we should have a async/chan base middleware for developing."
|
||||
(fact "It should exchanges for each security in the config"
|
||||
(let [config {:securities [{:sec-id :molly} {:sec-id :pepper}]}
|
||||
exchanges (create-exchange-apis-for config)]
|
||||
(keys exchanges) => [:molly :pepper]
|
||||
(vals exchanges) => #(every? map? %))))
|
||||
Reference in new issue
Block a user