Accelerated-text: A No-code Natural Language Generation Platform

Accelerated Text


A picture is worth a thousand words. Or is it? Tables, charts, pictures are all useful in understanding our data but often we need a description – a story to tell us what are we looking at. Accelerated Text is a natural language generation tool which allows you to define data descriptions and then generates multiple versions of those descriptions varying in wording and structure.

preview.gif

About

Accelerated Text can work with all sorts of data:

  • descriptions of business metrics
  • customer interaction data
  • product attributes
  • financial metrics

With Accelerated Text you can use such data to generate text for your business reports, your e-commerce platform or your customer support system.

Accelerated Text provides a web based Document Plan builder, where:

  • the logical structure of the document is defined
  • communication goals are expressed
  • data usage within text is defined

Document Plans and the connected data are used by Accelerated Text's Natural Language Generation engine to produce multiple variations of text exactly expressing what was intended to be communicated to the readers.

Philosophy

Natural language generation is a broad domain with applications in chat-bots, story generation, and data descriptions to name a few. Accelerated Text focuses on applying NLG technology to solve your data to text needs.

Data descriptions require precision. For example, generated text describing weather conditions should not contain things beyond those provided in the initial data – temperature: -1C, humidity: 40%, wind: 10km/h. Despite this, the expression of an individual fact – temperature – could vary. It could result in "it is cold", or "it is just below freezing", or "-1C", but this fact will be stated because it is present in the data. A data to text system is also not the one to elaborate on a story adding something about the serenity of some freezing lake – again, it was not in the supplied data.

Accelerated Text follows the principle of this strict adherence to the data-bound text generation. Via its user interface it provides instruments to define how the data should be translated into a descriptive text. This description – a document plan – is executed by natural language generation engine to produce texts that vary in structure and wording but are always and only about the data provided.

Key Features

  • Document plan editor to define what needs to be said about the data.
  • Data samples can be uploaded as CSV files to be used when building Document Plans.
  • Text structure variations to provide richer reading experience going beyond rigid template generated text.
  • Language and vocabulary control to match each of your reader groups.
  • Build-in rule engine to allow the control of what is said based on the different values of data points.
  • Live preview to see variations of generated text.

Get Started

The easiest way to get started is to use Accelerated Text Project Template. It will provide you with the necessary project configuration structure.

If you want to start tinkering and run it based on the latest code in the repository, first make sure that you have make and docker-compose installed, then clone the project and run

make run-app

After running this command the document plan editor will be availabe at http://localhost:8080, while AMR and DLG editors will be reachable via http://localhost:8080/amr/ and http://localhost:8080/dlg/ respectively.

For more detailed description of text generation workflow visit the Documentation.

Demo

For a demonstration of how Accelerated Text can be used to provide descriptions for various items in an e-commerce platform (https://www.reactioncommerce.com/) please check the following repository: https://github.com/tokenmill/reaction-acc-text-demo.

Development

To get started with a development environment for Accelerated Text please follow the instructions in our developer's guides for the front-end, api and the text generation engine.

Contact Us

If you have any questions, do not hesitate asking us at info@acceleratedtext.com

If you'll submit an Issue this will help everyone and you will be able to track the progress of us fixing it. In order to facilitate it please provide description of needed information for bug requests (like project version number, Docker version, etc.)


Download Details:

Author: Accelerated-text
Source Code: https://github.com/accelerated-text/accelerated-text 
License: View license

#javascript #graphql #clojure #text 

Accelerated-text: A No-code Natural Language Generation Platform
Oral  Brekke

Oral Brekke

1676513962

Electric: A Reactive Signals DSL for Fullstack Web UI

Electric Clojure – a signals DSL for fullstack web UI, with compiler-managed network sync

Electric (formerly known as Photon) is a reactive and network-aware Clojure/Script DSL that fully abstracts over client/server state sync at the programming language layer, in order to achieve strong composition across the frontend/backend boundary in dynamic web apps. With Electric, backend expressions (i.e. queries) and frontend expressions (i.e. views) compose directly. There is no incidental network divide. The Electric macros will, at compile time, perform deep graph analysis of your hollistic program's data flow in order to transparently partition and distribute it across the client/server distributed system. There is no client/server dichotomy from the programmer's perspective. All IO and effects are managed.

Figure: This is not RPC or client-side ORM. The Electric compiler performs deep graph analysis of your unified frontend/backend program to automatically determine the optimal network cut, and then compile it into separate client and server target programs that cooperate and anticipate each other's needs.

Fully reactive: unlike javascript frameworks, in Electric, reactivity is built directly into the programming language itself. Reactive-if, reactive-for, reactive try/catch. When everything is reactive, it feels like nothing is reactive. No observables! No async types! No function coloring problem! De-load your mind and relax.

Multi-tier: frontend and backend are defined in the same expression, same function, same file. It's not code sharing, it's code splitting. Let the compiler infer the boundary from your code, instead of contorting your code — nay, your entire architecture — to fit the boundary.

Network-transparent: Electric closures close over server and client scope bindings, all in the same expression. The Electric compiler uses compile-time static knowledge of your source code to slice your expressions into client and server portions. Right through closures, loops and deeply nested function calls.

Strong composition: Network-transparent Electric functions are true functions. They follow function laws and work at the Clojure/Script REPL. You have lambda, recursion, HOFs, closures, dynamic scope, macros, etc: the full undamaged composition power of Lisp. Goodbye "functional core imperative shell"; with Electric the entire system is a function.

Multiplayer-native: everything is automatically multiplayer, 0 LOC cost.

Our mission is to raise the abstraction ceiling in web development in the same way that garbage collection did for functional programming, paving the way for something new.

Demos

How it works

Dependency

; stable {:deps {com.hyperfiddle/electric {:mvn/version "v2-alpha-0-g40c3384e"}}}

  • Production ready for, let's say back office apps, after 8 months of private user testing and extreme dogfooding in the Hyperfiddle sister project.
  • As a maturity indicator, the only low level bug in recent memory was a hash collision triggered by scrolling a server-paginated grid over thousands of server-streamed elements.
  • Stack traces aren't great; we do have async stack traces already but they need work

Current development priorities:

  • developer experience improvements
  • network planner improvements
  • language semantics improvements

To date we have focused on correct semantics over syntax and performance. Now that we are useful in production, we are using production learnings to drive our priorities.

Community

Getting Started

Standalone starter repo to fork:

Demos, examples, tutorials are in this repo, see src-docs/user/.

  • clj -A:dev -X user/main serves demos at http://localhost:8080
  • dev alias; (user/main) compiles assets and serves app. see src-dev/user.clj & user.cljs

IDE setup

Clojure compat matrix

We target full Clojure/Script compatibility (say 99%). That means you can take a pre-existing Clojure snippet and copy/paste it into an Electric function body and it will "work" and produce the correct result. Including host interop syntax, use of pre-existing macros, etc.

Gaps:

Errors and issues

  • Requires -Xss2m to compile. The default of 1m ThreadStackSize is exceeded by the Electric compiler due to large macroexpansions resulting in false StackOverflowError during analysis.
  • :eval opcode - probably interop syntax, or a macro like assert that expands to interop syntax
  • Unbound var. Usually means wrong peer, i.e. accessed server-only var on client

Download Details:

Author: Hyperfiddle
Source Code: https://github.com/hyperfiddle/electric 
License: EPL-2.0 license

#clojure #fullstack #web 

Electric: A Reactive Signals DSL for Fullstack Web UI

Sente: Realtime Web Comms for Clojure/Script

CHANGELOG | API | current Break Version:

[com.taoensso/sente "1.17.0"] ; See CHANGELOG for details

See here if you're interested in helping support my open-source work, thanks! - Peter Taoussanis

Sente: realtime web comms for Clojure/Script

Or: We don't need no Socket.IO

Or: core.async + Ajax + WebSockets = The Shiznizzle

Sente is a small client+server library that makes it easy to build reliable, high-performance realtime web applications with Clojure + ClojureScript.

Hero

Sen-te (先手) is a Japanese Go term used to describe a play with such an overwhelming follow-up that it demands an immediate response, leaving its player with the initiative.

(I'd also recommend checking out James Henderson's Chord and Kevin Lynagh's jetty7-websockets-async as possible alternatives!)

Features

  • Bidirectional a/sync comms over both WebSockets and Ajax (auto-fallback)
  • It just works: auto keep-alives, buffering, protocol selection, reconnects
  • Efficient design incl. transparent event batching for low-bandwidth use, even over Ajax
  • Send arbitrary Clojure vals over edn or Transit (JSON, MessagePack, etc.)
  • Tiny API: make-channel-socket! and you're good to go
  • Automatic, sensible support for users connected with multiple clients and/or devices simultaneously
  • Realtime info on which users are connected over which protocols (v0.10.0+)
  • Flexible model: use it anywhere you'd use WebSockets/Ajax/Socket.IO, etc.
  • Standard Ring security model: auth as you like, HTTPS when available, CSRF support, etc.
  • Fully documented, with examples
  • Small codebase: ~1.5k lines for the entire client+server implementation
  • Supported servers: http-kit, Immutant v2+, nginx-clojure, node.js, Aleph, ring-jetty9-adapter

Capabilities

Protocolclient>serverclient>server + ack/replyserver>user push
WebSockets✓ (native)✓ (emulated)✓ (native)
Ajax✓ (emulated)✓ (native)✓ (emulated)

So you can ignore the underlying protocol and deal directly with Sente's unified API. It's simple, and exposes the best of both WebSockets (bidirectionality + performance) and Ajax (optional evented ack/reply model).

Getting started

Note that there's also a variety of full example projects available

Add the necessary dependency to your project:

Leiningen: [com.taoensso/sente "1.17.0"] ; or
deps.edn:   com.taoensso/sente {:mvn/version "1.17.0"}

On the server (Clojure) side

First make sure that you're using one of the supported web servers (PRs for additional server adapters welcome!).

Somewhere in your web app's code you'll already have a routing mechanism in place for handling Ring requests by request URL. If you're using Compojure for example, you'll have something that looks like this:

(defroutes my-app
  (GET  "/"            req (my-landing-pg-handler  req))
  (POST "/submit-form" req (my-form-submit-handler req)))

For Sente, we're going to add 2 new URLs and setup their handlers:

(ns my-server-side-routing-ns ; .clj
  (:require
    ;; <other stuff>
    [taoensso.sente :as sente] ; <--- Add this

    [ring.middleware.anti-forgery :refer [wrap-anti-forgery]] ; <--- Recommended

    ;; Uncomment a web-server adapter --->
    ;; [taoensso.sente.server-adapters.http-kit      :refer (get-sch-adapter)]
    ;; [taoensso.sente.server-adapters.immutant      :refer (get-sch-adapter)]
    ;; [taoensso.sente.server-adapters.nginx-clojure :refer (get-sch-adapter)]
    ;; [taoensso.sente.server-adapters.aleph         :refer (get-sch-adapter)]
  ))

;;; Add this: --->
(let [{:keys [ch-recv send-fn connected-uids
              ajax-post-fn ajax-get-or-ws-handshake-fn]}
      (sente/make-channel-socket! (get-sch-adapter) {})]

  (def ring-ajax-post                ajax-post-fn)
  (def ring-ajax-get-or-ws-handshake ajax-get-or-ws-handshake-fn)
  (def ch-chsk                       ch-recv) ; ChannelSocket's receive channel
  (def chsk-send!                    send-fn) ; ChannelSocket's send API fn
  (def connected-uids                connected-uids) ; Watchable, read-only atom
  )

(defroutes my-app-routes
  ;; <other stuff>

  ;;; Add these 2 entries: --->
  (GET  "/chsk" req (ring-ajax-get-or-ws-handshake req))
  (POST "/chsk" req (ring-ajax-post                req))
  )

(def my-app
  (-> my-app-routes
      ;; Add necessary Ring middleware:
      ring.middleware.keyword-params/wrap-keyword-params
      ring.middleware.params/wrap-params
      ring.middleware.anti-forgery/wrap-anti-forgery
      ring.middleware.session/wrap-session))

The ring-ajax-post and ring-ajax-get-or-ws-handshake fns will automatically handle Ring GET and POST requests to our channel socket URL ("/chsk"). Together these take care of the messy details of establishing + maintaining WebSocket or long-polling requests.

Add a CSRF token somewhere in your HTML:

(let [csrf-token (force ring.middleware.anti-forgery/*anti-forgery-token*)]
  [:div#sente-csrf-token {:data-csrf-token csrf-token}])

On the client (ClojureScript) side

You'll setup something similar on the client side:

(ns my-client-side-ns ; .cljs
  (:require-macros
   [cljs.core.async.macros :as asyncm :refer (go go-loop)])
  (:require
   ;; <other stuff>
   [cljs.core.async :as async :refer (<! >! put! chan)]
   [taoensso.sente  :as sente :refer (cb-success?)] ; <--- Add this
  ))

;;; Add this: --->

(def ?csrf-token
  (when-let [el (.getElementById js/document "sente-csrf-token")]
    (.getAttribute el "data-csrf-token")))

(let [{:keys [chsk ch-recv send-fn state]}
      (sente/make-channel-socket-client!
       "/chsk" ; Note the same path as before
       ?csrf-token
       {:type :auto ; e/o #{:auto :ajax :ws}
       })]

  (def chsk       chsk)
  (def ch-chsk    ch-recv) ; ChannelSocket's receive channel
  (def chsk-send! send-fn) ; ChannelSocket's send API fn
  (def chsk-state state)   ; Watchable, read-only atom
  )

Now what?

The client will automatically initiate a WebSocket or repeating long-polling connection to your server. Client<->server events are now ready to transmit over the ch-chsk channel.

Last step: you'll want to hook your own event handlers up to this channel. Please see one of the example projects for details.

Client-side API

  • ch-recv is a core.async channel that'll receive event-msgs
  • chsk-send! is a (fn [event & [?timeout-ms ?cb-fn]]) for standard client>server req>resp calls

Server-side API

  • ch-recv is a core.async channel that'll receive event-msgs
  • chsk-send! is a (fn [user-id event]) for async server>user PUSH calls

===============

TermForm
event[<ev-id> <?ev-data>], e.g. [:my-app/some-req {:data "data"}]
server event-msg{:keys [event id ?data send-fn ?reply-fn uid ring-req client-id]}
client event-msg{:keys [event id ?data send-fn]}
<ev-id>A namespaced keyword like :my-app/some-req
<?ev-data>An optional arbitrary edn value like {:data "data"}
:ring-reqRing map for Ajax request or WebSocket's initial handshake request
:?reply-fnPresent only when client requested a reply

Summary

  • So clients can use chsk-send! to send events to the server and optionally request a reply with timeout
  • The server can likewise use chsk-send! to send events to all the clients (browser tabs, devices, etc.) of a particular connected user by his/her user-id
  • The server can also use an event-msg's ?reply-fn to reply to a particular client event using an arbitrary edn value

It's worth noting that the server>user push (chsk-send! <user-id> <event>) takes a mandatory user-id argument. See the FAQ later for more info.

Ajax/Sente comparison: client>server

(jayq/ajax ; Using the jayq wrapper around jQuery
 {:type :post :url "/some-url-on-server/"
  :data {:name "Rich Hickey"
         :type "Awesome"}
  :timeout 8000
  :success (fn [content text-status xhr]
             (do-something! content))
  :error   (fn [xhr text-status] (error-handler!))})

(chsk-send! ; Using Sente
  [:some/request-id {:name "Rich Hickey" :type "Awesome"}] ; Event
  8000 ; Timeout
  ;; Optional callback:
  (fn [reply] ; Reply is arbitrary Clojure data
    (if (sente/cb-success? reply) ; Checks for :chsk/closed, :chsk/timeout, :chsk/error
      (do-something! reply)
      (error-handler!))))

Some important differences to note:

  • The Ajax request is slow to initialize, and bulky (HTTP overhead)
  • The Sente request is pre-initialized (usu. WebSocket), and lean (edn/Transit protocol)

Ajax/Sente comparison: server>user push

  • Ajax would require clumsy long-polling setup, and wouldn't easily support users connected with multiple clients simultaneously
  • Sente: (chsk-send! "destination-user-id" [:some/alert-id <arb-clj-data-payload>])

Channel socket client state

Each time the channel socket client's state changes, a client-side :chsk/state event will fire that you can watch for and handle like any other event.

The event form is [:chsk/state [<old-state-map> <new-state-map>]] with the following possible state map keys:

KeyValue
:typee/o #{:auto :ws :ajax}
:open?Truthy iff chsk appears to be open (connected) now
:ever-opened?Truthy iff chsk handshake has ever completed successfully
:first-open?Truthy iff chsk just completed first successful handshake
:uidUser id provided by server on handshake, or nil
:csrf-tokenCSRF token provided by server on handshake, or nil
:handshake-dataArb user data provided by server on handshake
:last-ws-error?{:udt _ :ev <WebSocket-on-error-event>}
:last-ws-close?{:udt _ :ev <WebSocket-on-close-event> :clean? _ :code _ :reason _}
:last-close?{:udt _ :reason _}, with reason e/o #{nil :requested-disconnect :requested-reconnect :downgrading-ws-to-ajax :unexpected}

Example projects

LinkDescription
[Official example]Official Sente reference example, always up-to-date
[@fiv0/spa-ws-template]Example Single Page App with ReFrame, http-kit, shadow-cljs
[@dharrigan/websockets]Example using [Reitit], Jetty 9/10 and [@dharrigan/websockets-js] (JS not Cljs!)
[@laforge49/sente-boot]Example using Sente v1.11.0, Boot (also works with Windows)
[@laforge49/sente-boot-reagent]Example using Sente v1.11.0, Boot, and Reagent
[@tiensonqin/lymchat]Example chat app using React Native
[@danielsz/system-websockets]Client-side UI, login and wiring of components
[@timothypratley/snakelake]Multiplayer snake game with screencast walkthrough
[@theasp/sente-nodejs-example]Ref. example adapted for Node.js servers ([Express], [Dog Fort]), as well as a node.js client
[@ebellani/carpet]Web+mobile interface for a remmitance application
[@danielsz/sente-system]Ref example adapted for [@danielsz/system]
[@danielsz/sente-boot]Ref example adapted for [boot]
[@seancorfield/om-sente]??
[@tfoldi/data15-blackjack]Multiplayer blackjack game with documented source code
[@davidvujic/sente-with-reagent-and-re-frame]Example code that combines Sente with Reagent and re-frame in a single page application
Your link here?PR's welcome!

FAQ

What is the user-id provided to the server>user push fn?

There's now also a full user-id, client-id summary up here

For the server to push events, we need a destination. Traditionally we might push to a client (e.g. browser tab). But with modern rich web applications and the increasing use of multiple simultaneous devices (tablets, mobiles, etc.) - the value of a client push is diminishing. You'll often see applications (even by Google) struggling to deal with these cases.

Sente offers an out-the-box solution by pulling the concept of identity one level higher and dealing with unique users rather than clients. What constitutes a user is entirely at the discretion of each application:

  • Each user-id may have zero or more connected clients at any given time
  • Each user-id may survive across clients (browser tabs, devices), and sessions

To give a user an identity, either set the user's :uid Ring session key OR supply a :user-id-fn (takes request, returns an identity string) to the make-channel-socket! constructor.

If you want a simple per-session identity, generate a random uuid. If you want an identity that persists across sessions, try use something with semantic meaning that you may already have like a database-generated user-id, a login email address, a secure URL fragment, etc.

Note that user-ids are used only for server>user push. client>server requests don't take a user-id.

As of Sente v0.13.0+ it's also possible to send events to :sente/all-users-without-uid.

How do I integrate Sente with my usual login/auth procedure?

This is trivially easy as of Sente v0.13.0+. Please see one of the example projects for details.

Will Sente work with Reactjs/Reagent/Om/Pedestel/etc.?

Sure! Sente's just a client<->server comms mechanism so it'll work with any view/rendering approach you'd like.

I have a strong preference for Reagent myself, so would recommend checking that out first if you're still evaluating options.

What if I need to use JSON, XML, raw strings, etc.?

As of v1, Sente uses an extensible client<->server serialization mechanism. It uses edn by default since this usu. gives good performance and doesn't require any external dependencies. The reference example project shows how you can plug in an alternative de/serializer. In particular, note that Sente ships with a Transit de/serializer that allows manual or smart (automatic) per-payload format selection.

How do I add custom Transit read and write handlers?

To add custom handlers to the TransitPacker, pass them in as writer-opts and reader-opts when creating a TransitPacker. These arguments are the same as the opts map you would pass directly to transit/writer. The code sample below shows how you would do this to add a write handler to convert Joda-Time DateTime objects to Transit time objects.

(ns my-ns.app
  (:require [cognitect.transit :as transit]
            [taoensso.sente.packers.transit :as sente-transit])
  (:import [org.joda.time DateTime ReadableInstant]))

;; From https://increasinglyfunctional.com/2014/09/02/custom-transit-writers-clojure-joda-time.html
(def joda-time-writer
  (transit/write-handler
    (constantly "m")
    (fn [v] (-> ^ReadableInstant v .getMillis))
    (fn [v] (-> ^ReadableInstant v .getMillis .toString))))

(def packer (sente-transit/->TransitPacker :json {:handlers {DateTime joda-time-writer}} {}))

How do I route client/server events?

However you like! If you don't have many events, a simple cond will probably do. Otherwise a multimethod dispatching against event ids works well (this is the approach taken in the reference example project).

Security: is there HTTPS support?

Yup, it's automatic for both Ajax and WebSockets. If the page serving your JavaScript (ClojureScript) is running HTTPS, your Sente channel sockets will run over HTTPS and/or the WebSocket equivalent (WSS).

Security: CSRF protection?

This is important. Sente has support, and use is strongly recommended. You'll need to use middleware like ring-anti-forgery or ring-defaults to generate and check CSRF codes. The ring-ajax-post handler should be covered (i.e. protected).

Please see one of the example projects for a fully-baked example.

Pageload: How do I know when Sente is ready client-side?

You'll want to listen on the receive channel for a [:chsk/state [_ {:first-open? true}]] event. That's the signal that the socket's been established.

How can server-side channel socket events modify a user's session?

Update: @danielsz has kindly provided a detailed example here.

Recall that server-side event-msgs are of the form {:ring-req _ :event _ :?reply-fn _}, so each server-side event is accompanied by the relevant[*] Ring request.

For WebSocket events this is the initial Ring HTTP handshake request, for Ajax events it's just the Ring HTTP Ajax request.

The Ring request's :session key is an immutable value, so how do you modify a session in response to an event? You won't be doing this often, but it can be handy (e.g. for login/logout forms).

You've got two choices:

Write any changes directly to your Ring SessionStore (i.e. the mutable state that's actually backing your sessions). You'll need the relevant user's session key, which you can find under your Ring request's :cookies key. This is flexible, but requires that you know how+where your session data is being stored.

Just use regular HTTP Ajax requests for stuff that needs to modify sessions (like login/logout), since these will automatically go through the usual Ring session middleware and let you modify a session with a simple {:status 200 :session <new-session>} response. This is the strategy the reference example takes.

Lifecycle management (component management/shutdown, etc.)

Using something like @stuartsierra/component or @palletops/leaven?

Most of Sente's state is held internally to each channel socket (the map returned from client/server calls to make-channel-socket!). The absence of global state makes things like testing, and running multiple concurrent connections easy. It also makes integration with your component management easy.

The only thing you may[1] want to do on component shutdown is stop any router loops that you've created to dispatch events to handlers. The client/server side start-chsk-router! fns both return a (fn stop []) that you can call to do this.

[1] The cost of not doing this is actually negligible (a single parked go thread).

There's also a couple lifecycle libraries that include Sente components:

  1. @danielsz/system for use with @stuartsierra/component
  2. @palletops/bakery for use with @palletops/leaven

How to debug/benchmark Sente at the protocol level?

@arichiardi has kindly provided notes on some of Sente's current implementation details here.

Any other questions?

If I've missed something here, feel free to open a GitHub issue or pop me an email!

Contacting me / contributions

Please use the project's GitHub issues page for all questions, ideas, etc. Pull requests welcome. See the project's GitHub contributors page for a list of contributors.

Otherwise, you can reach me at Taoensso.com. Happy hacking!

- Peter Taoussanis


Download Details:

Author: ptaoussanis
Source Code: https://github.com/ptaoussanis/sente

License: EPL-1.0 license

#clojure #script 

Sente: Realtime Web Comms for Clojure/Script

LispSyntax.jl: Lisp-like Syntax in Julia

LispSyntax.jl: A clojure-like lisp syntax for julia

This package provides a lisp-to-julia syntax translator with convenience macros that let you do this:

lisp"(defn fib [a] (if (< a 2) a (+ (fib (- a 1)) (fib (- a 2)))))"
@test lisp"(fib 30)" == 832040
@test fib(30)        == 832040

LispSyntax.jl is implemented as an expression translator between lisp/clojure-like syntax and julia's AST. Julia's compiler, JIT and multiple-dispatch infrastructure is used for code generation and execution. Because of this, LispSyntax.jl is not really clojure or lisp in most meaningful ways. The semantics are entirely julia-based (which are very similar to scheme/lisp in many ways). The net result is that LispSyntax.jl is really an alternative S-expression-like syntax for julia, not an implemention of clojure or lisp.

Special Forms

  • (def symbol init)
  • (quote form)
  • (defn symbol [param*] expr*)
  • (defmacro symbol [param*] expr*)
  • (lambda [param*] expr*)
  • (fn [param*] expr*)
  • (let [binding*] expr*)
  • (global symbol*)
  • (while test expr*)
  • (for [binding*] expr*)
  • (import package*)

Notable Differences

  • Symbol names cannot have -, *, /, ? ... - Julia symbol naming is used for everything, as a result, Julia syntax restrictions are maintained in LispSyntax.jl.
  • Reference to global variables in function scopes - Julia requires declaration of global symbols that are referenced in function scope. Because of this functions need to declare which symbols are global. This is done via the special form (global symbol*).
  • Binding forms not implemented - Clojure has very awesome destructuring binds that can used in most special forms requiring bindings (e.g. let, fn parameter lists, etc.). This is not currently implemented.
  • Lack of loop/recur - Currently, this is not implemented. As with Clojure, julia does not currently support TCO, so something like this may be needed (but a macro-implementation of tail call rewriting may be more appropriate for julia).
  • Optional typing - Currently not implemented.
  • Named functions are julia methods - For efficiency, functions defined with defn are translated to normal julia function expressions. This means the act as named lambdas in local scope.
  • Method definition - Also not currently implemented. If implemented it will probably not be a full implementation of Clojure's sophisticated dispatch system.
  • Macros differences - Macros defined in LispSyntax.jl look like standard Lisp macros but because expressions are special objects in julia, S-expressions returned from macros require a special translation step to generate julia expression trees. The result is that LispSyntax.jl macros are directly translated into Julia macros and must be called via special syntax (e.g. (@macro expr)). Macro hygiene follows the Julia approach of hygenic-by-default with explicit escaping using esc. This is the opposite of Clojure's macros which use explicit hygiene with specially named variables.
  • Julia's string macro dispatch not supported (yet) - for macros like @r_str which in Julia can be called via r"", it is currently necessary to call these via standard macro syntax: (@r_str "string")

REPL Mode

LispSyntax.jl provides a convenience REPL, alleviating one from having to type lisp"( ... )" for each top level expression. In order to use REPL mode, simply initialize it:

julia> using LispSyntax
julia> LispSyntax.init_repl()
REPL mode Lisp Mode initialized. Press ) to enter and backspace to exit.

At this point, type ), and you're ready to Lisp:

jλ> (* 2 (reduce + (: 1 6)))
42
jλ> (defn fib [a] 
      (if (< a 2) 
        a 
        (+ (fib (- a 1)) (fib (- a 2)))))
fib (generic function with 1 method)
jλ> (fib 10)
55

To return to the Julia prompt, simply type the backspace type or Ctrl-C. Once there, you'll still have access to the fuctions you defined:

julia> fib
fib (generic function with 1 method)
julia> fib(10)
55

You may also create a customized REPL.

TODO

  • Support for exceptions: this is straight forward but not currently implemented.
  • Optional typing to support method definition
  • Structs and aggregate types
  • Special dispatch for string macro forms
  • Modules
  • import vs. using vs. include -- only using is currently implemented and confusingly, it matches Clojure's import form.
  • varargs and named arguments

Download Details:

Author: swadey
Source Code: https://github.com/swadey/LispSyntax.jl 
License: View license

#julia #clojure 

 LispSyntax.jl: Lisp-like Syntax in Julia

Sexpr.jl: Julia <3 Clojure + Macroexpansion

S-Julia - s-expression to julia convertor.  

Quickstart

> Pkg.clone("https://github.com/vshesh/Sexpr.jl.git")

$ julia -e 'import Sexpr; Sexpr.main()' --
usage: Sexpr.jl [-i] [-c] [-l LINES] [-o OUTPUT] [-e EXTENSION] [-h]
               [files...]
A program to port clojure-like s-expression syntax to and from
julia. By default, this program takes clojure syntax and outputs
the julia version. Use -i to flip direction.

positional arguments:
  files                 If given one file and no output directory,
                        will dump to stdout. If given a directory or
                        multiple files, eg "sjulia file1 dir file2",
                        an output directory must be specified with
                        -o/--output where the files will go.
optional arguments:
  -i, --invert          take julia code and print out s-expression
                        code instead
  -c, --cat             cat all the input from STDIN rather than read
                        from file. Ignores all positional args to the
                        program.
  -l, --lines LINES     how many blank lines should exist between top
                        level forms, default 1 (type: Int64, default:
                        1)
  -o, --output OUTPUT   where to write out files if there are multiple
                        positional arguments to the file. If this is
                        empty, and there are >1 argument, the program
                        will throw an error.
  -e, --extension EXTENSION
                        add an extension that qualifies as a lisp file
                        (can use multiple times). Defaults: clj, cljs,
                        cl, lisp, wisp, hy.
  -h, --help            show this help message and exit
$ julia -e 'import Sexpr; Sexpr.main()' -- -o test/output/ test/programs/
# will transpile all .clj files in test/programs and dump them into test/output.

Overview

This project aims to make s-expression syntax interoperable with julia's own Expr objects.

If you've seen LispSyntax.jl, it's a similar idea, but IMHO this project does a bit more, such as allow you to transpile file->file rather than just read in a program, and also transpile back, so you can convert your julia files (minus a few special forms that aren't supported yet) into clojure syntax. This makes it possible to go from julia to python (again, not that anyone needed another route b/c pycall) via Hylang, or to JS via WispJS. The benefit here is that the awkward macro syntax in both of those languages is avoided (Hy necessitates wrapping everything in HyModel objects yourself, which is ridiculous, and WispJS's module system is broken, because it is Javascript, so resolving variable names is not working properly).

The final goal is to use interoperability to do a macroexpand operation on the input clj syntax. So you would be able to give a folder of clj files, and a temp folder with jl files would be created, then each file would be read in and macroexpanded, converted back to clj syntax, and written out to a third folder. Unfortunately, it's necessary to write the jl files out as an intermediary step, because they need to be able to find each other to resolve imports. Alternatively, you could write the clj files as jl files with the macro @clj_str, but that makes your whole file a string, which breaks most syntax highlighters, which can be annoying.

I know that you're probably thinking "why?" and it was mostly a project for me to learn Julia and muck around with its internals. I learned quite a bit, so mission accomplished! CLJS has self-hosting now, which means that they will hopefully have a js-only package soon. However, dealing with google closure compiler and leiningen's java/jvm dependencies are a larger problem to be solved, and until then, I still consider it unwieldy, so there's still some practical use to be had here.

Effectively, this is just the reader portion of implementing a lisp - Julia does everything else using its inbuilt mechanisms.

Syntax Overview

Atoms

  • nil translates to julia's nothing. They work exactly the same.
  • true -> true and false -> false. No surprises at all there.
  • number constants compile to either Int64 or Float64 types.
    • rational constants also supported, so 3/5 -> 3//5 in Julia.
  • character any atom starting with a \ is a character.
    • \newline, \space, \tab, \formfeed, \backspace, \return for escapes
    • unicode/octal support still needs to be handled.
    • non-strict, giving a longer literal silently just gives you the first character right now. This is probably not the best long-term strategy. Eg, \xyz -> \x
  • string is any sequence of characters inside double quotes.
    • multiline strings are allowed, but padding is not subtracted (yet).
  • keyword basically a symbol that starts with a :. In julia, these are confusingly called symbols, and symbols are called variables.
    • keywords cannot have a / or . in them anywhere.
    • in clojure keywords with two colons are resolved in the current namespace, that behavior is not the same here. Everything just compiles to a normal symbol in julia, so no namespacing. There are probably issues here, I just don't know what they are.
  • symbol which is any identifier for a variable.
    • any / or . character is converted to a . in julia. Eg, module/function becomes module.function as an identifier. This should be relatively consistent with clojure semantics.
    • clojure is more lenient about symbol characters than julia. In order to get around this limitation, the default is to output unicode characters where regular ones won't suffice. so *+?!-_':>< are all allowed inside a symbol.
      • TODO make the option to use escaped ascii-only names available. (ugly, but avoids having to use unicode, which is a pain depending on how your unicode extension is defined).
      • :: in a symbol identifier compiles to a type. eg, x::Int compiles to (:: x Int)
      • ::T1::T2 compiles to a union like x::T1::T2 -> (:: x T1 T2)

Collections

  • '(a b c) a list - if not quoted, it's evaluated and transpiled.
    • quoted lists evaluate to tuples, as of now.
  • [a b c] a vector - transpiles to a julia array.
  • {a b c d} a map - transpiles to a julia Dict(a => b, c=> d) form.
  • TODO #{a b c} a set, which can map to Set() in julia.

Julia Special Forms

  • Short Circuit
    • and/&& (what you expect this to be) - needs to be a special form because of short circuiting. Julia defines the and and or forms this way on purpose.
    • or/|| (again, what you expect), see above.
  • x[i] family (getting/setting/slicing arrays)
    • (aget x 1) -> Expr(:ref, :x, 1) -> x[1].
    • (aget x 1 2 4 5) -> Expr(:ref, :x, 1, 2, 4, 5) -> x[1, 2, 4, 5]
    • (aget x (: 1 3)) -> x[1:3]
    • (aget x (: 6)) -> x[6:end] (preferred)
    • (aget x (: 6 :end)) -> x[6:end] (not preferred)
  • Typing
    • (:: x Int) -> x::Int The :: form defines types.
      • (:: x Int In64) -> x::Union{Int, Int64} there's auto-union if many types are defined.
      • only useful for function and type defintions.
    • (curly Array Int64) -> Array{Int64} will allow parameterized types.
    • (.b a x y) -> a.b(x,y) is the dot call form.
    • (. a b c d) -> a.b.c.d is the dot access form.
      • note that ((. a b) x y) is equivalent to (.b a x y).
  • Modules and Import
    • (module M ... end) creates a module. This is visually annoying since you indent your whole file by two spaces just for this call to module, however I haven't figured out any better way to do this - the other option is to make #module M a special hash dispatch that wraps the whole file but... meh, I don't consider this a high enough priority.
    • (import|using X y z a b) contrary to my expectations, this will give you import X.y.a.b. There will be a separate import statement for each function/file you want to use.
      • TODO make this cartesian productable, so (import X [y z a]) will expand to import X.y; import X.z; import X.a instead. This should shorten the writing. Ideally should make this a system macro (in a system.clj file that I define) and call it import* or something.
    • (export a b c) -> export a, b, c. It makes sense from julia's point of view, since modules are flat things, and you only ever have one level of definitions to export.

Special Forms

()/'() or empty list.

  • For now, this compiles to an empty tuple. In some lisps this is equivalent to nil (eg Common Lisp) but in Clojure it's not, so I'm following that convention.

(do exprs...) does each expression and returns the results of the last one.

(if test true-case false-case?) standard if, evaluates form #2 and branches.

(let [var1 value1 var2 value2...] exprs...) binds pairs of variables to their values, then evaluates exprs in an implicit do.

(fn name? [params...] exprs...) defines a function.

  • a function with no name and only one expr in the body will be converted to a -> form. Eg: (fn [x] x) -> (x) -> x.

(defn name docstring? [params...] exprs...) named defined function.

  • docstrings are ignored right now.

(def var expr) defines a variable.

throw is a function already in julia, so there's no special form dedicated to it.

include is a function already in julia, so there's no dedicated special form for it.

TODOS

  • loop/recur (this doesn't have a julia equivalent),
  • try/catch/finally
  • for vars in expr do... (useful for lazy iterators)
  • destructuring and rest param like (fn [& rest])
  • defmulti and related (does this even mean anything given julia's multiple-dispatch?)
  • deftype -> type in Julia.

Macro Forms

  • (@m x y z) how to call a macro - prepend it's name with @. There is unfortunately no way around this, since julia requires this distinction and for me to resolve what things are macros without it would involve writing an entire compiler. To keep it simple, I'm leaving this requirement in place.
    • TODO Since @x means deref in clojure, I might choose to use a different symbol to denote macrocall in the future. maybe μ or something. Another idea is abusing # dispatch so `#macro (html [:div "helloworld"])`` calls the next form as a macro rather than a regular function. The hash dispatch one seems worse, though.
  • defmacro defines a macro, as expected.
    • The way that macros work right now is that the macro definition is passed a clojure s-expression to work with. This is not the same as being passed a julia equivalent.
    • the macro output should again be a clojure expression, which has to be translated by the reader into a julia expression. This means that whatever program you write has to include the reader module of this project in order to produce the desired output.
    • Every macro will end in a call to Sexpr.rehydrate() which will translate the expression back to julia's native AST.
  • quote or ' gives a literal list of the following expression.
    • The quote form doesn't properly escape symbols yet. Eg, 'x is equal to :x in Julia, but in order to stop the gensym pass from running you actually have to do esc(:x) to get the equivalent. I'm unclear as of yet how the translation should work to get the desired results, so right now quote and syntax-quote do the same thing, which needs to be changed.
    • you can get around this yourself by putting esc calls in the right places, it will compile down to a function call in the code.
  • syntax-quote or backtick character. the :() quoting form in julia is actually a syntax quote. It also has an auto-gensym (which can be a pain to get around if you want to return the original name without obfuscation).
  • unquote or ~ is $ in julia inside expressions. It should evaluate the variable that's given to the macro and use the evaluated value.
  • unquote-splice or ~@ unquotes, and also expands the form by one layer into the form that's being returned. Ie, (f ~@x) is the same as :(f($x...)) in julia.

Download Details:

Author: VShesh
Source Code: https://github.com/vshesh/Sexpr.jl 

#julia  #clojure 

Sexpr.jl: Julia <3 Clojure + Macroexpansion
Nat  Grady

Nat Grady

1657425840

Light Table: The Light Table IDE

Light Table

Light Table is a next generation code editor that connects you to your creation with instant feedback. Light Table is very customizable and can display anything a Chromium browser can.

Light Table is putting out a call for additional maintainers! There is plenty to do for nearly every aspect of the project. Ranging from digging deep down into the internals, writing documentation, fixing bugs, writing plugins, or triaging new issues, Light Table could use a hand. If you are interested, please reach out.

Downloads

Prebuilt binaries are available through lighttable.com. To build and use a developer version of Light Table see these instructions.

For OSX users, the install process involves the following steps until we officially sign our OSX App:

  • In Finder, Ctrl-click on LightTable.app/ and select Open.
  • When you see this prompt about LightTable being unidentified, click Open.
  • If Ctrl-click doesn't work for you, open System Preferences > Security & Privacy > General, temporarily change "Allow apps downloaded from:" to Anywhere and double click on LightTable.app.

Documentation

Plugins

Light Table has a powerful plugin system that allows almost any aspect of the editor to be extended and customized. With over 100+ plugins, the community is able to offer eval support for new languages, create domain-specific IDEs and much more. If you're interested in writing your own plugin, see the Write a Plugin and Submit a Plugin docs. For an example ClojureScript plugin, see LightTable-Declassifier.

Community

Want to ask a question or just say hi? Please do :). Our mailing list is the Light Table Google group. We also hang out in #lighttable on Freenode IRC.

For Developers

LightTable is primarily written in ClojureScript. If you aren't familiar with it, check out David Nolen's tutorial.

In order to develop for Light Table, you will need to install a developer version of Light Table. For more information, read CONTRIBUTING.md and For Developers.

Credits

Big thanks to all our contributors! Thanks of course to Kodowa for all they have done for Light Table and also to Cognitect for providing friday contributions for one of the core team members.

Author: LightTable
Source Code: https://github.com/LightTable/LightTable 
License: MIT license

#electron #editor #clojure #javascript 

Light Table: The Light Table IDE
Nat  Grady

Nat Grady

1657384560

MarkRight: Electron Powered Markdown Editor with Live Preview

MarkRight

a minimalistic github flavored markdown editor

screenshot

Download

On mac, install it through cask:

brew install --cask markright

Alternatively, check out the latest release to quickly find the latest version. Here are the current binaries:

Command line

On mac, you can launch markright from the command line with a little alias:

alias markright="open -a /Applications/MarkRight.app"
markright README.md

Building

MarkRight is written in clojurescript. To build, make sure you have clojure and leiningen installed on your system.

Requirements

  • npm
  • leiningen
  • bower
  • npm install
  • bower install

Compiling

All commands you need are available inside package.json. To compile the code, run npm run compile:<prod/dev>. node/ is the folder that goes into electron.

Development

To develop, run the self-reloading build:

  • lein run -m build/ui-dev
  • lein run -m build/main-dev

shadow-build will live-reload the frontend so you don't need to refresh. If you change main.cljs however, you'll have to restart electron to reload your changes.

This project is currently frozen. If you want to help developing it, please feel free to ping me

Author: dvcrn
Source Code: https://github.com/dvcrn/markright 
License: GPL-3.0 license

#electron #preview #javascript #clojure #css 

MarkRight: Electron Powered Markdown Editor with Live Preview
Dexter  Goodwin

Dexter Goodwin

1657366620

Datascript: Immutable Database and Datalog Query Engine for Clojure

What if creating a database would be as cheap as creating a Hashmap?

An immutable in-memory database and Datalog query engine in Clojure and ClojureScript.

DataScript is meant to run inside the browser. It is cheap to create, quick to query and ephemeral. You create a database on page load, put some data in it, track changes, do queries and forget about it when the user closes the page.

DataScript databases are immutable and based on persistent data structures. In fact, they’re more like data structures than databases (think Hashmap). Unlike querying a real SQL DB, when you query DataScript, it all comes down to a Hashmap lookup. Or series of lookups. Or array iteration. There’s no particular overhead to it. You put a little data in it, it’s fast. You put in a lot of data, well, at least it has indexes. That should do better than you filtering an array by hand anyway. The thing is really lightweight.

The intention with DataScript is to be a basic building block in client-side applications that needs to track a lot of state during their lifetime. There’s a lot of benefits:

  • Central, uniform approach to manage all application state. Clients working with state become decoupled and independent: rendering, server sync, undo/redo do not interfere with each other.
  • Immutability simplifies things even in a single-threaded browser environment. Keep track of app state evolution, rewind to any point in time, always render consistent state, sync in background without locking anybody.
  • Datalog query engine to answer non-trivial questions about current app state.
  • Structured format to track data coming in and out of DB. Datalog queries can be run against it too.

Latest version 

[datascript "1.3.13"]

Important! If you are using shadow-cljs, add

:compiler-options {:externs ["datascript/externs.js"]}

to your build (see #432 #298 #216)

Support us

Resources

Support:

Books:

Docs:

Posts:

Talks:

  • “Frontend with Joy” talk (FPConf, August 2015): video in Russian
  • “Programming Web UI with Database in a Browser” talk (PolyConf, July 2015): slides, video
  • “DataScript for Web Development” talk (Clojure eXchange, Dec 2014): slides, video
  • “Building ToDo list with DataScript” webinar (ClojureScript NYC, Dec 2014): video, app
  • DataScript hangout (May 2014, in Russian): video

Projects using DataScript:

Related projects:

  • DataScript-Transit, transit serialization for database and datoms
  • Posh, lib that lets you use a single DataScript db to store Reagent app state
  • re-posh, use re-frame with DataScript storage
  • DataScript-mori, DataScript & Mori wrapper for use from JS
  • DatSync, Datomic ↔︎ DataScript syncing/replication utilities
  • Intension, lib to convert associative structures to in-memory databases for querying them
  • Datamaps, lib designed to leverage datalog queries to query arbitrary maps.

Demo applications:

Usage examples

For more examples, see our acceptance test suite.

(require '[datascript.core :as d])

;; Implicit join, multi-valued attribute

(let [schema {:aka {:db/cardinality :db.cardinality/many}}
      conn   (d/create-conn schema)]
  (d/transact! conn [ { :db/id -1
                        :name  "Maksim"
                        :age   45
                        :aka   ["Max Otto von Stierlitz", "Jack Ryan"] } ])
  (d/q '[ :find  ?n ?a
          :where [?e :aka "Max Otto von Stierlitz"]
                 [?e :name ?n]
                 [?e :age  ?a] ]
       @conn))

;; => #{ ["Maksim" 45] }


;; Destructuring, function call, predicate call, query over collection

(d/q '[ :find  ?k ?x
        :in    [[?k [?min ?max]] ...] ?range
        :where [(?range ?min ?max) [?x ...]]
               [(even? ?x)] ]
      { :a [1 7], :b [2 4] }
      range)

;; => #{ [:a 2] [:a 4] [:a 6] [:b 2] }


;; Recursive rule

(d/q '[ :find  ?u1 ?u2
        :in    $ %
        :where (follows ?u1 ?u2) ]
      [ [1 :follows 2]
        [2 :follows 3]
        [3 :follows 4] ]
     '[ [(follows ?e1 ?e2)
         [?e1 :follows ?e2]]
        [(follows ?e1 ?e2)
         [?e1 :follows ?t]
         (follows ?t ?e2)] ])

;; => #{ [1 2] [1 3] [1 4]
;;       [2 3] [2 4]
;;       [3 4] }


;; Aggregates

(d/q '[ :find ?color (max ?amount ?x) (min ?amount ?x)
        :in   [[?color ?x]] ?amount ]
     [[:red 10]  [:red 20] [:red 30] [:red 40] [:red 50]
      [:blue 7] [:blue 8]]
     3)

;; => [[:red  [30 40 50] [10 20 30]]
;;     [:blue [7 8] [7 8]]]

Using from vanilla JS

DataScript can be used from any JS engine without additional dependencies:

<script src="https://github.com/tonsky/datascript/releases/download/1.3.13/datascript-1.3.13.min.js"></script>

or as a CommonJS module (npm page):

npm install datascript
var ds = require('datascript');

or as a RequireJS module:

require(['datascript'], function(ds) { ... });

Queries:

  • Query and rules should be EDN passed as strings
  • Results of q are returned as regular JS arrays

Entities:

  • Entities returned by entity call are lazy as in Clojure
  • Use e.get("prop"), e.get(":db/id"), e.db to access entity properties
  • Entities implement ECMAScript 6 Map interface (has/get/keys/...)

Transactions:

  • Use strings such as ":db/id", ":db/add", etc. instead of db-namespaced keywords
  • Use regular JS arrays and objects to pass data to transact and db_with

Transaction reports:

  • report.tempids has string keys ("-1" for entity tempid -1), use resolve_tempid to set up a correspondence

Check out test/js/tests.js for usage examples.

Project status

Stable. Most of the features done, expecting non-breaking API additions and performance optimizations. No docs at the moment, use examples & Datomic documentation.

The following features are supported:

  • Database as a value: each DB is an immutable value. New DBs are created on top of old ones, but old ones stay perfectly valid too
  • Triple store model
  • EAVT, AEVT and AVET indexes
  • Multi-valued attributes via :db/cardinality :db.cardinality/many
  • Lazy entities and :db/valueType :db.type/ref auto-expansion
  • Database “mutations” via transact!
  • Callback-based analogue to txReportQueue via listen!
  • Direct index lookup and iteration via datoms and seek-datoms
  • Filtered databases via filter
  • Lookup refs
  • Unique constraints, upsert
  • Pull API (thx David Thomas Hume)

Query engine features:

  • Implicit joins
  • Query over DB or regular collections
  • Parameterized queries via :in clause
  • Tuple, collection, relation binding forms in :in clause
  • Query over multiple DB/collections
  • Predicates and user functions in query
  • Negation and disjunction
  • Rules, recursive rules
  • Aggregates
  • Find specifications

Interface differences:

  • Conn is just an atom storing last DB value, use @conn instead of (d/db conn)
  • Instead of #db/id[:db.part/user -100] just use -100 in place of :db/id or entity id
  • Transactor functions can be called as [:db.fn/call f args] where f is a function reference and will take db as first argument (thx @thegeez)
  • In ClojureScript, custom query functions and aggregates should be passed as source instead of being referenced by symbol (due to lack of resolve in CLJS)
  • Custom aggregate functions are called via aggregate keyword: :find (aggregate ?myfn ?e) :in $ ?myfn
  • Additional :db.fn/retractAttribute shortcut
  • Transactions are not annotated by default with :db/txInstant

Expected soon:

  • Better error reporting
  • Proper documentation

Differences from Datomic

  • DataScript is built totally from scratch and is not related by any means to the popular Clojure database Datomic
  • Runs in a browser and/or in a JVM
  • Simplified schema, not queryable
  • Attributes do not have to be declared in advance. Put them to schema only when you need special behaviour from them
  • Any type can be used for values
  • No :db/ident attributes, keywords are literally attribute values, no integer id behind them
  • No schema migrations
  • No cache segments management, no laziness. Entire DB must reside in memory
  • No facilities to persist, transfer over the wire or sync DB with the server
  • No pluggable storage options, no full-text search, no partitions
  • No external dependencies
  • Free

Aimed at interactive, long-living browser applications, DataScript DBs operate in constant space. If you do not add new entities, just update existing ones, or clean up database from time to time, memory consumption will be limited. This is unlike Datomic which keeps history of all changes, thus grows monotonically. DataScript does not track history by default, but you can do it via your own code if needed.

Some of the features are omitted intentionally. Different apps have different needs in storing/transfering/keeping track of DB state. DataScript is a foundation to build exactly the right storage solution for your needs without selling too much “vision”.

Contributing

Testing

Setup

npm install ws

Running the tests

clj -M:test -m kaocha.runner

Watching tests:

./script/watch.sh

Benchmarking and Datomic compatibility

datomic-free is a dependency not available on Clojars or Maven Central.

  1. Download datomic-free from https://my.datomic.com/downloads/free
  2. Unzip it
  3. Inside the unzipped folder run ./bin/maven-install

Run compatibility checks:

clj -M:datomic

Benchmark:

cd bench
./bench.clj

Author: Tonsky
Source Code: https://github.com/tonsky/datascript 
License: EPL-1.0 license

#javascript #clojure #database 

Datascript: Immutable Database and Datalog Query Engine for Clojure
Raleigh  Hayes

Raleigh Hayes

1653966000

How to Create A Simple Web Server using Deps.edn - clojure

This is an introductory video on creating a simple web server using deps.edn and some clojure libraries

------
Links

My Code - https://github.com/kelvin-mai/learn-deps/tree/http-kit-intro

You can see more at: A Clojure/Clojurescript Notebook Application

#clojure 

How to Create A Simple Web Server using Deps.edn - clojure
Raleigh  Hayes

Raleigh Hayes

1653958800

Introduction: Clojure deps.edn

In this video, we learn about clojure cli and deps.edn as a build tool.. An introduction to the clojure cli and deps.edn as a build tool.

My Code - https://github.com/kelvin-mai/learn-deps

You can see more at: A gentle intro to Clojure
#clojure 

Introduction: Clojure deps.edn
Hermann  Frami

Hermann Frami

1653004020

Serverless Plugin for Clojurescript Deployment W/ Cljs-lambda

serverless-cljs-plugin

A Serverless plugin which uses lein/cljs-lambda (or, optionally Lumo) to package services written in Clojurescript.

Leiningen Template

$ lein new serverless-cljs example
example$ lein deps

Will generate an example directory containing a minimal serverless.yml and project.clj demonstrating this plugin's functionality.

Guide to using the plugin via Lein/JVM compilation.

Usage

functions:
  echo:
    cljs: example.core/echo

plugins:
 - serverless-cljs-plugin

With the above serverless.yml, serverless deploy will create a zip file containing your functions. Doing this is similar to setting the Serverless packaging.artifact option - cljs-lambda is responsible for the zip contents, and Serverless includes/excludes will be skipped (cljs-lambda offers equivalent functionality).

In the example above, there needn't be a corresponding entry for echo in project.clj.

Lumo

Alternatively you can use the Lumo compiler.

In order to enable it, pass the --lumo switch to either deploy or package:

$ serverless deploy --lumo

Or add the following to your serverless.yml:

custom:
  cljsCompiler: lumo

Compiler options

The source paths and compiler options will be read from the optional file serverless-lumo.edn. Below are the defaults:

{:source-paths ["src"]
 :compiler     {:output-to     "out/lambda.js"
                :output-dir    "out"
                :source-map    false ;; because of a bug in lumo <= 1.8.0
                :target        :nodejs
                :optimizations :none}}

Lumo Configuration

As an alternative to cljsCompiler: lumo, cljsCompiler.lumo may be specified as a map of options. These options are passed directly to the lumo process. Currently supported:

custom:
  cljsCompiler:
    lumo:
      dependencies:
        - andare:0.7.0
      classpath:
        - /tmp/
      localRepo: /xyz
      cache: /cache | none
      index: true | false
      exitOnWarning: true | false

Note: caching is always on unless you specify "none" in the config.

The index.js file

The index option will materialize a custom index.js in :output-dir's parent folder. This file should be thought as managed by serverless-cljs-plugin and it is necessary for some plugin (e.g.: serverless-offline) to work properly.

Note: with the default compiler options, index.js will be saved in the project root, overwriting without warning.

Exit on compilation warnings

Lumo generates warnings such as WARNING: Use of undeclared Var to signal failures. You can tune the ones you want to see by using the :warnings compiler option in serverless-lumo.edn, but by default the lumo process emits the warnings, does not throw and returns 0. This means that serverless will keep going in presence of warnings.

Author: Nervous-systems
Source Code: https://github.com/nervous-systems/serverless-cljs-plugin 
License: Unlicense license

#serverless #aws #clojure 

Serverless Plugin for Clojurescript Deployment W/ Cljs-lambda
Best of Crypto

Best of Crypto

1650723420

District UI Module for Mobile Browser Integration

district-ui-mobile

Clojurescript re-mount module, that provides mobile integration.

Installation

Add [district0x/district-ui-mobile "1.0.0"] into your project.clj

Quickstart

district.ui.mobile first needs to be initialized, as defined in the re-mount pattern.

Include district.ui.mobile within the main file where you call mount/start

;; core.cljs, or main.cljs, etc...
(require '[mount.core :as mount])
(require '[district.ui.mobile])

;; optional initialization options
(def district-ui-options
  {:mobile {:force-mobile-device false}})

(mount/start (with-args district-ui-options))

Subscriptions can then be made to determine if the web application is being viewed from mobile devices, specifically Android or iOS devices.

;; re-frame view file
(require '[re-frame :refer [subscribe]])
(require '[district.ui.mobile.subs :as mobile-subs])

(defn show-device []
  (let [android? (subscribe [::mobile-subs/android?])
        ios? (subscribe [::mobile-subs/ios?])]
    (fn []
     [:div
      (cond
       @android? [:span "You are on an Android device."]
       @ios? [:span "You are on an iOS (iPhone, iPad) device."]
       :else [:span "We don't know if you're on a mobile device."])])))

Another use-case is determining if the device is coinbase-compatible.

;; re-frame view file
(require '[re-frame :refer [subscribe]])
(require '[district.ui.mobile.subs :as mobile-subs])

(defn coinbase-dialog []
  (let [coinbase-compatible? (subscribe [::mobile-subs/coinbase-compatible?])]
    (fn []
     [:div
      (if @coinbase-compatible?
        [:span "Mobile device is coinbase compatible."]
        [:span "Device is not coinbase compatible."])])))

API Overview

district.ui.mobile

This namespace contains the mobile mount module.

You can pass the following args while initiating this module:

  • :force-mobile-device Used to imitate a mobile browser. Accepts one of the values: true (android), :android, :ios, or false. By default, this value is set to false.

For example, if I wanted to imitate an iOS device:

(ns my-district.core
 (:require [mount.core :as mount]
           [district.ui.mobile]
           ;;...
           ))

(-> (mount/with-args
     {:mobile {:force-mobile-device :ios}
      ;; Additional mount options...
      })
    (mount/start))

district.ui.mobile.subs

re-frame subscriptions provided by this module:

::android? []

Returns true if an Android mobile device is viewing the web application, otherwise false

::ios? []

Returns true if an iOS mobile device (iPhone, iPad) is viewing the web application, otherwise false.

::coinbase-compatible? []

Returns true if an coinbase-compatible mobile device is viewing the web application, otherwise false.

Development

Testing

$ lein doo

Download Details:
Author: district0x
Source Code: https://github.com/district0x/district-ui-mobile
License: EPL-1.0 License

#blockchain   #cryptocurrency   #district0x   #web3   #clojure 

District UI Module for Mobile Browser Integration
Best of Crypto

Best of Crypto

1650716040

District UI for Web3 Sync

district-ui-web3-sync-now

Clojurescript re-mount module, that synchronises UI time with the blockchain time.

Installation

Add [district0x/district-ui-web3-sync-now "1.0.3-2"] into your project.clj. Include [district.ui.web3-sync-now] in your CLJS file, where you use mount/start.

API Overview

Warning: district0x modules are still in early stages, therefore API can change in a future.

district.ui.web3-sync-now

This namespace contains now mount module. This module has no configuration parameters.

(ns my-district.core
  (:require [mount.core :as mount]
            [district.ui.now]
            [district.ui.web3]
            [district.ui.web3-sync-now]
            [district.ui.logging]))

(-> (mount/with-args {:logging {:level :info}
                      :web3 {:url "http://127.0.0.1:8549"}})
    (mount/start))

After the :start lifecycle method gets called this module waits for the :district.ui.web3.events/web3-created event and sets :district.ui.now.subs/now time to the last block time on the blockchain. Set the logging level to get notified of errors and/or successfull events.

district.ui.web3-sync-now.events

re-frame events provided by this module:

::increment-now

Event to increment now time in a re-frame db and the (testrpc) blockchain time by a number of seconds.

(ns my-district.core
  (:require [district.ui.web3-sync-now.events :as sync-now-events]
            [re-frame.core :as re-frame]))

(re-frame/dispatch [::sync-now-events/increment-now 300])

Errors and successfully handled events will be logged to the JS console.

::block-number

This is an utility event called by the :start lifecycle method of the module. It wraps the re-frame-web3-fx web3/call effect and chains the returned last block number to the ::get-block event. In a typical application you will never need to call this event yourself.

::get-block

This is an utility event which wraps the re-frame-web3-fx web3/call effect and chains the returned last block object to the ::set-now. In a typical application you will never need to call this event yourself.

::set-now

This is an utility event which sets the :district.ui.now.subs/now time from the last block time. Upon success it will log to the JS console. In a typical application you will never need to call this event yourself.

Development

Run test suite:

lein deps
# To run tests and rerun on changes
lein doo chrome tests

Install into local repo:

lein install

Download Details:
Author: district0x
Source Code: https://github.com/district0x/district-ui-web3-sync-now
License: EPL-1.0 License

#blockchain   #cryptocurrency   #district0x   #web3   #clojure 

District UI for Web3 Sync
Best of Crypto

Best of Crypto

1650708720

District UI Component for Calendar Reminders

district-ui-component-add-to-calendar

Clojurescript mount + re-frame component for a district UI, that provides reagent UI component for adding calendar reminders. Works with Google Calendar and Apple Calendar.

Installation

Add [district0x/district-ui-add-to-calendar "1.0.0"] into your project.clj.
Include [district.ui.component.add-to-calendar] in your CLJS file.

Usage

district.ui.component.add-to-calendar

This namespace contains reagent UI component.

Basic usage example:

(ns my-district
  (:require [cljs-time.core :as t]
            [reagent.core :as r]
            [district.ui.component.add-to-calendar :as add-to-calendar]))

(defn main-panel []
  [:div#page1 [add-to-calendar/add-to-calendar {:title "Test"
                                                :url "https://district0x.io"
                                                :description "description"
                                                :start-time (t/now)
                                                :end-time (t/now)}]])

(defn ^:export init []
  (r/render [main-panel] (.getElementById js/document "app")))

Download Details:
Author: district0x
Source Code: https://github.com/district0x/district-ui-component-add-to-calendar
License:

#blockchain   #cryptocurrency   #district0x  #web3   #clojure 

District UI Component for Calendar Reminders
Best of Crypto

Best of Crypto

1650701400

District0x Tasks: Voting Dapp to Assign Project Work To Contractors

district0x-tasks

Development

First time run

lein deps

Compile contracts (assumes you have solc installed):

lein solc

Auto compile contracts on changes:

lein solc auto

Start server:

ganache-cli -d -p 8545 -m district0x
lein repl
(start-server!)
node dev-server/district0x-tasks.js

Start UI:

lein garden once
lein repl
(start-ui!)
# go to http://localhost:4598/

How to do tests:

ganache-cli -d -p 8545 -m district0x
lein test-doo

If change contracts code:

; auto compile Solidity code in project when files changed
lein solc auto

Remember this doesn't trigger cljs tests. So you have to change cljs tests files to trigger. For example add new line.

QA env and Dockerfiles

See docker-compose file in https://github.com/district0x/pipelines

Download Details:
Author: district0x
Source Code: https://github.com/district0x/district0x-tasks
License: EPL-1.0 License

#blockchain   #cryptocurrency  #district0x   #web3   #clojure 

District0x Tasks: Voting Dapp to Assign Project Work To Contractors