├── resources └── VERSION ├── samples ├── test.edn └── test.json ├── tests.edn ├── .gitignore ├── src ├── app │ ├── json.clj │ ├── edn.clj │ ├── json │ │ └── bb.clj │ └── main.clj └── tabl │ └── format │ ├── k8s.clj │ └── markdown.clj ├── dev └── fiddle │ ├── main.clj │ └── formats.clj ├── CHANGES.md ├── scripts └── compile ├── pod_test.clj ├── deps.edn ├── test └── app │ └── main_test.clj ├── README.md └── LICENSE /resources/VERSION: -------------------------------------------------------------------------------- 1 | 0.4.0-SNAPSHOT 2 | -------------------------------------------------------------------------------- /samples/test.edn: -------------------------------------------------------------------------------- 1 | {:foo "bar", :baz 4} 2 | {:foo "oof", :baz 4} 3 | -------------------------------------------------------------------------------- /samples/test.json: -------------------------------------------------------------------------------- 1 | {"foo":"bar","baz":4} 2 | {"foo":"oof","baz":4} 3 | -------------------------------------------------------------------------------- /tests.edn: -------------------------------------------------------------------------------- 1 | #kaocha/v1 2 | {:reporter [kaocha.report/documentation]} 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cpcache/ 2 | .rebel_readline_history 3 | .socket-port 4 | .nrepl-port 5 | classes/ 6 | .clj-kondo/.cache/ 7 | 8 | tabl 9 | tabl.build_artifacts.txt 10 | -------------------------------------------------------------------------------- /src/app/json.clj: -------------------------------------------------------------------------------- 1 | (ns app.json 2 | (:require [app.json.bb :as json.bb]) 3 | (:import 4 | [com.fasterxml.jackson.core JsonParser])) 5 | 6 | (defn json-seq 7 | [reader] 8 | (lazy-seq 9 | (if-let [obj (json.bb/parse-json reader true)] 10 | (cons obj (json-seq reader)) 11 | (.close ^JsonParser reader)))) 12 | 13 | (defn reader->seq 14 | [reader] 15 | (-> (json.bb/json-parser reader) 16 | (json-seq))) 17 | -------------------------------------------------------------------------------- /dev/fiddle/main.clj: -------------------------------------------------------------------------------- 1 | (ns fiddle.main 2 | (:require 3 | [clojure.tools.cli :refer [parse-opts]] 4 | 5 | [app.main :as main])) 6 | 7 | (defn h 8 | [& args] 9 | (let [parsed (parse-opts args main/cli-options)] 10 | (some->> (main/find-errors parsed) 11 | (main/print-errors parsed)))) 12 | 13 | 14 | #_(h) 15 | #_(h "-h") 16 | #_(h "-x" "-h") 17 | #_(h "-f" "not-found.edn" "-e") 18 | #_(h "-f" "not-found.json" "-j") 19 | -------------------------------------------------------------------------------- /src/tabl/format/k8s.clj: -------------------------------------------------------------------------------- 1 | (ns tabl.format.k8s 2 | (:require [clojure.string :as string] 3 | [doric.core :refer [aligned-td aligned-th]])) 4 | 5 | (defn th 6 | [col] 7 | (aligned-th (assoc col :title-align :left))) 8 | 9 | (def td aligned-td) 10 | 11 | (defn render [table] 12 | (concat [(str (string/join " " (map string/upper-case (first table))))] 13 | (for [tr (rest table)] 14 | (str (string/join " " tr))))) 15 | -------------------------------------------------------------------------------- /src/app/edn.clj: -------------------------------------------------------------------------------- 1 | (ns app.edn 2 | (:require [clojure.edn :as edn] 3 | [clojure.java.io :as io]) 4 | (:import 5 | [java.io PushbackReader])) 6 | 7 | (defn edn-seq 8 | [reader] 9 | (lazy-seq 10 | (if-let [obj (edn/read {:eof nil} reader)] 11 | (cons obj (edn-seq reader)) 12 | (.close ^PushbackReader reader)))) 13 | 14 | (defn reader->seq 15 | [reader] 16 | (-> (io/reader reader) 17 | (PushbackReader.) 18 | (edn-seq))) 19 | -------------------------------------------------------------------------------- /src/app/json/bb.clj: -------------------------------------------------------------------------------- 1 | (ns app.json.bb 2 | (:require [cheshire.factory :as factory] 3 | [cheshire.parse :as cheshire-parse]) 4 | (:import [com.fasterxml.jackson.core JsonFactory] 5 | [java.io Reader])) 6 | 7 | (defn json-parser [reader] 8 | (.createParser ^JsonFactory factory/json-factory 9 | ^Reader reader)) 10 | 11 | (defn parse-json [json-reader keywordize] 12 | (cheshire-parse/parse-strict json-reader keywordize nil nil)) 13 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # v0.3.0 2 | 3 | Features: 4 | 5 | * Add md (markdown) and k8s style table formatting modes 6 | 7 | Fixes: 8 | 9 | * Compatibility with latest Babashka pod protocol 10 | 11 | # v0.2.0 12 | 13 | Features: 14 | 15 | * Add more table rendering modes, ability to choose 16 | * Add pod support for fancy and doric functions 17 | 18 | # v0.0.0-pre2 19 | 20 | Fixes: 21 | 22 | * When no file is specified, assume stdin even if not yet ready. 23 | 24 | # v0.0.0-pre1 25 | 26 | Initial version. 27 | 28 | * Handlers JSON and EDN input 29 | -------------------------------------------------------------------------------- /scripts/compile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | app_name=tabl 4 | 5 | rm -rf classes 6 | mkdir classes 7 | clojure -e "(compile 'app.main)" 8 | 9 | if [ -z "$NATIVE_IMAGE" ]; then 10 | echo 'Please set $NATIVE_IMAGE' 11 | exit 1 12 | fi 13 | 14 | $NATIVE_IMAGE \ 15 | -cp $(clojure -Spath):classes \ 16 | -H:Name=$app_name \ 17 | -H:+ReportExceptionStackTraces \ 18 | -H:IncludeResources=VERSION \ 19 | --initialize-at-build-time \ 20 | --report-unsupported-elements-at-runtime \ 21 | --verbose \ 22 | --no-fallback \ 23 | --no-server \ 24 | "-J-Xmx3g" \ 25 | app.main 26 | -------------------------------------------------------------------------------- /pod_test.clj: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bb 2 | 3 | (require '[babashka.pods :as pods]) 4 | (pods/load-pod "./tabl") 5 | ; (pods/load-pod ["clojure" "-M" "-m" "app.main"]) 6 | 7 | (require '[pod.tabl.fancy :as fancy]) 8 | (require '[pod.tabl.doric :as doric]) 9 | 10 | (def data 11 | [{:foo 1 :bar 2} 12 | {:foo 2 :bar 3}]) 13 | 14 | (println "fancy") 15 | (fancy/print-table data) 16 | (println) 17 | 18 | (def doric-styles 19 | ['doric.csv 20 | 'doric.html 21 | 'doric.org 22 | 'doric.raw 23 | 'tabl.format.k8s 24 | 'tabl.format.markdown]) 25 | 26 | (doseq [t doric-styles] 27 | (println t) 28 | (doric/print-table {:format t} data) 29 | (println)) 30 | -------------------------------------------------------------------------------- /src/tabl/format/markdown.clj: -------------------------------------------------------------------------------- 1 | (ns tabl.format.markdown 2 | (:require [clojure.string :as string] 3 | [doric.core :refer [aligned-td aligned-th]])) 4 | 5 | (def th aligned-th) 6 | 7 | (def td aligned-td) 8 | 9 | (defn render [table] 10 | (let [spacer (str "-" 11 | (string/join "-|-" 12 | (map #(apply str (repeat (.length ^java.lang.String %) "-")) 13 | (first table))) 14 | "-")] 15 | (concat [(str " " (string/join " | " (first table)) " ") 16 | spacer] 17 | (for [tr (rest table)] 18 | (str " " (string/join " | " tr) " "))))) 19 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:aliases 2 | {:repl 3 | {:extra-paths ["dev"] 4 | :extra-deps {io.github.justone/cljdev {:git/sha "dc9171f9f091e476a734714d128704876c7fa679"}} 5 | :exec-fn cljdev.repl/start} 6 | :test 7 | {:extra-paths ["dev" "test"] 8 | :extra-deps {lambdaisland/kaocha {:mvn/version "1.70.1086"}} 9 | :main-opts ["-m" "kaocha.runner"]}} 10 | 11 | :deps 12 | {org.clojure/clojure {:mvn/version "1.11.1"} 13 | org.endot/bb-pod-racer {:mvn/version "0.1.9"} 14 | cheshire/cheshire {:mvn/version "5.11.0"} 15 | doric/doric {:git/url "https://github.com/justone/doric.git" 16 | :sha "43e9b7027902c2239fc7084ee7325262cf362ba0"} 17 | fancy/fancy {:mvn/version "0.2.3"} 18 | org.clojure/tools.cli {:mvn/version "1.0.214"}} 19 | 20 | :paths ["src" "resources"]} 21 | -------------------------------------------------------------------------------- /dev/fiddle/formats.clj: -------------------------------------------------------------------------------- 1 | (ns fiddle.formats 2 | {:clj-kondo/config '{:linters {:unused-namespace {:level :off}}}} 3 | (:require 4 | [clojure.java.io :as io] 5 | 6 | [app.edn :as edn] 7 | [app.json :as json] 8 | 9 | [fancy.table :as table] 10 | [doric.core :as doric] 11 | )) 12 | 13 | #_(->> (io/reader "test.json") 14 | json/reader->seq 15 | (table/render-table) 16 | (run! println)) 17 | 18 | #_(->> (io/reader "test.edn") 19 | edn/reader->seq 20 | (table/render-table) 21 | (run! println)) 22 | 23 | (def data 24 | [{"foo" 1, "really long field name" 2} 25 | {"foo" "really long field value", "really long field name" 1} 26 | {"foo" 3, "really long field name" 0}]) 27 | 28 | #_(println (doric/table {:format 'app.format.markdown} data)) 29 | #_(println (doric/table {:format 'app.format.k8s} data)) 30 | -------------------------------------------------------------------------------- /test/app/main_test.clj: -------------------------------------------------------------------------------- 1 | (ns app.main-test 2 | (:require [app.main :as main] 3 | [clojure.java.io :as io] 4 | [clojure.string :as string] 5 | [clojure.test :refer [deftest is]] 6 | [clojure.tools.cli :refer [parse-opts]])) 7 | 8 | (defn errors-in 9 | [& args] 10 | (main/find-errors (parse-opts args main/cli-options))) 11 | 12 | (deftest errors 13 | (is (= {:exit 0} 14 | (errors-in "-h"))) 15 | (is (= {:exit 0 16 | :plain true 17 | :message (string/trim (slurp (io/resource "VERSION")))} 18 | (errors-in "--version"))) 19 | (is (= {:exit 1 20 | :message "please specify which format"} 21 | (errors-in))) 22 | (is (= {:exit 1 23 | :message "Unknown option: \"-x\""} 24 | (errors-in "-x"))) 25 | (is (= {:exit 1 26 | :message "file not found: samples/not-found-test.edn"} 27 | (errors-in "-e" "-f" "samples/not-found-test.edn"))) 28 | ) 29 | 30 | (deftest run 31 | (is (= (str " :baz | :foo \n" 32 | "------|------\n" 33 | " 4 | bar \n" 34 | " 4 | oof \n") 35 | (with-out-str (main/-main "-e" "-f" "samples/test.edn")))) 36 | (is (= (str "|-----+-----|\n" 37 | "| Foo | Baz |\n" 38 | "|-----+-----|\n" 39 | "| bar | 4 |\n" 40 | "| oof | 4 |\n" 41 | "|-----+-----|\n") 42 | (with-out-str (main/-main "-e" "-m" "org" "-f" "samples/test.edn")))) 43 | (is (= (str "Foo Baz\n" 44 | "bar 4 \n" 45 | "oof 4 \n") 46 | (with-out-str (main/-main "-e" "-m" "raw" "-f" "samples/test.edn")))) 47 | (is (= (str "Foo,Baz\n" 48 | "bar,4\n" 49 | "oof,4\n") 50 | (with-out-str (main/-main "-e" "-m" "csv" "-f" "samples/test.edn")))) 51 | (is (= (str "\n" 52 | "\n" 53 | "\n" 54 | "\n" 55 | "
FooBaz
bar4
oof4
\n") 56 | (with-out-str (main/-main "-e" "-m" "html" "-f" "samples/test.edn")))) 57 | (is (= (str "FOO BAZ\n" 58 | "bar 4 \n" 59 | "oof 4 \n") 60 | (with-out-str (main/-main "-e" "-m" "k8s" "-f" "samples/test.edn")))) 61 | (is (= (str " Foo | Baz \n" 62 | "-----|-----\n" 63 | " bar | 4 \n" 64 | " oof | 4 \n") 65 | (with-out-str (main/-main "-e" "-m" "md" "-f" "samples/test.edn")))) 66 | ) 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tabl 2 | 3 | Make tables from data in your terminal. 4 | 5 | # Install 6 | 7 | Download the latest from the [releases page](https://github.com/justone/tabl/releases). 8 | 9 | # Usage 10 | 11 | This small utility takes JSON or EDN files with multiple maps and creates a 12 | table for ease of viewing. For example: 13 | 14 | ``` 15 | $ cat test.json 16 | {"foo":"bar","baz":4} 17 | {"foo":"oof","baz":4} 18 | $ cat test.json | tabl -j 19 | :baz | :foo 20 | ------|------ 21 | 4 | bar 22 | 4 | oof 23 | ``` 24 | 25 | There are several table rendering modes available: 26 | 27 | | library | modes | 28 | |----------------------------------------------------|---------------------| 29 | | [fancy](https://github.com/chbrown/fancy-clojure/) | fancy | 30 | | [doric](https://github.com/joegallo/doric) | org, csv, html, raw | 31 | | built-in | md, k8s | 32 | 33 | 34 | ``` 35 | $ cat test.json | tabl -j -m org 36 | |-----+-----| 37 | | Foo | Baz | 38 | |-----+-----| 39 | | bar | 4 | 40 | | oof | 4 | 41 | |-----+-----| 42 | ``` 43 | 44 | # [Babashka pod](https://github.com/babashka/babashka.pods) support 45 | 46 | The following namespaces and functions are exposed via the pod interface: 47 | 48 | * `pod.tabl.fancy` (see [here](https://cljdoc.org/d/fancy/fancy/0.2.3/api/fancy.table) for more information) 49 | * `render-table` - returns table as a list of strings 50 | * `print-table` - prints a table based on data 51 | * `pod.tabl.doric` 52 | * `table` - returns table as a list of strings (see [here](https://github.com/joegallo/doric) for more information) 53 | * `print-table` - prints a table based on data 54 | 55 | Example: 56 | 57 | ``` 58 | #!/usr/bin/env bb 59 | 60 | (require '[babashka.pods :as pods]) 61 | (pods/load-pod "tabl") 62 | 63 | (require '[pod.tabl.fancy :as fancy]) 64 | (require '[pod.tabl.doric :as doric]) 65 | 66 | ;; 67 | (fancy/print-table [{:foo 1 :bar 2} {:foo 2 :bar 3}]) 68 | (doric/print-table [{:foo 1 :bar 2} {:foo 2 :bar 3}]) 69 | (doric/print-table {:format 'doric.org} [{:foo 1 :bar 2} {:foo 2 :bar 3}]) 70 | ``` 71 | 72 | See [pod_test.clj](./pod_test.clj) for more examples. 73 | 74 | # Development 75 | 76 | Not quite ready yet. This depends on a soon-to-be-released library. 77 | 78 | Thank you to [Michiel Borkent](https://github.com/borkdude) and 79 | [Lee Read](https://github.com/lread) for spearheading the GraalVM efforts, 80 | documented [here](https://github.com/lread/clj-graal-docs). 81 | 82 | # License 83 | 84 | Copyright © 2019-2022 Nate Jones 85 | 86 | Distributed under the EPL License. See LICENSE. 87 | 88 | This project contains code from: 89 | 90 | [babashka](https://github.com/borkdude/babashka), which is licensed under the same EPL License. 91 | -------------------------------------------------------------------------------- /src/app/main.clj: -------------------------------------------------------------------------------- 1 | (ns app.main 2 | (:require [app.edn :as edn] 3 | [app.json :as json] 4 | [clojure.java.io :as io] 5 | [clojure.string :as string] 6 | [clojure.tools.cli :refer [parse-opts]] 7 | [doric.core :as doric] 8 | [doric.csv] 9 | [doric.html] 10 | [doric.org] 11 | [doric.raw] 12 | [fancy.table] 13 | [pod-racer.core :as pod] 14 | [tabl.format.k8s] 15 | [tabl.format.markdown]) 16 | (:import 17 | [java.io File]) 18 | (:gen-class)) 19 | 20 | (def formatters 21 | {"fancy" fancy.table/print-table 22 | "org" #(->> % (doric/table {:format 'doric.org}) println) 23 | "csv" #(->> % (doric/table {:format 'doric.csv}) println) 24 | "raw" #(->> % (doric/table {:format 'doric.raw}) println) 25 | "html" #(->> % (doric/table {:format 'doric.html}) println) 26 | "md" #(->> % (doric/table {:format 'tabl.format.markdown}) println) 27 | "k8s" #(->> % (doric/table {:format 'tabl.format.k8s}) println)}) 28 | 29 | (def cli-options 30 | [["-e" "--edn" "Input is JSON"] 31 | ["-f" "--file FILE" "File to process instead of stdin"] 32 | ["-j" "--json" "Input is EDN"] 33 | ; ["-c" "--csv" "Input is CSV"] 34 | ["-m" "--mode MODE" (str "Formatting mode, available options: " (string/join ", " (keys formatters))) 35 | :default "fancy" 36 | :validate [#(contains? formatters %) (str "Must be one of " (string/join ", " (keys formatters)))]] 37 | ["-h" "--help"] 38 | ["-v" "--version" "Print version"]]) 39 | 40 | (defn print-usage 41 | [summary] 42 | (println "usage: tabl [opts]") 43 | (println " ") 44 | (println "options:") 45 | (println summary)) 46 | 47 | (defn find-errors 48 | [parsed] 49 | (let [{:keys [errors options]} parsed 50 | {:keys [file help edn json version]} options] 51 | (cond 52 | help 53 | {:exit 0} 54 | 55 | version 56 | {:message (string/trim (slurp (io/resource "VERSION"))) 57 | :plain true 58 | :exit 0} 59 | 60 | errors 61 | {:message (string/join "\n" errors) 62 | :exit 1} 63 | 64 | (not (or edn json)) 65 | {:message "please specify which format" 66 | :exit 1} 67 | 68 | (and file (not (.exists ^File (io/file file)))) 69 | {:message (str "file not found: " file) 70 | :exit 1} 71 | ))) 72 | 73 | (defn print-errors 74 | [parsed errors] 75 | (let [{:keys [summary]} parsed 76 | {:keys [message exit plain]} errors] 77 | (if plain 78 | (println message) 79 | (do 80 | (when message 81 | (println message) 82 | (println " ")) 83 | (print-usage summary))) 84 | exit)) 85 | 86 | (defn select-input 87 | [options] 88 | (let [{:keys [file]} options] 89 | (if file 90 | (io/reader file) 91 | *in*))) 92 | 93 | (defn input->seq 94 | [options reader] 95 | (cond 96 | (:edn options) 97 | (edn/reader->seq reader) 98 | 99 | (:json options) 100 | (json/reader->seq reader))) 101 | 102 | (def pod-config 103 | {:pod/namespaces 104 | [{:pod/ns "pod.tabl.fancy" 105 | :pod/vars [{:var/name "render-table" 106 | :var/fn fancy.table/render-table} 107 | {:var/name "print-table" 108 | :var/fn fancy.table/print-table}]} 109 | {:pod/ns "pod.tabl.doric" 110 | :pod/vars [{:var/name "table" 111 | :var/fn doric/table} 112 | {:var/name "print-table" 113 | :var/fn (fn [& args] 114 | (println (apply doric/table args)))}]}]}) 115 | 116 | (defn -main [& args] 117 | (let [parsed (parse-opts args cli-options) 118 | {:keys [options]} parsed] 119 | (if (System/getenv "BABASHKA_POD") 120 | (pod/launch pod-config) 121 | (or (some->> (find-errors parsed) 122 | (print-errors parsed) 123 | (System/exit)) 124 | (let [data (->> (select-input options) 125 | (input->seq options)) 126 | formatter (get formatters (:mode options))] 127 | (formatter data)))))) 128 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 2.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 4 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION 5 | OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial content 12 | Distributed under this Agreement, and 13 | 14 | b) in the case of each subsequent Contributor: 15 | i) changes to the Program, and 16 | ii) additions to the Program; 17 | where such changes and/or additions to the Program originate from 18 | and are Distributed by that particular Contributor. A Contribution 19 | "originates" from a Contributor if it was added to the Program by 20 | such Contributor itself or anyone acting on such Contributor's behalf. 21 | Contributions do not include changes or additions to the Program that 22 | are not Modified Works. 23 | 24 | "Contributor" means any person or entity that Distributes the Program. 25 | 26 | "Licensed Patents" mean patent claims licensable by a Contributor which 27 | are necessarily infringed by the use or sale of its Contribution alone 28 | or when combined with the Program. 29 | 30 | "Program" means the Contributions Distributed in accordance with this 31 | Agreement. 32 | 33 | "Recipient" means anyone who receives the Program under this Agreement 34 | or any Secondary License (as applicable), including Contributors. 35 | 36 | "Derivative Works" shall mean any work, whether in Source Code or other 37 | form, that is based on (or derived from) the Program and for which the 38 | editorial revisions, annotations, elaborations, or other modifications 39 | represent, as a whole, an original work of authorship. 40 | 41 | "Modified Works" shall mean any work in Source Code or other form that 42 | results from an addition to, deletion from, or modification of the 43 | contents of the Program, including, for purposes of clarity any new file 44 | in Source Code form that contains any contents of the Program. Modified 45 | Works shall not include works that contain only declarations, 46 | interfaces, types, classes, structures, or files of the Program solely 47 | in each case in order to link to, bind by name, or subclass the Program 48 | or Modified Works thereof. 49 | 50 | "Distribute" means the acts of a) distributing or b) making available 51 | in any manner that enables the transfer of a copy. 52 | 53 | "Source Code" means the form of a Program preferred for making 54 | modifications, including but not limited to software source code, 55 | documentation source, and configuration files. 56 | 57 | "Secondary License" means either the GNU General Public License, 58 | Version 2.0, or any later versions of that license, including any 59 | exceptions or additional permissions as identified by the initial 60 | Contributor. 61 | 62 | 2. GRANT OF RIGHTS 63 | 64 | a) Subject to the terms of this Agreement, each Contributor hereby 65 | grants Recipient a non-exclusive, worldwide, royalty-free copyright 66 | license to reproduce, prepare Derivative Works of, publicly display, 67 | publicly perform, Distribute and sublicense the Contribution of such 68 | Contributor, if any, and such Derivative Works. 69 | 70 | b) Subject to the terms of this Agreement, each Contributor hereby 71 | grants Recipient a non-exclusive, worldwide, royalty-free patent 72 | license under Licensed Patents to make, use, sell, offer to sell, 73 | import and otherwise transfer the Contribution of such Contributor, 74 | if any, in Source Code or other form. This patent license shall 75 | apply to the combination of the Contribution and the Program if, at 76 | the time the Contribution is added by the Contributor, such addition 77 | of the Contribution causes such combination to be covered by the 78 | Licensed Patents. The patent license shall not apply to any other 79 | combinations which include the Contribution. No hardware per se is 80 | licensed hereunder. 81 | 82 | c) Recipient understands that although each Contributor grants the 83 | licenses to its Contributions set forth herein, no assurances are 84 | provided by any Contributor that the Program does not infringe the 85 | patent or other intellectual property rights of any other entity. 86 | Each Contributor disclaims any liability to Recipient for claims 87 | brought by any other entity based on infringement of intellectual 88 | property rights or otherwise. As a condition to exercising the 89 | rights and licenses granted hereunder, each Recipient hereby 90 | assumes sole responsibility to secure any other intellectual 91 | property rights needed, if any. For example, if a third party 92 | patent license is required to allow Recipient to Distribute the 93 | Program, it is Recipient's responsibility to acquire that license 94 | before distributing the Program. 95 | 96 | d) Each Contributor represents that to its knowledge it has 97 | sufficient copyright rights in its Contribution, if any, to grant 98 | the copyright license set forth in this Agreement. 99 | 100 | e) Notwithstanding the terms of any Secondary License, no 101 | Contributor makes additional grants to any Recipient (other than 102 | those set forth in this Agreement) as a result of such Recipient's 103 | receipt of the Program under the terms of a Secondary License 104 | (if permitted under the terms of Section 3). 105 | 106 | 3. REQUIREMENTS 107 | 108 | 3.1 If a Contributor Distributes the Program in any form, then: 109 | 110 | a) the Program must also be made available as Source Code, in 111 | accordance with section 3.2, and the Contributor must accompany 112 | the Program with a statement that the Source Code for the Program 113 | is available under this Agreement, and informs Recipients how to 114 | obtain it in a reasonable manner on or through a medium customarily 115 | used for software exchange; and 116 | 117 | b) the Contributor may Distribute the Program under a license 118 | different than this Agreement, provided that such license: 119 | i) effectively disclaims on behalf of all other Contributors all 120 | warranties and conditions, express and implied, including 121 | warranties or conditions of title and non-infringement, and 122 | implied warranties or conditions of merchantability and fitness 123 | for a particular purpose; 124 | 125 | ii) effectively excludes on behalf of all other Contributors all 126 | liability for damages, including direct, indirect, special, 127 | incidental and consequential damages, such as lost profits; 128 | 129 | iii) does not attempt to limit or alter the recipients' rights 130 | in the Source Code under section 3.2; and 131 | 132 | iv) requires any subsequent distribution of the Program by any 133 | party to be under a license that satisfies the requirements 134 | of this section 3. 135 | 136 | 3.2 When the Program is Distributed as Source Code: 137 | 138 | a) it must be made available under this Agreement, or if the 139 | Program (i) is combined with other material in a separate file or 140 | files made available under a Secondary License, and (ii) the initial 141 | Contributor attached to the Source Code the notice described in 142 | Exhibit A of this Agreement, then the Program may be made available 143 | under the terms of such Secondary Licenses, and 144 | 145 | b) a copy of this Agreement must be included with each copy of 146 | the Program. 147 | 148 | 3.3 Contributors may not remove or alter any copyright, patent, 149 | trademark, attribution notices, disclaimers of warranty, or limitations 150 | of liability ("notices") contained within the Program from any copy of 151 | the Program which they Distribute, provided that Contributors may add 152 | their own appropriate notices. 153 | 154 | 4. COMMERCIAL DISTRIBUTION 155 | 156 | Commercial distributors of software may accept certain responsibilities 157 | with respect to end users, business partners and the like. While this 158 | license is intended to facilitate the commercial use of the Program, 159 | the Contributor who includes the Program in a commercial product 160 | offering should do so in a manner which does not create potential 161 | liability for other Contributors. Therefore, if a Contributor includes 162 | the Program in a commercial product offering, such Contributor 163 | ("Commercial Contributor") hereby agrees to defend and indemnify every 164 | other Contributor ("Indemnified Contributor") against any losses, 165 | damages and costs (collectively "Losses") arising from claims, lawsuits 166 | and other legal actions brought by a third party against the Indemnified 167 | Contributor to the extent caused by the acts or omissions of such 168 | Commercial Contributor in connection with its distribution of the Program 169 | in a commercial product offering. The obligations in this section do not 170 | apply to any claims or Losses relating to any actual or alleged 171 | intellectual property infringement. In order to qualify, an Indemnified 172 | Contributor must: a) promptly notify the Commercial Contributor in 173 | writing of such claim, and b) allow the Commercial Contributor to control, 174 | and cooperate with the Commercial Contributor in, the defense and any 175 | related settlement negotiations. The Indemnified Contributor may 176 | participate in any such claim at its own expense. 177 | 178 | For example, a Contributor might include the Program in a commercial 179 | product offering, Product X. That Contributor is then a Commercial 180 | Contributor. If that Commercial Contributor then makes performance 181 | claims, or offers warranties related to Product X, those performance 182 | claims and warranties are such Commercial Contributor's responsibility 183 | alone. Under this section, the Commercial Contributor would have to 184 | defend claims against the other Contributors related to those performance 185 | claims and warranties, and if a court requires any other Contributor to 186 | pay any damages as a result, the Commercial Contributor must pay 187 | those damages. 188 | 189 | 5. NO WARRANTY 190 | 191 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 192 | PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" 193 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 194 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF 195 | TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 196 | PURPOSE. Each Recipient is solely responsible for determining the 197 | appropriateness of using and distributing the Program and assumes all 198 | risks associated with its exercise of rights under this Agreement, 199 | including but not limited to the risks and costs of program errors, 200 | compliance with applicable laws, damage to or loss of data, programs 201 | or equipment, and unavailability or interruption of operations. 202 | 203 | 6. DISCLAIMER OF LIABILITY 204 | 205 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 206 | PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS 207 | SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 208 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST 209 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 210 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 211 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 212 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE 213 | POSSIBILITY OF SUCH DAMAGES. 214 | 215 | 7. GENERAL 216 | 217 | If any provision of this Agreement is invalid or unenforceable under 218 | applicable law, it shall not affect the validity or enforceability of 219 | the remainder of the terms of this Agreement, and without further 220 | action by the parties hereto, such provision shall be reformed to the 221 | minimum extent necessary to make such provision valid and enforceable. 222 | 223 | If Recipient institutes patent litigation against any entity 224 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 225 | Program itself (excluding combinations of the Program with other software 226 | or hardware) infringes such Recipient's patent(s), then such Recipient's 227 | rights granted under Section 2(b) shall terminate as of the date such 228 | litigation is filed. 229 | 230 | All Recipient's rights under this Agreement shall terminate if it 231 | fails to comply with any of the material terms or conditions of this 232 | Agreement and does not cure such failure in a reasonable period of 233 | time after becoming aware of such noncompliance. If all Recipient's 234 | rights under this Agreement terminate, Recipient agrees to cease use 235 | and distribution of the Program as soon as reasonably practicable. 236 | However, Recipient's obligations under this Agreement and any licenses 237 | granted by Recipient relating to the Program shall continue and survive. 238 | 239 | Everyone is permitted to copy and distribute copies of this Agreement, 240 | but in order to avoid inconsistency the Agreement is copyrighted and 241 | may only be modified in the following manner. The Agreement Steward 242 | reserves the right to publish new versions (including revisions) of 243 | this Agreement from time to time. No one other than the Agreement 244 | Steward has the right to modify this Agreement. The Eclipse Foundation 245 | is the initial Agreement Steward. The Eclipse Foundation may assign the 246 | responsibility to serve as the Agreement Steward to a suitable separate 247 | entity. Each new version of the Agreement will be given a distinguishing 248 | version number. The Program (including Contributions) may always be 249 | Distributed subject to the version of the Agreement under which it was 250 | received. In addition, after a new version of the Agreement is published, 251 | Contributor may elect to Distribute the Program (including its 252 | Contributions) under the new version. 253 | 254 | Except as expressly stated in Sections 2(a) and 2(b) above, Recipient 255 | receives no rights or licenses to the intellectual property of any 256 | Contributor under this Agreement, whether expressly, by implication, 257 | estoppel or otherwise. All rights in the Program not expressly granted 258 | under this Agreement are reserved. Nothing in this Agreement is intended 259 | to be enforceable by any entity that is not a Contributor or Recipient. 260 | No third-party beneficiary rights are created under this Agreement. 261 | 262 | Exhibit A - Form of Secondary Licenses Notice 263 | 264 | "This Source Code may also be made available under the following 265 | Secondary Licenses when the conditions for such availability set forth 266 | in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), 267 | version(s), and exceptions or additional permissions here}." 268 | 269 | Simply including a copy of this Agreement, including this Exhibit A 270 | is not sufficient to license the Source Code under Secondary Licenses. 271 | 272 | If it is not possible or desirable to put the notice in a particular 273 | file, then You may include the notice in a location (such as a LICENSE 274 | file in a relevant directory) where a recipient would be likely to 275 | look for such a notice. 276 | 277 | You may add additional accurate notices of copyright ownership. 278 | --------------------------------------------------------------------------------