├── doc └── profile-screenshot.png ├── .gitignore ├── project.clj ├── src └── nrepl_profile │ ├── plugin.clj │ └── core.clj ├── README.md ├── cider-profile.el └── LICENSE /doc/profile-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thunknyc/nrepl-profile/HEAD/doc/profile-screenshot.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject thunknyc/nrepl-profile "0.1.0-SNAPSHOT" 2 | :description "nrepl support for thunknyc/progile" 3 | :url "http://github.com/thunknyc/nrepl-profile" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[thunknyc/profile "0.5.2"]] 7 | :exclusions [org.clojure/clojure] 8 | :profiles {:1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]} 9 | :1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]} 10 | :1.7 {:dependencies [[org.clojure/clojure "1.7.0-master-SNAPSHOT"]]} 11 | :dev {:repl-options {:nrepl-middleware [nrepl-profile.core/wrap-profile]}}}) 12 | -------------------------------------------------------------------------------- /src/nrepl_profile/plugin.clj: -------------------------------------------------------------------------------- 1 | (ns nrepl-profile.plugin 2 | (:require [clojure.java.io :as io])) 3 | 4 | (defn- version [] 5 | (let [v (-> (io/resource "META-INF/leiningen/thunknyc/nrepl-profile/project.clj") 6 | slurp 7 | read-string 8 | (nth 2))] 9 | (assert (string? v) 10 | (str "Something went wrong, version is not a string: " 11 | v)) 12 | v)) 13 | 14 | (defn middleware [project] 15 | (-> project 16 | (update-in [:dependencies] 17 | (fnil into []) 18 | [['thunknyc/nrepl-profile (version)]]) 19 | (update-in [:repl-options :nrepl-middleware] 20 | (fnil into []) 21 | '[nrepl-profile.core/wrap-profile]))) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nrepl-profile 2 | 3 | > ## This functionality has been [integrated into CIDER itself](https://github.com/clojure-emacs/cider/pull/2197). Don't use this project if using a version of CIDER with built-in profiling, as it would cause problems. 4 | 5 | nREPL and CIDER support for 6 | [thunknyc/profile](http://github.com/thunknyc/profile). 7 | 8 | ![Screenshot](https://raw.github.com/thunknyc/nrepl-profile/master/doc/profile-screenshot.png) 9 | 10 | ## Introduction 11 | 12 | Profiling is a rich and varied field of human endeavour. I 13 | encourage you to consider what you're trying to accomplish by 14 | profiling. This package for CIDER may not be suited to your current 15 | needs. What is nrepl-profile good for? It's intended for 16 | interactive profiling applications where you do not expect a 17 | profiling tool to automatically compensate for JVM warm-up and 18 | garbage collection issues. If you are doing numeric computing or 19 | writing other purely functional code that can be executed 20 | repeatedly without unpleasant side effects, I recommend you at the 21 | very least check out [Criterium](https://github.com/hugoduncan/criterium). 22 | 23 | If you are primarily concerned about the influence of JVM-exogenous 24 | factors on your code—HTTP requests, SQL queries, other network- or 25 | (possibly) filesystem-accessing operations—then this package may be 26 | just what the doctor ordered. 27 | 28 | ## Installation 29 | 30 | [![MELPA](http://melpa.org/packages/cider-profile-badge.svg)](http://melpa.org/#/cider-profile) 31 | 32 | Add `[thunknyc/nrepl-profile "0.1.0-SNAPSHOT"]` to the vector 33 | associated with the `:plugins` key of your `:user` profile inside 34 | `${HOME}/.lein/profiles.clj`. Schematically, like this: 35 | 36 | ```clojure 37 | {:user {:plugins [[thunknyc/nrepl-profile "0.1.0-SNAPSHOT"]]}} 38 | ``` 39 | 40 | Obviously the plug-in for CIDER needs to be in there too. 41 | 42 | For Emacs, stick `cider-profile.el` somewhere accessible and add 43 | `(require 'cider-profile)` to your `${HOME}/.emacs`, 44 | `${HOME}/.emacs.d/init.el`, whatever. 45 | 46 | Add the following to your `init.el`, `.emacs`, whatever: 47 | 48 | ``` 49 | (add-hook 'cider-mode-hook 'cider-profile-mode) 50 | (add-hook 'cider-repl-mode-hook 'cider-profile-mode) 51 | ``` 52 | 53 | If you would like to display profiling statistics in the current repl 54 | window instead of in a pop-up window, do the following: 55 | 56 | ``` 57 | (setq cider-profile-buffer nil) 58 | ``` 59 | 60 | ## Keybindings 61 | 62 | Cider-profile includes the following keybindings out of the box: 63 | 64 | * `C-c =` Toggle profiling of var under point. 65 | * `C-c +` Toggle profiling of namespace. 66 | * `C-c M-=` Report whether var under point is profiled. 67 | * `C-c M-+` Display (and, with `C-u`, set) current maximum per-var samples. 68 | * `C-c -` Display summary of profiling data. 69 | * `C-c M--` Display profiling data for var under point. 70 | * `C-c _` Clear collected profiling data. 71 | 72 | ## License 73 | 74 | Copyright © 2014 Edwin Watkeys 75 | 76 | Distributed under the Eclipse Public License either version 1.0 or (at 77 | your option) any later version. 78 | -------------------------------------------------------------------------------- /src/nrepl_profile/core.clj: -------------------------------------------------------------------------------- 1 | (ns nrepl-profile.core 2 | (:require [clojure.string :as s] 3 | [profile.core :as p] 4 | [clojure.tools.nrepl.transport :as t] 5 | [clojure.tools.nrepl.middleware :refer [set-descriptor!]] 6 | [clojure.tools.nrepl.misc :refer [response-for]] 7 | [cider.nrepl.middleware.util.misc :as u])) 8 | 9 | (defn send-exception 10 | [e msg transport] 11 | (t/send transport (response-for msg :status :done :value "exception"))) 12 | 13 | (defn toggle-profile 14 | [{:keys [ns sym transport] :as msg}] 15 | (try 16 | (if-let [v (ns-resolve (symbol ns) (symbol sym))] 17 | (let [profiled? (p/toggle-profile-var* v)] 18 | (t/send transport 19 | (response-for 20 | msg 21 | :status :done 22 | :value (if profiled? "profiled" "unprofiled")))) 23 | (t/send transport 24 | (response-for 25 | msg 26 | :status #{:toggle-profile-not-such-var :done} 27 | :value "unbound"))) 28 | (catch Exception e (send-exception e msg transport)))) 29 | 30 | (defn profile-var-summary 31 | [{:keys [ns sym transport] :as msg}] 32 | (try 33 | (if-let [v (ns-resolve (symbol ns) (symbol sym))] 34 | (if-let [table (with-out-str (binding [*err* *out*] 35 | (p/print-entry-summary v)))] 36 | (t/send transport 37 | (response-for msg 38 | :status :done 39 | :err table)) 40 | (t/send transport 41 | (response-for msg 42 | :status :done 43 | :err (format "No profile data for %s." v)))) 44 | (t/send transport 45 | (response-for msg 46 | :status :done 47 | :value (format "Var %s/%s is not bound." ns sym)))) 48 | (catch Exception e (prn :e e) (send-exception e msg transport)))) 49 | 50 | (defn profile-summary 51 | [{:keys [transport] :as msg}] 52 | (try 53 | (t/send transport 54 | (response-for msg 55 | :status :done 56 | :err (with-out-str 57 | (binding [*err* *out*] (p/print-summary))))) 58 | (catch Exception e (send-exception e msg transport)))) 59 | 60 | (defn clear-profile 61 | [{:keys [transport] :as msg}] 62 | (try 63 | (p/clear-profile-data) 64 | (t/send transport 65 | (response-for msg 66 | :status :done 67 | :value "cleared")) 68 | (catch Exception e (send-exception e msg transport)))) 69 | 70 | (defn toggle-profile-ns 71 | [{:keys [ns transport] :as msg}] 72 | (try (let [profiled? (p/toggle-profile-ns (symbol ns))] 73 | (t/send transport 74 | (response-for 75 | msg 76 | :status :done 77 | :value (if profiled? "profiled" "unprofiled")))) 78 | (catch Exception e (send-exception e msg transport)))) 79 | 80 | (defn is-var-profiled 81 | [{:keys [ns sym transport] :as msg}] 82 | (try (let [var (ns-resolve (symbol ns) (symbol sym)) 83 | profiled? (p/profiled? @var)] 84 | (t/send transport 85 | (response-for 86 | msg 87 | :status :done 88 | :value (if profiled? "profiled" "unprofiled")))) 89 | (catch Exception e (send-exception e msg transport)))) 90 | 91 | (defn get-max-samples 92 | [{:keys [transport] :as msg}] 93 | (try (t/send transport 94 | (response-for 95 | msg 96 | :status :done 97 | :value (str (p/max-sample-count)))) 98 | (catch Exception e (send-exception e msg transport)))) 99 | 100 | (defn normalize-max-samples [n] 101 | (cond (and (sequential? n) (empty? n)) nil 102 | (string? n) (Long/parseLong n) 103 | :else n)) 104 | 105 | (defn set-max-samples 106 | [{:keys [max-samples transport] :as msg}] 107 | (try (let [max-samples (normalize-max-samples max-samples)] 108 | (p/set-max-sample-count max-samples) 109 | (t/send transport 110 | (response-for 111 | msg 112 | :status :done 113 | :value (str (p/max-sample-count))))) 114 | (catch Exception e (send-exception e msg transport)))) 115 | 116 | (defn wrap-profile 117 | "Middleware that toggles profiling of a given var." 118 | [handler] 119 | (fn [{:keys [op] :as msg}] 120 | (case op 121 | "toggle-profile" 122 | (toggle-profile msg) 123 | "toggle-profile-ns" 124 | (toggle-profile-ns msg) 125 | "is-var-profiled" 126 | (is-var-profiled msg) 127 | "profile-summary" 128 | (profile-summary msg) 129 | "profile-var-summary" 130 | (profile-var-summary msg) 131 | "clear-profile" 132 | (clear-profile msg) 133 | "get-max-samples" 134 | (get-max-samples msg) 135 | "set-max-samples" 136 | (set-max-samples msg) 137 | (handler msg)))) 138 | 139 | (set-descriptor! 140 | #'wrap-profile 141 | {:handles 142 | {"toggle-profile-ns" 143 | {:doc "Toggle profiling of given namespace." 144 | :requires {"ns" "The current namespace"} 145 | :returns {"status" "Done" 146 | "value" "'profiled' if profiling enabled, 'unprofiled' if disabled"}} 147 | "is-var-profiled" 148 | {:doc "Reports wheth symbol is currently profiled." 149 | :requires {"sym" "The symbol to check" 150 | "ns" "The current namespace"} 151 | :returns {"status" "Done" 152 | "value" "'profiled' if profiling enabled, 'unprofiled' if disabled"}} 153 | "get-max-samples" 154 | {:doc "Returns maximum number of samples to be collected for any var." 155 | :requires {} 156 | :returns {"status" "Done" 157 | "value" "String representing number of max-sample-count"}} 158 | "set-max-samples" 159 | {:doc "Sets maximum sample count. Returns new max-sample-count." 160 | :requires {"max-samples" "Maxiumum samples to collect for any single var."} 161 | :returns {"status" "Done" 162 | "value" "String representing number of max-sample-count"}} 163 | "toggle-profile" 164 | {:doc "Toggle profiling of a given var." 165 | :requires {"sym" "The symbol to profile" 166 | "ns" "The current namespace"} 167 | :returns {"status" "Done" 168 | "value" "'profiled' if profiling enabled, 'unprofiled' if disabled, 'unbound' if ns/sym not bound"}} 169 | "profile-var-summary" 170 | {:doc "Return profiling data summary for a single var." 171 | :requires {"sym" "The symbol to profile" 172 | "ns" "The current namespace"} 173 | :returns {"status" "Done" 174 | "err" "Content of profile summary report"}} 175 | "profile-summary" 176 | {:doc "Return profiling data summary." 177 | :requires {} 178 | :returns {"status" "Done" 179 | "err" "Content of profile summary report"}} 180 | "clear-profile" 181 | {:doc "Clears profile of samples." 182 | :requires {} 183 | :returns {"status" "Done"}}}}) 184 | -------------------------------------------------------------------------------- /cider-profile.el: -------------------------------------------------------------------------------- 1 | ;;; cider-profile.el --- CIDER profiling support -*- lexical-binding: t -*- 2 | ;; Copyright © 2014 Edwin Watkeys 3 | ;; 4 | ;; Author: Edwin Watkeys 5 | ;; Version: 0.1.0 6 | ;; Package-Requires: ((cider "0.8.0")) 7 | ;; Keywords: cider, clojure, profiling 8 | ;; URL: http://github.com/thunknyc/nrepl-profile 9 | 10 | ;; This program is free software: you can redistribute it and/or modify 11 | ;; it under the terms of the GNU General Public License as published by 12 | ;; the Free Software Foundation, either version 3 of the License, or 13 | ;; (at your option) any later version. 14 | 15 | ;; This program is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with this program. If not, see . 22 | 23 | ;; This file is not part of GNU Emacs. 24 | 25 | ;;; Commentary: 26 | 27 | ;; This package augments CIDER to provide coarse-grained interactive 28 | ;; profiling support. 29 | 30 | ;;; Installation: 31 | 32 | ;; Available as a package in melpa.milkbox.net. 33 | ;; 34 | ;; (add-to-list 'package-archives 35 | ;; '("melpa" . "http://melpa.milkbox.net/packages/") t) 36 | ;; 37 | ;; M-x package-install cider-profile 38 | ;; 39 | ;; On the Clojure side, add `[thunknyc/nrepl-profile "0.1.0-SNAPSHOT"]` 40 | ;; to the vector associated with the `:plugins` key of your `:user` 41 | ;; profile inside `${HOME}/.lein/profiles.clj`. Schematically, like 42 | ;; this: 43 | ;; 44 | ;; ```clojure 45 | ;; {:user {:plugins [[thunknyc/nrepl-profile "0.1.0-SNAPSHOT"]]}} 46 | ;; ``` 47 | ;; 48 | ;; Profiling is a rich and varied field of human endeavour. I 49 | ;; encourage you to consider what you're trying to accomplish by 50 | ;; profiling. This package for CIDER may not be suited to your current 51 | ;; needs. What is nrepl-profile good for? It's intended for 52 | ;; interactive profiling applications where you do not expect a 53 | ;; profiling tool to automatically compensate for JVM warm-up and 54 | ;; garbage collection issues. If you are doing numeric computing or 55 | ;; writing other purely functional code that can be executed 56 | ;; repeatedly without unpleasant side effects, I recommend you at the 57 | ;; very least check out [Criterium](https://github.com/hugoduncan/criterium). 58 | ;; 59 | ;; If you are primarily concerned about the influence of JVM-exogenous 60 | ;; factors on your code—HTTP requests, SQL queries, other network- or 61 | ;; (possibly) filesystem-accessing operations—then this package may be 62 | ;; just what the doctor ordered. 63 | ;; 64 | ;; Usage: 65 | ;; 66 | ;; Add the following to your `init.el`, `.emacs`, whatever: 67 | ;; 68 | ;; ``` 69 | ;; (add-hook 'cider-mode-hook 'cider-profile-mode) 70 | ;; (add-hook 'cider-repl-mode-hook 'cider-profile-mode) 71 | ;; ``` 72 | ;; 73 | ;; If you would like to display profiling statistics in the current 74 | ;; repl window instead of in a pop-up window, do the following: 75 | ;; 76 | ;; ``` 77 | ;; (setq cider-profile-buffer nil) 78 | ;; ``` 79 | ;; 80 | ;; Cider-profile includes the following keybindings out of the box: 81 | ;; 82 | ;; * `C-c =` Toggle profiling of var under point. 83 | ;; * `C-c +` Toggle profiling of namespace. 84 | ;; * `C-c M-=` Report whether var under point is profiled. 85 | ;; * `C-c M-+` Display (and, with `C-u`, set) current maximum per-var samples. 86 | ;; * `C-c -` Display summary of profiling data. 87 | ;; * `C-c M--` Display profiling data for var under point. 88 | ;; * `C-c _` Clear collected profiling data. 89 | 90 | ;;; Code: 91 | 92 | (require 'cider) 93 | 94 | (defconst cider-profile-buffer "*cider-profile*") 95 | 96 | ;;;###autoload 97 | (defun cider-profile-samples (&optional query) 98 | "Displays current max-sample-count. If optional QUERY is 99 | specified, set max-sample-count and display new value." 100 | (interactive "P") 101 | (cider-ensure-op-supported "set-max-samples") 102 | (cider-ensure-op-supported "get-max-samples") 103 | (if (not (null query)) 104 | (nrepl-send-request 105 | (let ((max-samples (if (numberp query) query '()))) 106 | (message (format "query: %s" max-samples)) 107 | (list "op" "set-max-samples" "max-samples" max-samples)) 108 | (nrepl-make-response-handler 109 | (current-buffer) 110 | (lambda (_buffer value) 111 | (let ((value (if (zerop (length value)) "unlimited" value))) 112 | (message (format "max-sample-count is now %s." value)))) 113 | '() 114 | '() 115 | '())) 116 | (nrepl-send-request 117 | (list "op" "get-max-samples") 118 | (nrepl-make-response-handler 119 | (current-buffer) 120 | (lambda (_buffer value) 121 | (let ((value (if (zerop (length value)) "unlimited" value))) 122 | (message (format "max-sample-count is now %s." value)))) 123 | '() 124 | '() 125 | '()))) 126 | query) 127 | 128 | ;;;###autoload 129 | (defun cider-profile-var-profiledp (query) 130 | "Displays the profiling status of var under point. Prompts for 131 | var if none under point or prefix argument is present." 132 | (interactive "P") 133 | (cider-ensure-op-supported "is-var-profiled") 134 | (cider-read-symbol-name 135 | "Report profiling status for var: " 136 | (lambda (sym) 137 | (let ((ns (cider-current-ns))) 138 | (nrepl-send-request 139 | (list "op" "is-var-profiled" 140 | "ns" ns 141 | "sym" sym) 142 | (nrepl-make-response-handler 143 | (current-buffer) 144 | (lambda (_buffer value) 145 | (cond ((equal value "profiled") 146 | (message (format "profiling %s/%s." ns sym))) 147 | ((equal value "unprofiled") 148 | (message (format "not profiling %s/%s." ns sym))) 149 | ((equal value "unbound") 150 | (message (format "%s/%s is not bound." ns sym))))) 151 | '() 152 | '() 153 | '())))) 154 | query)) 155 | 156 | ;;;###autoload 157 | (defun cider-profile-ns-toggle (&optional query) 158 | "Toggle profiling for the ns associated with optional QUERY or, 159 | if nil current ns." 160 | (interactive "P") 161 | (cider-ensure-op-supported "toggle-profile-ns") 162 | (let ((ns (if query (completing-read 163 | "Toggle profiling for ns: " (cider-sync-request:ns-list)) 164 | (cider-current-ns)))) 165 | (nrepl-send-request 166 | (list "op" "toggle-profile-ns" 167 | "ns" ns) 168 | (nrepl-make-response-handler 169 | (current-buffer) 170 | (lambda (_buffer value) 171 | (cond ((equal value "profiled") 172 | (message (format "profiling %s." ns))) 173 | ((equal value "unprofiled") 174 | (message (format "not profiling %s." ns))))) 175 | '() 176 | '() 177 | '()))) 178 | query) 179 | 180 | ;;;###autoload 181 | (defun cider-profile-toggle (query) 182 | "Toggle profiling for the given QUERY. 183 | Defaults to the symbol at point. With prefix arg or no symbol at 184 | point, prompts for a var." 185 | (interactive "P") 186 | (cider-ensure-op-supported "toggle-profile") 187 | (cider-read-symbol-name 188 | "Toggle profiling for var: " 189 | (lambda (sym) 190 | (let ((ns (cider-current-ns))) 191 | (nrepl-send-request 192 | (list "op" "toggle-profile" 193 | "ns" ns 194 | "sym" sym) 195 | (nrepl-make-response-handler 196 | (current-buffer) 197 | (lambda (_buffer value) 198 | (cond ((equal value "profiled") 199 | (message (format "profiling %s/%s." ns sym))) 200 | ((equal value "unprofiled") 201 | (message (format "not profiling %s/%s." ns sym))) 202 | ((equal value "unbound") 203 | (message (format "%s/%s is not bound." ns sym))))) 204 | '() 205 | '() 206 | '())))) 207 | query)) 208 | 209 | (defun cider-profile-display-stats (stats-response) 210 | (let ((table (nrepl-dict-get stats-response "err"))) 211 | (if cider-profile-buffer 212 | (let ((buffer (cider-make-popup-buffer cider-profile-buffer))) 213 | (with-current-buffer buffer 214 | (let ((inhibit-read-only t)) (insert table))) 215 | (display-buffer buffer) 216 | (let ((window (get-buffer-window buffer))) 217 | (set-window-point window 0) 218 | (select-window window) 219 | (fit-window-to-buffer window))) 220 | (cider-repl-emit-err-output (cider-current-repl-buffer) table)))) 221 | 222 | ;;;###autoload 223 | (defun cider-profile-summary (query) 224 | "Display a summary of currently collected profile data." 225 | (interactive "P") 226 | (cider-ensure-op-supported "profile-summary") 227 | (cider-profile-display-stats 228 | (nrepl-send-sync-request (list "op" "profile-summary"))) 229 | query) 230 | 231 | ;;;###autoload 232 | (defun cider-profile-var-summary (query) 233 | "Display profile data for var under point, prompting if none or 234 | prefix argument given." 235 | (interactive "P") 236 | (cider-ensure-op-supported "profile-var-summary") 237 | (cider-read-symbol-name 238 | "Profile-summary for var: " 239 | (lambda (sym) 240 | (cider-profile-display-stats 241 | (nrepl-send-sync-request 242 | (list "op" "profile-var-summary" 243 | "ns" (cider-current-ns) 244 | "sym" sym))))) 245 | query) 246 | 247 | ;;;###autoload 248 | (defun cider-profile-clear (query) 249 | "Clear any collected profile data." 250 | (interactive "P") 251 | (cider-ensure-op-supported "clear-profile") 252 | (nrepl-send-request 253 | (list "op" "clear-profile") 254 | (nrepl-make-response-handler 255 | (current-buffer) 256 | (lambda (_buffer value) 257 | (when (equal value "cleared") 258 | (message "cleared profile data."))) 259 | '() 260 | '() 261 | '())) 262 | query) 263 | 264 | ;;;###autoload 265 | (define-minor-mode cider-profile-mode 266 | "Toggle cider-profile-mode." 267 | nil 268 | nil 269 | `((,(kbd "C-c =") . cider-profile-toggle) 270 | (,(kbd "C-c _") . cider-profile-clear) 271 | (,(kbd "C-c -") . cider-profile-summary) 272 | (,(kbd "C-c M--") . cider-profile-var-summary) 273 | (,(kbd "C-c +") . cider-profile-ns-toggle) 274 | (,(kbd "C-c M-=") . cider-profile-var-profiledp) 275 | (,(kbd "C-c M-+") . cider-profile-samples))) 276 | 277 | (provide 'cider-profile) 278 | 279 | ;;; cider-profile.el ends here 280 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor tocontrol, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | --------------------------------------------------------------------------------