GithubHelp home page GithubHelp logo

swirrl / grafter Goto Github PK

View Code? Open in Web Editor NEW
184.0 28.0 17.0 6.35 MB

Linked Data & RDF Manufacturing Tools in Clojure

License: Eclipse Public License 1.0

Clojure 94.06% Shell 0.91% Java 5.04%
clojure etl linked-data rdf semantic-web data grafter

grafter's Introduction

Grafter - Linked Data & RDF Processing

Clojars Project | Clojars Project | Clojars Project

"For the hard graft of linked data processing."

Grafter is a Clojure library for linked data processing. It is mature and under active development.

It provides support for all common RDF serialisations and includes a library of functions for querying and writing to SPARQL repositories.

It is split into three sub-projects with their own dependency packages

  • io.github.swirrl/grafter.repository {:mvn/version "3.0.0"} (SPARQL repositories via RDF4j)
  • io.github.swirrl/grafter.io {:mvn/version "3.0.0"} (Reading/Writing RDF formats via RDF4j)
  • io.github.swirrl/grafter.core {:mvn/version "3.0.0"} (RDF protocols - independent of RDF4j)

Prerequisites

  • Java 17
  • Clojure 1.11.1

FAQ

Where can I find the api-docs?

Legacy docs

Didn't grafter also contain tools for tabular processing?

As of 0.9.0 the grafter.tabular library has been moved into a separate repository so the core grafter library can focus on processing linked data.

This part of the library is now considered deprecated. If you depend on it you can still use it, and it may receive occasional maintainance updates.

If you're looking to start a greenfield project then you can easily wire up any capable CSV/excel parser to the RDF processing side of grafter.

License

Copyright © 2014 Swirrl IT Ltd.

Distributed under the Eclipse Public License version 1.0, the same as Clojure.

grafter's People

Contributors

andrewmcveigh avatar benswirrl avatar billswirrl avatar callum-oakley avatar kieranlives avatar kiramclean avatar lkitching avatar martinklepsch avatar nterpo avatar otfrom avatar rickmoynihan avatar ricswirrl avatar robsteranium avatar scottlowe avatar the-frey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grafter's Issues

Rename s function to literal

"Probably good reason for this, but my initial impression is that I'm not fond of the s function name. I can see that you want a short name, and that it is used everywhere so you want to reduce line noise… but given that it creates an RDF literal, why not call it lit or literal? Also makes executing a global find difficult and refactoring a pain, as well as other kinds of searches - google etc"

Strings in the lang-or-uri position should be treated as a URI for a datatype not a language tag.

grafter.rdf.io/ISesameRDFConverter fails for common string values

short of delegating to a generic function which can be specialized per iri scheme, it would be most useful, were the conversion to make at least the most obvious distinctions, as in:

(extend java.lang.String
 grafter.rdf.io/ISesameRDFConverter
 {:->sesame-rdf-type (fn [this] (if (re-matches #"(urn|http|https):.*" this) (URIImpl. this) (LiteralImpl. this)))
 })

Remove Triple records - we should just use Quad everywhere

Having both Triple and Quad records causes problems with equality.

We should unify everything to be a Quad (which will still extend the Statement protocol).

If you want a Quad to be a Triple, you should just assign it a nil :c.

We may also want to add a predicate triple? function that tests if (nil? (:c quad)).

Any functions that return triples such as triplify should return Quads.

Remove unused functions

There seems to be a few unused functions and namespaces dotted about - could be historical, i.e. part of the development process over the last few months. Some functions I can assume are part of the API that is being offered, so that’s a potential reason that they aren’t used, but there are also some private function definitions defn- that can’t be explained by that.

My personal rule is that if unused blocks of code are hanging around for more than a few days, then they should be deleted. We can always go back and have a look in source control, if we change our minds.

Example of private unused funcs: grep-row and remove-indices in grafter/tabular.clj.

Another public function which isn't called in the codebase is tabular/rename-columns - again, perhaps this is to be consumed by an API user, but given that it is non-trivial, perhaps this should be tested?

query function should convert sesame types into clojure/grafter ones

Currently types aren't round tripped, and the types we return are sesame ones.

We need to round trip types so that:

  • SesameURI's come back java.net.URI's (which can be used with the grafter-url protocols/libraries)
  • literals with an appropriate sesame-rdf-type->type function are converted to the appropriate grafter/clojure type
  • un-coerced literals come back as a Literal object.

Before we do this work we also need to deprecate the s function and represent Literals explicitly #24; and also interpret strings as string literals #25.

Calling statements on a repository should return results from default graph

There are methods already in sesame which we could leverage to do this... with a thread to pipe things into a sequence etc...

(let [r (repo)]
  (grafter.rdf.protocols/add r [(grafter.rdf.protocols/->Quad ":a" ":a" ":a" nil) (grafter.rdf.protocols/->Quad ":a" ":a" ":a" ":c")])
  (.exportStatements
   (->connection r) nil nil nil false
   (reify org.openrdf.rio.RDFHandler
     (handleStatement [this statement]
       (println statement))
     (handleNamespace [this prefix uri]
       ;;TODO: are namespaces re-written? Need to re-write results if
       ;;so...
       (println prefix))
     (startRDF [this] (println "start"))
     (endRDF [this] (println "end"))
     (handleComment [this comment] (println "comment"))) (into-array Resource [])))

Support Ragged Rows in CSV

read-dataset should support a way of loading :ragged-rows.

One approach might be to have a :ragged-rows option to read-dataset that when supplied provides a quick method of finding the number of columns on the widest row. The cost of this is that it will need to do two passes over the file.

NOTE: If we do this we need to be careful not to hold onto the head of the sequence of rows.

An alternative might be to provide a :with-header-row option that lets you supply a header row, or a function to load one. If supplied a function the function will receive a dataset as an argument and be able to perform a pass over it to find a header row.

Calling add multiple times on the same rdf-serializer causes prefixes to be written multiple times when :append true is set

This is a little awkward and will likely require breaking grafter API changes to the way add/rdf-serializer work.

Basically the problem is that if you have code like this:

(let [quads ,,,
       dest (rdf-serializer "/tmp/foo.trig" :append true)]
   (add dest quads)
   (add dest more-quads))

Each add will cause the default prefixes to be written to the stream. Sesame/RDF4j's behaviour might be at fault, though arguably we're just using their API wrong, as you can work around it.

e.g. you might end up with this:

@prefix g: <http://example.org/graph/> .
@prefix exid: <http://example.org/id/> .

g:1 {
   exid:keep-me exid:keep-me exid:keep-me .
}

@prefix g: <http://example.org/graph/> .
@prefix exid: <http://example.org/id/> .

g:2 {
   exid:keep-me exid:keep-me exid:keep-me .
}

Obviously you just want the prefixes to be written once.

I have worked around this on my project by defining the following functions, though a more general solution would probably be desirable:

(ns grafter.migrate.rdf-writer
  (:require [clojure.java.io :as io]
            [grafter.rdf :as rdf]
            [grafter.rdf
             [io :as rio]
             [protocols :as pr]
             [repository :as repo]]
            [me.raynes.fs :as fs])
  (:import java.io.File
           org.openrdf.repository.Repository
           org.openrdf.rio.RDFFormat
           org.openrdf.rio.Rio))

;; NOTE this namespace contains some functions copied and modified
;; from grafter for adding to an RDF graph.

(defn rdf-serializer
  "Coerces destination into an java.io.Writer using
  clojure.java.io/writer and returns an RDFSerializer.

  Accepts also the following optional options:

  - :append        If set to true it will append new values to the end of
                   the file destination (default: `false`).

  - :format        If a String or a File are provided the format parameter
                   can be optional (in which case it will be infered from
                   the file extension).  This should be a sesame RDFFormat
                   object.

  - :encoding      The character encoding to be used (default: UTF-8)  "

  ([destination & {:keys [append format encoding] :or {append false
                                                                encoding "UTF-8"}}]

   (let [^RDFFormat format (#'rio/resolve-format-preference destination format)
         writer (Rio/createWriter format
                                  (io/writer destination
                                             :append append
                                             :encoding encoding))]

     writer)))

(defn- write-prefixes [writer prefixes]
  (reduce (fn [acc [name prefix]]
               (doto writer
                 (.handleNamespace name prefix))) writer prefixes))

(defn start-rdf [writer prefixes]
  (.startRDF writer)
  (write-prefixes writer prefixes)
  writer)

(defn end-rdf [writer]
  (.endRDF writer))

(defn add! [writer quads]
  (cond
    (seq quads)
    (do
      (doseq [t quads]
        (pr/add-statement writer t)))
    :else (throw (IllegalArgumentException. "This serializer was given an unknown type it must be passed a sequence of Statements."))))

(defn- start-rdf* [[symbol-binding _]]
  `(start-rdf ~symbol-binding rio/default-prefixes))

(defn- end-rdf* [[symbol-binding _]]
  `(end-rdf ~symbol-binding))

(defmacro with-rdf-writer [bindings & forms]
  (let [vars (partition 2 bindings)]
    `(let ~bindings
       (do
         ~@(map start-rdf* vars)
         ~@forms
         ~@(map end-rdf* vars)))))

(comment 
  ;; usage
(with-rdf-writer [a (rio/rdf-serializer "/tmp/fooobar.trig" :append true) 
                   b (rio/rdf-serializer "/tmp/fooobarbaaaaaaz.trig")] 
     (add! a [(rdf/->Quad (java.net.URL. "http://a") (java.net.URL. "http://a") (java.net.URL. "http://a") (java.net.URL. "http://a"))]) 
     (add! a [(rdf/->Quad (java.net.URL. "http://a") (java.net.URL. "http://a") (java.net.URL. "http://a") (java.net.URL. "http://a"))]) (add! a [(rdf/->Quad (java.net.URL. "http://b") (java.net.URL. "http://b") (java.net.URL. "http://b") (java.net.URL. "http://a"))]))

Miscellaneous new dataset functions

@Robsteranium I saw these in one of your pipelines...

We should consider adding some new dataset functions... or supporting their usecases somehow:

(defn drop-columns [dataset cols-to-drop]
                   (let [selected-columns (remove (set cols-to-drop) (column-names dataset))]
                     (columns dataset selected-columns)))

(defn select-columns [dataset selector-fn]
  (let [selected-columns (filter selector-fn (column-names dataset))]
    (if (empty? selected-columns)
      (throw (RuntimeException. "No columns selected"))
      (columns dataset selected-columns))))

(defn drop-where [dataset pred column-or-columns]
  (if (sequential? column-or-columns)
    (letfn [(drop-where-reverse [pred column dataset] (drop-where dataset pred column))]
      ((apply comp (for [column column-or-columns]
                     (partial drop-where-reverse pred column))) dataset))
    (transform-rows dataset (fn [rows] (remove #(pred (% column-or-columns)) rows)))))

(defn take-where [dataset pred column]
  (transform-rows dataset (fn [rows] (filter #(pred (% column)) rows))))

(defn mapcat-rows [dataset f]
  (transform-rows dataset (fn [rows] (mapcat f rows))))

Can't supply Readers or InputStreams to read-dataset

Calling read-dataset on a Reader or InputStream should work but the dispatch chain results in an infinite loop.

This is a required feature so users can manage the open/closing of dataset files:

Currently throws a stackoverflowexception when calling

 (with-open [r (io/input-stream "/tmp/csv.clj")]
  (read-dataset r :format :csv))

should also support Reader too.

1. Unhandled java.lang.StackOverflowError
   (No message)

        PersistentHashMap.java:  580  clojure.lang.PersistentHashMap$BitmapIndexedNode/index
        PersistentHashMap.java:  680  clojure.lang.PersistentHashMap$BitmapIndexedNode/find
        PersistentHashMap.java:  152  clojure.lang.PersistentHashMap/valAt
        PersistentHashMap.java:  156  clojure.lang.PersistentHashMap/valAt
                  MultiFn.java:  147  clojure.lang.MultiFn/getMethod
                  MultiFn.java:  158  clojure.lang.MultiFn/getFn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn
                  MultiFn.java:  231  clojure.lang.MultiFn/invoke
                    common.clj:  134  grafter.tabular.common/eval30980/fn

Add simple coercions for numeric types

I think we need protocol based coercers for coercing strings into specific numeric types etc (and some general ones too).

Probably in a namespace like grafter.tabular.coercers or grafter.coercions.

  • (->int "10") (->int 10)
  • (->double "10.0") (->double 10.0)
  • (->float "5.5")
  • (->byte "128")
  • ... one for all java/clj numeric types

And a more generic one that coerces more like you do there - by looking for .:

  • (->number "10.21")

They should probably raise an exception on an invalid parse.

Add a .gitignore in grafter template

Consider adding a .gitignore to the template with the usual lein and general java-world ignores, i.e. Eclipse, IntelliJ. This will make for a really good (and smooth) first impression upon a developer using Grafter for the first time.

pom.xml
pom.xml.asc
*jar
/lib/
/classes/
/target/
/checkouts/
.lein-deps-sum
.lein-repl-history
.lein-plugins/
.lein-failures
.nrepl-port

*.iml
.idea/
*.ipr
*.iws

out/
.idea_modules/

Investigate repack errors & enable repacked builds

I've had to disable our use of lein-repack to generate smaller isolated grafter dependencies from a single grafter source tree.

If you lein repack install grafter create a template project and run:

$ lein grafter run test-project.pipeline/convert-persons-data-to-graph ./data/example-data.csv output.nt

You get an error. You'll get the same error at a repl too if you try and use

(grafter.rdf.io/->sesame-rdf-type (grafter.rdf.protocols/->Triple "http://foo" "http://foo" "http://foo" ))

See stack below:

(:repositories detected in user-level profiles! [:user] 
See https://github.com/technomancy/leiningen/wiki/Repeatability)
Exception in thread "main" java.lang.IllegalArgumentException: No implementation of method: :->sesame-rdf-type of protocol: #'grafter.rdf.io/ISesameRDFConverter found for class: grafter.rdf.protocols.Quad, compiling:(/private/var/folders/6j/vpfh3hk97mq82r9nmq7d2h0h0000gn/T/form-init6041481122296038594.clj:1:124)
    at clojure.lang.Compiler.load(Compiler.java:7142)
    at clojure.lang.Compiler.loadFile(Compiler.java:7086)
    at clojure.main$load_script.invoke(main.clj:274)
    at clojure.main$init_opt.invoke(main.clj:279)
    at clojure.main$initialize.invoke(main.clj:307)
    at clojure.main$null_opt.invoke(main.clj:342)
    at clojure.main$main.doInvoke(main.clj:420)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: No implementation of method: :->sesame-rdf-type of protocol: #'grafter.rdf.io/ISesameRDFConverter found for class: grafter.rdf.protocols.Quad
    at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:544)
    at grafter.rdf.io$eval18997$fn__18998$G__18988__19003.invoke(io.clj:39)
    at grafter.rdf.io$eval19243$fn__19252.invoke(io.clj:358)
    at grafter.rdf.protocols$eval18708$fn__18709$G__18699__18722.invoke(protocols.clj:11)
    at grafter.rdf.io$eval19243$fn__19244.invoke(io.clj:366)
    at grafter.rdf.protocols$eval18708$fn__18730$G__18697__18761.invoke(protocols.clj:11)
    at grafter.rdf$add.invoke(rdf.clj:55)
    at user$eval10543.invoke(form-init6041481122296038594.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6693)
    at clojure.lang.Compiler.eval(Compiler.java:6693)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    ... 11 more
Subprocess failed

Support prefixes in RDF serialisations

It would be good to support prefixes when serialising to formats that support them e.g. turtle / trig etc...

It can be a pain to read serialisations that don't have prefixes defined because of URI blindness.

This should already be supported in sesame, so we should find a way to expose it and make use of it in grafter.

Numeric column headings are ambiguous with positional access

Integer column headings don't work properly with things like rename-columns/derive-column etc...

The problem is that we assume numeric headings are positional access - not the values themselves. Ideally we'd have a way to distinguish between positional lookups and numeric column headings.

This returns: bb not cc because of the ambiguity.

(-> (grafter.tabular/make-dataset [["a" "b" "c"]] [3 2 1]) (grafter.tabular/derive-column :foo [1 2] str))
;; => 
| 3 | 2 | 1 | :foo |
|---+---+---+------|
| a | b | c |   bb |

When there is no ambiguity (i.e. the column headings don't overlap with the column-positions) things work as expected.

Validation functions for dataset tables

It would be good to be able to validate datasets easily, useful for both raising errors on inputs and validating data is what you want in unit tests etc...

e.g. validate arbitrary cell positions with predicate functions:

(validate ds [[integer? string?] [string? integer?]])

and more commonly validating by columns e.g.

(validate ds {"a" integer? "b" string?})

validate should probably return the ds if successful, or some kind of validation error if not. Errors should be located in the cells where the occurred with info about what data in the cell was invalid etc..

Also should consider how to contextualise error messages, and allow custom messages etc...

Add a simple pipe debug function

Simple pipe debug function

Perhaps this already exists and I've missed this in the codebase, but I really want to see what's going on in the pipeline. I'd imagine that some real-world pipelines would contain many more steps than the convert-persons-data example.

I'd like to see the inclusion of some simple functions that help debug each step of the data tranformation. Clearly we have tools like dotrace at our disposal, but they don't know how to print Datasets. For example, I'd like to see something like this added to the grafter.tabular namespace:

(defn debug-ds
  "Pretty print a dataset & return the dataset. Useful for debugging pipelines.
  Takes an optional output label which will help distinguish multiple outputs"
  ([dataset]
    (debug-ds dataset nil))
  ([dataset label]
    (do
      (when label
        (println label))
      (clojure.pprint/print-table (:column-names dataset)
                                  (:rows dataset))
      dataset)))

Would be used like any other pipeline function and deleted when debugging is over:

(defpipe convert-persons-data
  "Pipeline to convert tabular persons data into a different tabular format."
  [data-file]
  (-> (read-dataset data-file)
      (drop-rows 1)
      (debug-ds "Rows dropped")
      (make-dataset [:name :sex :age])
      (derive-column :person-uri [:name] base-id)
      (mapc {:age ->integer
             :sex {"f" (s "female")
                   "m" (s "male")}})))

As you might expect, the REPL output displays intermediate Dataset stage:

(convert-persons-data "./data/example-data.csv")
Rows dropped

|     a | b |  c |
|-------+---+----|
| Alice | f | 34 |
|   Bob | m | 63 |
=> 
| :name |   :sex | :age |                   :person-uri |
|-------+--------+------+-------------------------------|
| Alice | female |   34 | http://my-domain.com/id/Alice |
|   Bob |   male |   63 |   http://my-domain.com/id/Bob |

This somewhat naïve implementation might be useful enough as is. Clearly this should only be used on a small sample of data because all that IO and side effects would be a terrible.

Maybe be some sort of threading debug macro e.g. dbg-> would be more useful, because you could then simply rename the normal Thread First Macro in-place.

Errors whilst consuming SPARQL results lack a proper stacktrace

e.g. If a query timesout it doesn't include information about where in the application it died. The stacktrace is for the I/O thread, not the application thread.

#error {
 :cause "Premature end of file."
 :via
 [{:type org.openrdf.query.QueryEvaluationException
   :message "org.openrdf.query.resultio.QueryResultParseException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file."
   :at [org.openrdf.http.client.QueueCursor checkException "QueueCursor.java" 170]}
  {:type org.openrdf.query.resultio.QueryResultParseException
   :message "org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file."
   :at [org.openrdf.query.resultio.sparqlxml.SPARQLXMLParserBase parseQueryResultInternal "SPARQLXMLParserBase.java" 140]}
  {:type org.xml.sax.SAXParseException
   :message "Premature end of file."
   :at [com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser parse "AbstractSAXParser.java" 1239]}]
 :trace
 [[com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser parse "AbstractSAXParser.java" 1239]
  [com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser parse "SAXParserImpl.java" 649]
  [info.aduna.xml.SimpleSAXParser parse "SimpleSAXParser.java" 226]
  [info.aduna.xml.SimpleSAXParser parse "SimpleSAXParser.java" 201]
  [org.openrdf.query.resultio.sparqlxml.SPARQLXMLParserBase parseQueryResultInternal "SPARQLXMLParserBase.java" 124]
  [org.openrdf.query.resultio.sparqlxml.SPARQLResultsXMLParser parseQueryResult "SPARQLResultsXMLParser.java" 84]
  [org.openrdf.http.client.BackgroundTupleResult run "BackgroundTupleResult.java" 102]
  [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1142]
  [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 617]
  [java.lang.Thread run "Thread.java" 745]]}

all-columns / columns

(columns (test-dataset 5 20) [:A :B :D :C])
; =>

| A | B | D |
|---+---+---|
| 0 | 0 | 0 |
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 4 | 4 |

The above should return a dataset containing the columns :A :B :C :D.

It doesn't go back and get :C. Because it makes a confused assumption that a dataset might be infinite in its columns.

However because of the row oriented nature of most file formats (e.g. csv) Datasets are almost always large in rows not in columns.

As columns is simply selecting a subset of columns from a finite list/vector of columns, it should (take (count (:column-names ds)) cols) to crop the potentially infinite sequence to the dataset and then find all of them.

Once we do this, there will be no need for remove all-columns, and we can just remove it.

trying to run the example project

lein grafter run test-project.pipeline/import-persons-data ./data/example-data.csv example-output.ttl
WARNING: update already refers to: #'clojure.core/update in namespace: incanter.core, being replaced by: #'incanter.core/update
Exception in thread "main" java.lang.NullPointerException, compiling:(/private/var/folders/pn/_m3b0pln25xc11zz37j0zfyh0000gn/T/form-init3936602071082137904.clj:1:125)
at clojure.lang.Compiler.load(Compiler.java:7239)
at clojure.lang.Compiler.loadFile(Compiler.java:7165)
at clojure.main$load_script.invoke(main.clj:275)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invoke(main.clj:308)
at clojure.main$null_opt.invoke(main.clj:343)
at clojure.main$main.doInvoke(main.clj:421)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.NullPointerException
at clojure.core$apply.invoke(core.clj:630)
at grafter.pipeline$execute_pipeline_with_coerced_arguments.invoke(pipeline.clj:73)
at user$eval12272.invoke(form-init3936602071082137904.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6772)
at clojure.lang.Compiler.eval(Compiler.java:6772)
at clojure.lang.Compiler.load(Compiler.java:7227)
... 11 more
Subprocess failed

Wherever grafter takes a :format param we should accept a mime-type or a keyword

Wherever grafter takes a :format param we should accept a mime-type or a keyword as well as an RDFFormat object.

We should coerce representations of rdf formats into RDFFormat objects e.g. these three things should work:

(statements "foo.ntriples" :format rdf-format-ntriples)
(statements "foo.ntriples" :format "application/ntriples")
(statements "foo.ntriples" :format :nt)

Use grafter-config.edn to provide metadata on pipelines instead of declare-pipeline

We should deprecate declare-pipeline for a pipeline-manifest.edn configuration file, which would provide additional flexibility.

e.g.

​{ sns2rdf.update/update-dataset
  { :name "Spreadsheet to datacube"
    :description "blah blah blah"
    ;; positional
    :arguments [{:name "Dataset"
                         :description "Select a Dataset"
                         :widget URI
                         :pmd/dataset-selector true }
                        {:name "Spreadsheet"
                         :description "blah blah"
                         :widget Dataset}]
    :output [Quad]
    :pmd/group :importers
  } 
​
  ;; ... more pipelines 
}

We should require many of the above keys, but also allow arbitrary other keys, e.g. :pmd/group which can be passed on to other services etc.

The grafter leiningen plugin and other services can then make use of these manifests to provide UI components and coercions to pipelines.

We should name these manifests grafter-config.edn - as we can now just require the namespaces from the keys that provide the pipeline var names.

the api and implementation should define clear extension points for data conversion between dataset and repository domains

in order to effect a minimal conversion of the data retrieved by a query from a repository, it was necessary to either filter the result dataset to convert all cell values or to intervene in the initial construction process.
the latter recommends itself with respect to both scaling and facility.
while the implementation implies a facility at the point of solution-to-map conversion

  • it is unclear how to get at that through the query operator
  • it serves only as an indirect means to affect the cell value conversion.

one alternative would be to provide a generic cell conversion function as the default.

(defmulti term-value class)
(defmethod term-value org.openrdf.model.Literal [literal] (literal-datatype->type literal))
(defmethod term-value org.openrdf.model.URI [uri] (.toString uri))
(defmethod term-value org.openrdf.model.BNode [node] (clojure.string/join ["_:" (.getID node)]))

;;; from grafter/repository.clj                                                                                                                       \

(defn query-bindings->map [^org.openrdf.query.BindingSet qbs]
  (let [boundvars (.getBindingNames qbs)]
    (->> boundvars
         (mapcat (fn [k]
                   [(symbol k) (-> qbs (.getBinding k) .getValue term-value)]))
     (apply hash-map))))

(defn query-results-seq [results]
  (if (.hasNext results)
      (let [current-result (try
                    (query-bindings->map (.next results))
                    (catch Exception e
                           (.close results)
                           (throw e)))]
(lazy-cat [current-result] (query-results-seq results)))
      (.close results)))

another would be to provide a means to specify one through the higher level api.

sesame-results->seq (and therby evaluate) fails with an invokeNoArgInstanceMember exception

neither a direct invocation, nor an invocation via grafter.rdf.repository/evaluate succeeds:

grafter.rdf.repository=> (def query (.prepareTupleQuery connection org.openrdf.query.QueryLanguage/SPARQL "SELECT * WHERE {?s ?p ?o}"))
#'grafter.rdf.repository/query
grafter.rdf.repository=> query
#<SailTupleQuery DydraQueryRoot
   Projection
      ProjectionElemList
         ProjectionElem "s"
         ProjectionElem "p"
         ProjectionElem "o"
      StatementPattern
         Var (name=s)
         Var (name=p)
         Var (name=o)
>
grafter.rdf.repository=> (def results (.evaluate query))
#'grafter.rdf.repository/results
grafter.rdf.repository=> results
#<TupleQueryResultImpl org.openrdf.query.impl.TupleQueryResultImpl@67a95db>
grafter.rdf.repository=> (instance? info.aduna.iteration.CloseableIteration results)
true
grafter.rdf.repository=> (.close results)
nil
grafter.rdf.repository=> (sesame-results->seq query query-bindings->map)

NoSuchMethodError clojure.lang.Reflector.invokeNoArgInstanceMember(Ljava/lang/Object;Ljava/lang/String;Z)Ljava/lang/Object;  grafter.rdf.repository/sesame-results->seq (repository.clj:287)       
grafter.rdf.repository=> (use 'clojure.stacktrace)
nil
grafter.rdf.repository=> (print-stack-trace *e)
java.lang.NoSuchMethodError: clojure.lang.Reflector.invokeNoArgInstanceMember(Ljava/lang/Object;Ljava/lang/String;Z)Ljava/lang/Object;                                                             
 at grafter.rdf.repository$sesame_results__GT_seq.invoke (repository.clj:287)
    grafter.rdf.repository$eval2401.invoke (form-init5044810080896752162.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:6619)
    clojure.lang.Compiler.eval (Compiler.java:6582)
    clojure.core$eval.invoke (core.clj:2852)
    clojure.main$repl$read_eval_print__6588$fn__6591.invoke (main.clj:259)
    clojure.main$repl$read_eval_print__6588.invoke (main.clj:259)
    clojure.main$repl$fn__6597.invoke (main.clj:277)
    clojure.main$repl.doInvoke (main.clj:277)
    clojure.lang.RestFn.invoke (RestFn.java:1523)
    clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__1761.invoke (interruptible_eval.clj:72)
    clojure.lang.AFn.applyToHelper (AFn.java:159)
    clojure.lang.AFn.applyTo (AFn.java:151)
    clojure.core$apply.invoke (core.clj:617)
    clojure.core$with_bindings_STAR_.doInvoke (core.clj:1788)
    clojure.lang.RestFn.invoke (RestFn.java:425)
    clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke (interruptible_eval.clj:56)
    clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__1803$fn__1806.invoke (interruptible_eval.clj:191)
    clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__1798.invoke (interruptible_eval.clj:159)
    clojure.lang.AFn.run (AFn.java:24)
    java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1145)
    java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:615)
    java.lang.Thread.run (Thread.java:745)
nil

query functions should convert data into values in domains supported by incanter

alternative to the suggestion embodied in #40, it should be possible to move data between datasets and both external files and repositories (through queries or as imports) under the principle, that the dataset cell content is limited to values in domains which incanter supports and that a conversion is available to the external and repository domains which "does the right thing" by default.

this implies, for example, that dataset cell content should be restricted to numeric and string values and that literal conversion to and from a repository should account for standard encodings for blank nodes, and iri as domains distinct from various literals.

while a complete implementation which includes excel sources should conform to csv2rdf and, as such should permit to specify datatype metadata for csv sources, at a baseline and in the absence of metadata, the process should at least correspond to the standard for sparql csv results
for csv-rdf conversion.

this would permit "least surprise" conversions with no intervention.

Error loading on OSX 10.10

I have java version "1.6.0_65" installed on OS X and when I run lein repl in the test project I get the error below. Just wondering if you have come across this and know a quick fix?

...
Retrieving slingshot/slingshot/0.10.3/slingshot-0.10.3.jar from clojars
Retrieving net/mikera/core.matrix/0.7.2/core.matrix-0.7.2.jar from clojars
Retrieving com/novemberain/pantomime/2.4.0/pantomime-2.4.0.jar from clojars
Could not find artifact com.sun:tools:jar:1.5 at specified path /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/../lib/tools.jar

I dont get this from testing with a regular clojure project, so I assume its related to one of the dependencies of grafter.

Canonicalise column names/keys to keywords

Incanter's use of string keys and/or keyword keys to identify columns is brittle and confusing.

We should move to a model where column names are always with Grafter uniformly keywords. Whereever you expressed a column name before should become a keyword, (e.g. (derive-column "a" [:a "b"] +) should become (derive-column :a [:a :b] +)

  • Column names should still be canonicalised into a keyword for storage in the dataset.
  • Column names which are referenced for reads should also be identifiable by their position (as they are currently), e.g. cases like (derive-column :sum (range 0 5)) should work.

For interop with incanter/core.matrix etc... we should also add a function that enforces this constraint on incoming datasets.

Correctly open Excel files with the right dimensions

Excel files like this one:

SttsNZ-Pivot-2.xlsx

are misinterpreted by Grafters Datasets. Grafter will incorrectly load this as containing one or two columns (I forget which), because it assumes Datasets have the same width as their first row.

It seems Apache POI has a method to get the Dimensions of the sheet, we see whether we can use this. Or perhaps modify clj-excel to support it:

http://stackoverflow.com/questions/5778599/how-to-get-the-max-no-of-columns-filled-in-an-xlsx-file-using-poi

A similar issue #46 exists in CSV files, if the first row isn't as wide as the widest row.

Allow SPARQL bindings to be programatically set

It's useful to be able to set bindings ontop of SPARQL queries, allowing an underlying query to be used as a kind of template.

JENA does something like this, and yesparql exposes it. Unfortunately we use sesame/RDF4j, so can't use yesparql.

However sesame/RDF4j do support something similar by setting bindings! See here for a branch implementing this with grafter.

Unfortunately this relies on Sesame/RDF4j doing this, and Sesame doesn't have some features we'd like:

  • Being able to set LIMIT and OFFSETs (not supported in Sesame because LIMIT/OFFSET according to the SPARQL grammar can't take a variable; and therefore they can't be provided as "bindings"
  • VALUES being able to provide values would be good too... e.g. providing [1 2 3 4] to ?foo might result in:
SELECT * WHERE { 
   VALUES ?foo {}
}   
SELECT * WHERE { 
   VALUES ?foo { 1 2 3 4 }
}   

For background also see this discussion I brought up on the RDF4j mailing list, and also this discussion about binding semantics on the RDF4j mailing list

Because of these limitations it seems we might need to implement these features as a pre-process step, ideally using a proper SPARQL parser. We might be able to implement such a parser relatively easily ourselves in clojure using Instaparse and running it over the SPARQL 1.1 EBNF grammar, after processing the string with our parser we'd then want to unparse it back into a string and submit it to RDF4j/Sesame.

In the interim we could probably add this by using a dirty regex to replace LIMIT ?varname/OFFSET ?othervarname with values supplied in our bindings map.

Demystify datasets

The pipeline section in the Docs mentions Datasets a great deal and they seemed like something mysterious and complex to me initially until I dumped on to the REPL. It's probably worth mentioning that they are simply records with :column-names and :rows, e.g.:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.