├── .gitignore
├── src
└── dsui
│ ├── ui.clj
│ ├── core.clj
│ ├── examples.clj
│ └── swing.clj
├── img
├── data_DSUI.png
└── data_cider.png
├── deps.edn
├── test
└── dsui
│ ├── swing_test.clj
│ └── core_test.clj
├── project.clj
├── README.md
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .nrepl-port
--------------------------------------------------------------------------------
/src/dsui/ui.clj:
--------------------------------------------------------------------------------
1 | (ns dsui.ui)
2 |
3 | (def colnumber 3)
4 |
--------------------------------------------------------------------------------
/img/data_DSUI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azel4231/dsui/HEAD/img/data_DSUI.png
--------------------------------------------------------------------------------
/deps.edn:
--------------------------------------------------------------------------------
1 | {:paths ["src"]
2 | :deps {org.clojure/clojure {:mvn/version "1.9.0"}}}
3 |
--------------------------------------------------------------------------------
/img/data_cider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azel4231/dsui/HEAD/img/data_cider.png
--------------------------------------------------------------------------------
/test/dsui/swing_test.clj:
--------------------------------------------------------------------------------
1 | (ns dsui.swing-test
2 | (:use [clojure.test])
3 | (:require [dsui.swing :as swing]))
4 |
5 | (deftest table-model-test
6 | (let [tm (swing/table-model '("A" "B" "c") [[1 2 3]
7 | [:1 :2 :3]])]
8 | (is (= 3 (.getColumnCount tm)))
9 | (is (= 2 (.getRowCount tm)))))
10 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject org.clojars.azel4231/dsui "0.1.1"
2 | :description "Generate a readonly form-based UI for arbitrary data"
3 | :url "https://github.com/Azel4231/dsui"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 |
7 | :dependencies [[org.clojure/clojure "1.9.0"]
8 | [org.clojure/test.check "0.9.0" :scope "test"]]
9 |
10 | :deploy-repositories [["clojars" {:sign-releases false
11 | :url "https://clojars.org/repo"}]]
12 |
13 | :plugins []
14 | :main dsui.examples
15 | :source-paths ["src"]
16 | :test-paths ["test"]
17 | :target-path "target/%s"
18 | :profiles {:uberjar {:aot :all}})
19 |
--------------------------------------------------------------------------------
/src/dsui/core.clj:
--------------------------------------------------------------------------------
1 | (ns dsui.core
2 | (:require [clojure.spec.alpha :as s]))
3 |
4 | (set! *warn-on-reflection* true)
5 |
6 | (defn scalar? [v]
7 | ((complement coll?) v))
8 |
9 | (defn same? [f coll]
10 | (if (empty? coll) false
11 | (apply = (map f coll))))
12 |
13 | (defn homogeneous? [ms]
14 | (same? keys ms))
15 |
16 | (defn scalar-map? [m]
17 | (every? scalar? (vals m)))
18 |
19 | (s/def ::ds (s/or ::entity ::entity
20 | ::table-of-entities ::table-of-entities
21 | ::matrix ::matrix
22 | ::labeled-ds ::labeled-ds
23 | ::list-of-scalars ::list-of-scalars
24 | ::list-of-dss ::list-of-dss))
25 |
26 | (s/def ::table-of-entities (s/and (s/coll-of map? :min-count 2)
27 | (s/every scalar-map?)
28 | homogeneous?))
29 |
30 | (s/def ::matrix (s/and (s/coll-of ::list-of-scalars)
31 | #(same? count %)))
32 |
33 | (s/def ::list-of-scalars (s/coll-of ::scalar))
34 |
35 | (s/def ::list-of-dss (s/and (s/coll-of ::ds-or-scalar)
36 | (complement map?)))
37 |
38 | (s/def ::entity (s/map-of any? ::ds-or-scalar))
39 |
40 | (s/def ::labeled-ds (s/and map-entry?
41 | (s/tuple keyword? ::ds-or-scalar)))
42 |
43 | (s/def ::ds-or-scalar (s/or ::nested-ds ::ds
44 | ::scalar ::scalar))
45 |
46 | (s/def ::scalar scalar?)
47 |
48 |
--------------------------------------------------------------------------------
/test/dsui/core_test.clj:
--------------------------------------------------------------------------------
1 | (ns dsui.core-test
2 | (:use dsui.core)
3 | [:use clojure.test]
4 | (:require [clojure.spec.alpha :as s]
5 | [dsui.core :as core]
6 | [dsui.swing :as swing]))
7 |
8 | (deftest scalar-test
9 | (is (scalar? 1))
10 | (is (not (scalar? []))))
11 |
12 | (def scalarmap {:a 1 :b "2" :c 1/2})
13 | (def nestmap {:a []})
14 | (deftest scalar-map-tets
15 | (is (scalar-map? scalarmap))
16 | (is (not (scalar-map? nestmap))))
17 |
18 | (def homo '({:a 1 :b 2} {:a "1" :b "2"} {:a 1/3 :b 3/7}))
19 | (def inhomo [{:a 1} {:b 2}])
20 | (def inhomo2 [{:a 1} {:a 2 :b 3}])
21 | (deftest homo-test
22 | (is (homogeneous? homo))
23 | (is (not (homogeneous? inhomo)))
24 | (is (not (homogeneous? inhomo2))))
25 |
26 |
27 |
28 | (def list-data ["a" "B" 1 2 3])
29 | (deftest conform_conformed_data
30 | (let [conformed-data (s/conform :dsui.core/ds list-data)
31 | conformed²-data (s/conform :dsui.core/ds conformed-data)]
32 | (is (= conformed-data
33 | [:dsui.core/list-of-scalars ["a" "B" 1 2 3]]))
34 | (is (map-entry? conformed-data))
35 | (is (= conformed²-data
36 | [:dsui.core/labeled-ds [:dsui.core/list-of-scalars
37 | [:dsui.core/nested-ds
38 | [:dsui.core/list-of-scalars ["a" "B" 1 2 3]]]]]))))
39 |
40 | (deftest matrix-test
41 | (is (= (s/conform :dsui.core/ds [["a" "B"] [1 2]])
42 | [:dsui.core/matrix [["a" "B"] [1 2]]]))
43 | ;; test same structure, only with map entries
44 | (is (= (s/conform :dsui.core/ds (seq {"a" "B" 1 2}))
45 | [:dsui.core/matrix [["a" "B"] [1 2]]])))
46 |
47 | (deftest list-of-scalars-test
48 | (is (= (s/conform :dsui.core/ds ["a" "B"])
49 | [:dsui.core/list-of-scalars ["a" "B"]])))
50 |
51 | (deftest scalar-entity-test
52 | (is (= (s/conform :dsui.core/ds {:a "A"
53 | :b 2
54 | :c 1/3
55 | :d 4.0})
56 | [:dsui.core/entity {:a [:dsui.core/scalar "A"]
57 | :b [:dsui.core/scalar 2]
58 | :c [:dsui.core/scalar 1/3]
59 | :d [:dsui.core/scalar 4.0]}])))
60 |
61 | ;; match table if there is more than one entity, otherwise detect entity in a list
62 | (deftest table-test
63 | (is (= [:dsui.core/table-of-entities [{:a 1}
64 | {:a 2}]]
65 | (s/conform :dsui.core/ds [{:a 1}
66 | {:a 2}])))
67 | (is (= [:dsui.core/list-of-dss
68 | [[:dsui.core/nested-ds
69 | [:dsui.core/entity {:a [:dsui.core/scalar 1]}]]]]
70 | (s/conform :dsui.core/ds [{:a 1}]))))
71 |
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DSUI
2 | A Clojure tool for displaying arbitrary, nested data structures as a read-only, form-based UI. DSUI stands for "Data Structure User Interface".
3 |
4 | [](https://clojars.org/org.clojars.azel4231/dsui)
5 |
6 | ## Motivation
7 |
8 | 1. Being tired of writing UI code.
9 |
10 | 1. Avoiding this:
11 | 
12 |
13 | 1. And getting this instead:
14 | 
15 |
16 | ## Usage
17 |
18 | ### Installing the library
19 |
20 | Via deps:
21 |
22 | ```clojure
23 | {:deps {org.clojars.azel4231/dsui {:mvn/version "0.1.1"}}}
24 | ```
25 |
26 | Via lein:
27 |
28 | ```clojure
29 | :dependencies [[org.clojars.azel4231/dsui "0.1.1"]]
30 | ```
31 |
32 | Via maven:
33 |
34 | ```
35 |
36 | org.clojars.azel4231
37 | dsui
38 | 0.1.1
39 |
40 | ```
41 |
42 | ### Calling the library
43 |
44 | ```clojure
45 | (require '[dsui.swing :as d])
46 | ```
47 |
48 | Display data as a form-based UI:
49 |
50 | ```clojure
51 | (d/dsui any-data)
52 | ```
53 |
54 | Show how data conforms to a spec. Useful for specs with choices (via s/or) or labeled values (vis s/cat). If the data does not conform, displays the explanation (explain-data) as a ui:
55 |
56 | ```clojure
57 | (d/conform-ui ::any-spec any-data)
58 | ```
59 |
60 | Attach dsui to a ref and leave it open:
61 |
62 | ```clojure
63 | (defonce state (atom []))
64 | (defonce ui (d/watch-ui state))
65 | ```
66 |
67 | Swap new data into the atom to update the watch-ui window (REPL workflow)
68 |
69 | ```clojure
70 | (reset! state '[1 2 3 "A" "B" "C" + - * /])
71 | ```
72 |
73 | Or just have it display your app's changing app-state.
74 |
75 |
76 | ## Basic Features
77 | Displays:
78 | - maps as forms, nested data structures a tabbed panes
79 | - sequential data (including vectors, lists and sets) as vertical tabbed panes with (0..n) as a title
80 | - lists containing only scalar values as JLists
81 | - Matrices (vector of vectors) as tables
82 | - Lists of maps, that have the same keyset and contain scalar values only, as tables
83 | - conformed data (labeled data) returned by specs as vertical tabbed panes with the label as a title. Thus DSUI can be also used to see how things conformed when writing specs
84 |
85 | Does not support:
86 | - a single scalar value
87 |
88 | Not suited for:
89 | - graph-like data
90 | - large data-sets (generating the UI is currently eager)
91 |
92 | ## How it works
93 | DSUI uses clojure.spec to "parse" an arbitrary data structure. The conformed data is used to generate the swing UI by calling a multimethod that polymorphically creates different types of UI elements.
94 |
95 | More detailed explanations can be found here and here
96 |
97 | ## Next Steps
98 | - Decomplect processing pipeline: move parts that are agnostic of the UI framework into a separate step so they can be reused for other UI frameworks.
99 | - Migrate to fn-fx
100 |
101 | ## Distant Future
102 | - Make UI editable (e.g. swap value to an atom)
103 |
104 | ## License
105 | Distributed under the Eclipse Public License, the same as Clojure.
106 |
--------------------------------------------------------------------------------
/src/dsui/examples.clj:
--------------------------------------------------------------------------------
1 | (ns dsui.examples
2 | (:require [clojure.spec.alpha :as s]
3 | [dsui.swing :as swing]))
4 |
5 |
6 | (def uni {:name "Foo-University of Bar"
7 | :students [{:name "John Doe" :student-id "12345"}
8 | {:name "Jane Doe" :student-id "11111"}
9 | {:name "Dr. Who" :student-id "?"}]
10 | :courses [{:name "Linear Algebra" :max-students 15 :room "Gauss" :registered ["11111" "?"]}
11 | {:name "Introduction to Algorithms" :max-students 25 :room "Dijkstra" :registered ["12345" "?"]}]})
12 |
13 | (def tbl [{:surname "Jane" :lastname "Doe" :occupation "unknown"}
14 | {:surname "Jimmy" :lastname "McNulty" :occupation "Criminal Investigator"}
15 | {:surname "Bunk" :lastname "Moreland" :occupation "Criminal Investigator"}
16 | {:surname "Omar" :lastname "Little" :occupation "?"}
17 | ])
18 |
19 |
20 | (def mage
21 | {:id (. java.util.UUID randomUUID)
22 | :name "John Doe"
23 | :player ""
24 | :concept ""
25 | :virtue ""
26 | :vice ""
27 | :size-natural 5
28 | :properties {:path :obrimos
29 | :order :mysterium
30 | :cabal ""
31 | :gnosis 1
32 | :willpower 1
33 | :wisdom 7
34 | :merits #{}
35 | :flaws #{}
36 | :attributes {:strength 1 :dexterity 5 :stamina 1,
37 | :intelligence 1 :wits 1 :resolve 1,
38 | :presence 1 :manipulation 1 :composure 1}
39 | :skills {:academics 0 :computer 0 :crafts 0 :investigation 0 :medicine 0 :occult 0 :politics 0 :science 0,
40 | :athletics 0 :brawl 0 :drive 0 :firearms 0 :larceny 0 :stealth 0 :survival 0 :weaponry 0,
41 | :animalKen 0 :empathy 0 :expression 0 :intimidation 0 :persuasion 0 :socialize 0 :streetwise 0 :subterfuge 0}
42 | :arcana {:death 0
43 | :fate 0
44 | :forces 0
45 | :life 0
46 | :matter 0
47 | :mind 0
48 | :prime 0
49 | :space 0
50 | :spirit 0
51 | :time 0}
52 | :rotes []
53 | :weapons []
54 | :experience-total 0
55 | :experience-current 0}
56 | :ledger {:chronicle ""
57 | :bashing 0
58 | :lethal 0
59 | :aggravated 0
60 | :mana 5
61 | :size-current 5
62 | :armor {:bashing 0
63 | :lethal 0
64 | :aggravated 0}
65 | :spells-active 0
66 | :spells-cast-upon-self 0
67 | :spells-protective 0
68 | :nimbus :none
69 | :paradox-marks :none}
70 | :historicProperties [1 2 3 4]})
71 |
72 | (def example {:scalar-value 42
73 | :list-of-scalars [1 4 9 16]
74 | :list-of-datastructures ["this" "is" "a" "heterogeneous" "list" #{:with :nested :stuff}]
75 | :table tbl
76 | :matrix [[1 2 3] ["a" "b" "c"] [1.2 1/4 4.5]]
77 | :conformed-data (s/conform :dsui.core/ds uni)
78 | :small-example uni
79 | :larger-example mage
80 | })
81 |
82 | (defn -main [& args]
83 | (swing/dsui example (fn [_]
84 | (println "Exiting!")
85 | (System/exit 0))))
86 |
87 |
88 |
89 | ;; How to use watch-ui:
90 | (comment
91 | ;; Create a ref
92 | (defonce state (atom []))
93 |
94 | ;; Create the watch-ui. When working at the REPL use defonce to avoid adding multiple UIs/watchers to the ref.
95 | (defonce ui (swing/watch-ui state))
96 |
97 | ;; Swap new data into the atom (REPL workflow)
98 | (reset! state '[1 2 3 "A" "B" "C" + - * /])
99 | ;; Or just have it display your app's changing state (e.g. in an atom).
100 | )
101 |
102 |
103 |
104 | ;; primitives currently not supported
105 | #_(swing/dsui 42)
106 |
107 | ;; displays the last exception as a ui
108 | #_(-> *e Throwable->map swing/dsui)
109 |
110 |
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/src/dsui/swing.clj:
--------------------------------------------------------------------------------
1 | (ns dsui.swing
2 | (:require [clojure.spec.alpha :as s]
3 | [dsui.core :as core]
4 | [dsui.ui :as ui])
5 | (:import [java.util Vector Collection]
6 | [javax.swing SwingUtilities JFrame JLabel JPanel JTextField JTabbedPane JTable JList DefaultListModel JScrollPane]
7 | [javax.swing.table DefaultTableModel]
8 | [java.awt.event KeyAdapter WindowAdapter]
9 | [java.awt Container GridBagLayout GridBagConstraints]))
10 |
11 | (defn ^JFrame frame [title close-f]
12 | (doto (new JFrame)
13 | (.setSize (new java.awt.Dimension 800 800))
14 | (.addWindowListener (proxy [WindowAdapter] [] (windowClosing [e] (close-f e))))
15 | (.setTitle title)
16 | (.setVisible true)))
17 |
18 | (defn add
19 | ([^Container p cs]
20 | (add p cs (repeat nil)))
21 | ([^Container p cs lds]
22 | (doall (map (fn [^Container c ld] (.add p c ld)) (flatten cs) (flatten lds)))
23 | p))
24 |
25 | (defn panel []
26 | (doto (new JPanel)
27 | (.setLayout (new GridBagLayout))))
28 |
29 | (defn field [value]
30 | (doto (new JTextField (str value))
31 | (.setEditable false)))
32 |
33 | (defn label [l]
34 | (new JLabel (str l)))
35 |
36 | (defn table [tm]
37 | (new JScrollPane (doto (new JTable tm)
38 | (.setEnabled false))))
39 |
40 | (defn table-model [^Collection colnames rows]
41 | (let [^Vector cns (new Vector colnames)
42 | ^Collection rs (mapv (fn [^Collection r] (new Vector r)) rows)
43 | ^Vector content (new Vector rs)]
44 | (doto (new DefaultTableModel content cns)
45 | (.setColumnIdentifiers cns))))
46 |
47 | (defn jlist [^DefaultListModel lm]
48 | (new JList lm))
49 |
50 | (defn ^DefaultListModel list-model [coll]
51 | (let [lm (new DefaultListModel)]
52 | (doseq [el coll] (.addElement lm el))
53 | lm))
54 |
55 | (defn gb-constraints [{:keys [x y fl gw wx wy a]}]
56 | (let [gbc (new GridBagConstraints)]
57 | (set! (. gbc gridx) x)
58 | (set! (. gbc gridy) y)
59 | (set! (. gbc fill) fl)
60 | (set! (. gbc gridwidth) gw)
61 | (set! (. gbc weightx) wx)
62 | (set! (. gbc weighty) wy)
63 | (set! (. gbc anchor) a)
64 | gbc))
65 |
66 | (defn panel-gbc [y]
67 | (gb-constraints {:x 0 :y y :fl GridBagConstraints/BOTH :gw (* 2 ui/colnumber) :wx 1.0 :wy 1.0 :a GridBagConstraints/PAGE_START}))
68 |
69 | (defn field-gbc [x y]
70 | (gb-constraints {:x x :y y :fl GridBagConstraints/HORIZONTAL :gw 1 :wx 1.0 :wy 0.0 :a GridBagConstraints/PAGE_START}))
71 |
72 | (defmulti create first)
73 |
74 | (defn tabbed-pane [m]
75 | (let [tpane (new JTabbedPane)]
76 | (doseq [[k v] m]
77 | (.addTab tpane (str k) (create v)))
78 | tpane))
79 |
80 |
81 |
82 | (defmethod create :dsui.core/scalar [[_ ds]]
83 | (label ds))
84 |
85 | (defmethod create :dsui.core/list-of-dss [[_ ds]]
86 | (let [m (into {} (map-indexed (fn [i v] [i v]) ds))
87 | ^JTabbedPane tpane (tabbed-pane m)]
88 | (. tpane setTabPlacement JTabbedPane/LEFT)
89 | tpane))
90 |
91 | (defmethod create :dsui.core/labeled-ds [[_ ds]]
92 | (let [m (into {} [ds])
93 | ^JTabbedPane tpane (tabbed-pane m)]
94 | (. tpane setTabPlacement JTabbedPane/LEFT)
95 | tpane))
96 |
97 | (defmethod create :dsui.core/entity [[_ ds]]
98 | (let [p (panel)
99 | layout-cols (* 2 ui/colnumber)
100 | fields (filter #(= :dsui.core/scalar (first (second %))) ds)
101 | nested-uis (filter #(= :dsui.core/nested-ds (first (second %))) ds)]
102 | (add p
103 | (for [[kw childDs] fields]
104 | [(label kw) (create childDs)])
105 | (for [i (range (* 2 (count fields)))]
106 | (field-gbc (mod i layout-cols) (quot i layout-cols))))
107 | (add p [(tabbed-pane (into {} nested-uis))]
108 | [(panel-gbc (inc (quot (count fields) ui/colnumber)))])
109 | p))
110 |
111 | (defmethod create :dsui.core/table-of-entities [[_ ds]]
112 | (table (table-model (keys (first ds)) (map vals ds))))
113 |
114 | (defmethod create :dsui.core/matrix [[_ ds]]
115 | (table (table-model (range (count (first ds))) ds)))
116 |
117 | (defmethod create :dsui.core/list-of-scalars [[_ ds]]
118 | (jlist (list-model ds)))
119 |
120 | (defmethod create :dsui.core/scalar [[_ ds]]
121 | (field ds))
122 |
123 | (defmethod create :dsui.core/nested-ds [[_ ds]]
124 | (create ds))
125 |
126 | (defn dsui-content
127 | [ds]
128 | (create (s/conform :dsui.core/ds ds)))
129 |
130 | (defn refresh [frm]
131 | (. SwingUtilities invokeLater (fn [] (. SwingUtilities updateComponentTreeUI frm))))
132 |
133 | (s/fdef dsui
134 | :args :dsui.core/ds
135 | :ret any?)
136 | (defn dsui
137 | "Creates a read-only, form-based swing UI for an arbitrary nested data structure."
138 | ([ds]
139 | (dsui ds #(print "Exiting..." %)))
140 | ([ds close-f]
141 | (doto (frame "DS-UI" close-f)
142 | (.setContentPane (dsui-content ds))
143 | refresh)))
144 |
145 |
146 | (defn conform-ui
147 | "Shows how the data conformed to the spec. Useful for specs with choices (via s/or) or labeled values (vis s/cat). If the data does not conform, displays the explanation (explain-data) as a ui."
148 | [spec data]
149 | (let [conf (s/conform spec data)]
150 | (if (= :clojure.spec.alpha/invalid conf)
151 | (dsui (s/explain-data spec data))
152 | (dsui conf))))
153 |
154 |
155 | (defn watch-ui
156 | "Watches the ref and updates itself to mirror the ref's value whenever it changes."
157 | [ref]
158 | (let [frame (dsui @ref)]
159 | (add-watch ref :dsui (fn [key ref old-data new-data]
160 | (doto frame
161 | (.setContentPane (dsui-content new-data))
162 | refresh)))))
163 |
164 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Eclipse Public License - v 1.0
2 |
3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5 | 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 code and documentation
12 | distributed under this Agreement, and
13 | b) in the case of each subsequent Contributor:
14 | i) changes to the Program, and
15 | ii) additions to the Program;
16 |
17 | where such changes and/or additions to the Program originate from and are
18 | distributed by that particular Contributor. A Contribution 'originates' from
19 | a Contributor if it was added to the Program by such Contributor itself or
20 | anyone acting on such Contributor's behalf. Contributions do not include
21 | additions to the Program which: (i) are separate modules of software
22 | distributed in conjunction with the Program under their own license
23 | agreement, and (ii) are not derivative works of the Program.
24 |
25 | "Contributor" means any person or entity that distributes the Program.
26 |
27 | "Licensed Patents" mean patent claims licensable by a Contributor which are
28 | necessarily infringed by the use or sale of its Contribution alone or when
29 | combined with the Program.
30 |
31 | "Program" means the Contributions distributed in accordance with this Agreement.
32 |
33 | "Recipient" means anyone who receives the Program under this Agreement,
34 | including all Contributors.
35 |
36 | 2. GRANT OF RIGHTS
37 | a) Subject to the terms of this Agreement, each Contributor hereby grants
38 | Recipient a non-exclusive, worldwide, royalty-free copyright license to
39 | reproduce, prepare derivative works of, publicly display, publicly perform,
40 | distribute and sublicense the Contribution of such Contributor, if any, and
41 | such derivative works, in source code and object code form.
42 | b) Subject to the terms of this Agreement, each Contributor hereby grants
43 | Recipient a non-exclusive, worldwide, royalty-free patent license under
44 | Licensed Patents to make, use, sell, offer to sell, import and otherwise
45 | transfer the Contribution of such Contributor, if any, in source code and
46 | object code form. This patent license shall apply to the combination of the
47 | Contribution and the Program if, at the time the Contribution is added by
48 | the Contributor, such addition of the Contribution causes such combination
49 | to be covered by the Licensed Patents. The patent license shall not apply
50 | to any other combinations which include the Contribution. No hardware per
51 | se is licensed hereunder.
52 | c) Recipient understands that although each Contributor grants the licenses to
53 | its Contributions set forth herein, no assurances are provided by any
54 | Contributor that the Program does not infringe the patent or other
55 | intellectual property rights of any other entity. Each Contributor
56 | disclaims any liability to Recipient for claims brought by any other entity
57 | based on infringement of intellectual property rights or otherwise. As a
58 | condition to exercising the rights and licenses granted hereunder, each
59 | Recipient hereby assumes sole responsibility to secure any other
60 | intellectual property rights needed, if any. For example, if a third party
61 | patent license is required to allow Recipient to distribute the Program, it
62 | is Recipient's responsibility to acquire that license before distributing
63 | the Program.
64 | d) Each Contributor represents that to its knowledge it has sufficient
65 | copyright rights in its Contribution, if any, to grant the copyright
66 | license set forth in this Agreement.
67 |
68 | 3. REQUIREMENTS
69 |
70 | A Contributor may choose to distribute the Program in object code form under its
71 | own license agreement, provided that:
72 |
73 | a) it complies with the terms and conditions of this Agreement; and
74 | b) its license agreement:
75 | i) effectively disclaims on behalf of all Contributors all warranties and
76 | conditions, express and implied, including warranties or conditions of
77 | title and non-infringement, and implied warranties or conditions of
78 | merchantability and fitness for a particular purpose;
79 | ii) effectively excludes on behalf of all Contributors all liability for
80 | damages, including direct, indirect, special, incidental and
81 | consequential damages, such as lost profits;
82 | iii) states that any provisions which differ from this Agreement are offered
83 | by that Contributor alone and not by any other party; and
84 | iv) states that source code for the Program is available from such
85 | Contributor, and informs licensees how to obtain it in a reasonable
86 | manner on or through a medium customarily used for software exchange.
87 |
88 | When the Program is made available in source code form:
89 |
90 | a) it must be made available under this Agreement; and
91 | b) a copy of this Agreement must be included with each copy of the Program.
92 | Contributors may not remove or alter any copyright notices contained within
93 | the Program.
94 |
95 | Each Contributor must identify itself as the originator of its Contribution, if
96 | any, in a manner that reasonably allows subsequent Recipients to identify the
97 | originator of the Contribution.
98 |
99 | 4. COMMERCIAL DISTRIBUTION
100 |
101 | Commercial distributors of software may accept certain responsibilities with
102 | respect to end users, business partners and the like. While this license is
103 | intended to facilitate the commercial use of the Program, the Contributor who
104 | includes the Program in a commercial product offering should do so in a manner
105 | which does not create potential liability for other Contributors. Therefore, if
106 | a Contributor includes the Program in a commercial product offering, such
107 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
108 | every other Contributor ("Indemnified Contributor") against any losses, damages
109 | and costs (collectively "Losses") arising from claims, lawsuits and other legal
110 | actions brought by a third party against the Indemnified Contributor to the
111 | extent caused by the acts or omissions of such Commercial Contributor in
112 | connection with its distribution of the Program in a commercial product
113 | offering. The obligations in this section do not apply to any claims or Losses
114 | relating to any actual or alleged intellectual property infringement. In order
115 | to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
116 | Contributor in writing of such claim, and b) allow the Commercial Contributor to
117 | control, and cooperate with the Commercial Contributor in, the defense and any
118 | related settlement negotiations. The Indemnified Contributor may participate in
119 | any such claim at its own expense.
120 |
121 | For example, a Contributor might include the Program in a commercial product
122 | offering, Product X. That Contributor is then a Commercial Contributor. If that
123 | Commercial Contributor then makes performance claims, or offers warranties
124 | related to Product X, those performance claims and warranties are such
125 | Commercial Contributor's responsibility alone. Under this section, the
126 | Commercial Contributor would have to defend claims against the other
127 | Contributors related to those performance claims and warranties, and if a court
128 | requires any other Contributor to pay any damages as a result, the Commercial
129 | Contributor must pay those damages.
130 |
131 | 5. NO WARRANTY
132 |
133 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
134 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
135 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
136 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
137 | Recipient is solely responsible for determining the appropriateness of using and
138 | distributing the Program and assumes all risks associated with its exercise of
139 | rights under this Agreement , including but not limited to the risks and costs
140 | of program errors, compliance with applicable laws, damage to or loss of data,
141 | programs or equipment, and unavailability or interruption of operations.
142 |
143 | 6. DISCLAIMER OF LIABILITY
144 |
145 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
146 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
147 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
148 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
149 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
150 | OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
151 | GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
152 |
153 | 7. GENERAL
154 |
155 | If any provision of this Agreement is invalid or unenforceable under applicable
156 | law, it shall not affect the validity or enforceability of the remainder of the
157 | terms of this Agreement, and without further action by the parties hereto, such
158 | provision shall be reformed to the minimum extent necessary to make such
159 | provision valid and enforceable.
160 |
161 | If Recipient institutes patent litigation against any entity (including a
162 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself
163 | (excluding combinations of the Program with other software or hardware)
164 | infringes such Recipient's patent(s), then such Recipient's rights granted under
165 | Section 2(b) shall terminate as of the date such litigation is filed.
166 |
167 | All Recipient's rights under this Agreement shall terminate if it fails to
168 | comply with any of the material terms or conditions of this Agreement and does
169 | not cure such failure in a reasonable period of time after becoming aware of
170 | such noncompliance. If all Recipient's rights under this Agreement terminate,
171 | Recipient agrees to cease use and distribution of the Program as soon as
172 | reasonably practicable. However, Recipient's obligations under this Agreement
173 | and any licenses granted by Recipient relating to the Program shall continue and
174 | survive.
175 |
176 | Everyone is permitted to copy and distribute copies of this Agreement, but in
177 | order to avoid inconsistency the Agreement is copyrighted and may only be
178 | modified in the following manner. The Agreement Steward reserves the right to
179 | publish new versions (including revisions) of this Agreement from time to time.
180 | No one other than the Agreement Steward has the right to modify this Agreement.
181 | The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation
182 | may assign the responsibility to serve as the Agreement Steward to a suitable
183 | separate entity. Each new version of the Agreement will be given a
184 | distinguishing version number. The Program (including Contributions) may always
185 | be distributed subject to the version of the Agreement under which it was
186 | received. In addition, after a new version of the Agreement is published,
187 | Contributor may elect to distribute the Program (including its Contributions)
188 | under the new version. Except as expressly stated in Sections 2(a) and 2(b)
189 | above, Recipient receives no rights or licenses to the intellectual property of
190 | any Contributor under this Agreement, whether expressly, by implication,
191 | estoppel or otherwise. All rights in the Program not expressly granted under
192 | this Agreement are reserved.
193 |
194 | This Agreement is governed by the laws of the State of New York and the
195 | intellectual property laws of the United States of America. No party to this
196 | Agreement will bring a legal action under this Agreement more than one year
197 | after the cause of action arose. Each party waives its rights to a jury trial in
198 | any resulting litigation.
199 |
--------------------------------------------------------------------------------