summaryrefslogtreecommitdiff
path: root/src/http/static/viz/2/cljs/core.cljs
diff options
context:
space:
mode:
Diffstat (limited to 'src/http/static/viz/2/cljs/core.cljs')
-rw-r--r--src/http/static/viz/2/cljs/core.cljs11565
1 files changed, 11565 insertions, 0 deletions
diff --git a/src/http/static/viz/2/cljs/core.cljs b/src/http/static/viz/2/cljs/core.cljs
new file mode 100644
index 0000000..c7f6d9a
--- /dev/null
+++ b/src/http/static/viz/2/cljs/core.cljs
@@ -0,0 +1,11565 @@
+; Copyright (c) Rich Hickey. All rights reserved.
+; The use and distribution terms for this software are covered by the
+; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+; which can be found in the file epl-v10.html at the root of this distribution.
+; By using this software in any fashion, you are agreeing to be bound by
+; the terms of this license.
+; You must not remove this notice, or any other, from this software.
+
+(ns cljs.core
+ (:require goog.math.Long
+ goog.math.Integer
+ [goog.string :as gstring]
+ [goog.object :as gobject]
+ [goog.array :as garray]
+ [goog.Uri])
+ (:import [goog.string StringBuffer]))
+
+;; next line is auto-generated by the build-script - Do not edit!
+(def *clojurescript-version* "1.10.439")
+
+;; Setting of these Vars is in ClojureScript code is associated with intrinsics
+;; that affect compilation state, but otherwise turn into no-ops in the emitted
+;; JavaScript.
+
+;; The scope of *unchecked-if* is controlled by balanced pairs of set! calls.
+(def *unchecked-if* false)
+;; The scope of *unchecked-arrays* is file-scope: In JVM ClojureScript its side-
+;; effect is to set same-named analyzer dynamic Var, which is unset via binding
+;; scopes. In self-hosted it is cleared via cljs.js/post-file-side-effects.
+(def *unchecked-arrays* false)
+;; The scope of *warn-on-infer* is file-scope: Its side effect is to set the
+;; cljs.analyzer/*cljs-warnings* dynamic Var, which is unset via binding scopes.
+(def *warn-on-infer* false)
+
+(set! *unchecked-arrays* true)
+
+(defonce PROTOCOL_SENTINEL #js {})
+
+(def MODULE_URIS nil) ;; set by compiler
+(def MODULE_INFOS nil) ;; set by compiler
+
+(goog-define
+ ^{:dynamic true
+ :doc "Var bound to the name value of the compiler build :target option.
+ For example, if the compiler build :target is :nodejs, *target* will be bound
+ to \"nodejs\". *target* is a Google Closure define and can be set by compiler
+ :closure-defines option."}
+ *target* "default")
+
+(def
+ ^{:dynamic true
+ :doc "Var bound to the current namespace. Only used for bootstrapping."
+ :jsdoc ["@type {*}"]}
+ *ns* nil)
+
+(def
+ ^{:dynamic true
+ :jsdoc ["@type {*}"]}
+ *out* nil)
+
+(def
+ ^{:dynamic true}
+ *assert* true)
+
+(defonce
+ ^{:doc "Each runtime environment provides a different way to print output.
+ Whatever function *print-fn* is bound to will be passed any
+ Strings which should be printed." :dynamic true}
+ *print-fn* nil)
+
+(defn ^{:doc "Arranges to have tap functions executed via the supplied f, a
+ function of no arguments. Returns true if successful, false otherwise." :dynamic true}
+ *exec-tap-fn*
+ [f]
+ (and
+ (exists? js/setTimeout)
+ (js/setTimeout f 0)
+ true))
+
+(defonce
+ ^{:doc "Each runtime environment provides a different way to print error output.
+ Whatever function *print-err-fn* is bound to will be passed any
+ Strings which should be printed." :dynamic true}
+ *print-err-fn* nil)
+
+(defn set-print-fn!
+ "Set *print-fn* to f."
+ [f] (set! *print-fn* f))
+
+(defn set-print-err-fn!
+ "Set *print-err-fn* to f."
+ [f] (set! *print-err-fn* f))
+
+(def
+ ^{:dynamic true
+ :doc "When set to true, output will be flushed whenever a newline is printed.
+
+ Defaults to true."}
+ *flush-on-newline* true)
+
+(def
+ ^{:dynamic true
+ :doc "When set to logical false will drop newlines from printing calls.
+ This is to work around the implicit newlines emitted by standard JavaScript
+ console objects."}
+ *print-newline* true)
+
+(def
+ ^{:dynamic true
+ :doc "When set to logical false, strings and characters will be printed with
+ non-alphanumeric characters converted to the appropriate escape sequences.
+
+ Defaults to true"}
+ *print-readably* true)
+
+(def
+ ^{:dynamic true
+ :doc "If set to logical true, when printing an object, its metadata will also
+ be printed in a form that can be read back by the reader.
+
+ Defaults to false."}
+ *print-meta* false)
+
+(def
+ ^{:dynamic true
+ :doc "When set to logical true, objects will be printed in a way that preserves
+ their type when read in later.
+
+ Defaults to false."}
+ *print-dup* false)
+
+(def
+ ^{:dynamic true
+ :doc "*print-namespace-maps* controls whether the printer will print
+ namespace map literal syntax.
+
+ Defaults to false, but the REPL binds it to true."}
+ *print-namespace-maps* false)
+
+(def
+ ^{:dynamic true
+ :doc "*print-length* controls how many items of each collection the
+ printer will print. If it is bound to logical false, there is no
+ limit. Otherwise, it must be bound to an integer indicating the maximum
+ number of items of each collection to print. If a collection contains
+ more items, the printer will print items up to the limit followed by
+ '...' to represent the remaining items. The root binding is nil
+ indicating no limit."
+ :jsdoc ["@type {null|number}"]}
+ *print-length* nil)
+
+(def
+ ^{:dynamic true
+ :doc "*print-level* controls how many levels deep the printer will
+ print nested objects. If it is bound to logical false, there is no
+ limit. Otherwise, it must be bound to an integer indicating the maximum
+ level to print. Each argument to print is at level 0; if an argument is a
+ collection, its items are at level 1; and so on. If an object is a
+ collection and is at a level greater than or equal to the value bound to
+ *print-level*, the printer prints '#' to represent it. The root binding
+ is nil indicating no limit."
+ :jsdoc ["@type {null|number}"]}
+ *print-level* nil)
+
+(def
+ ^{:dynamic true
+ :doc "*print-fns-bodies* controls whether functions print their source or
+ only their names."}
+ *print-fn-bodies* false)
+
+(defonce
+ ^{:dynamic true
+ :jsdoc ["@type {*}"]}
+ *loaded-libs* nil)
+
+(defn- pr-opts []
+ {:flush-on-newline *flush-on-newline*
+ :readably *print-readably*
+ :meta *print-meta*
+ :dup *print-dup*
+ :print-length *print-length*})
+
+(declare into-array)
+
+(defn enable-console-print!
+ "Set *print-fn* to console.log"
+ []
+ (set! *print-newline* false)
+ (set-print-fn!
+ (fn []
+ (let [xs (js-arguments)]
+ (.apply (.-log js/console) js/console (garray/clone xs)))))
+ (set-print-err-fn!
+ (fn []
+ (let [xs (js-arguments)]
+ (.apply (.-error js/console) js/console (garray/clone xs)))))
+ nil)
+
+(def
+ ^{:doc "bound in a repl thread to the most recent value printed"}
+ *1)
+
+(def
+ ^{:doc "bound in a repl thread to the second most recent value printed"}
+ *2)
+
+(def
+ ^{:doc "bound in a repl thread to the third most recent value printed"}
+ *3)
+
+(def
+ ^{:doc "bound in a repl thread to the most recent exception caught by the repl"}
+ *e)
+
+(defn truth_
+ "Internal - do not use!"
+ [x]
+ (cljs.core/truth_ x))
+
+(def not-native nil)
+
+(declare instance? Keyword)
+
+(defn ^boolean identical?
+ "Tests if 2 arguments are the same object"
+ [x y]
+ (cljs.core/identical? x y))
+
+(defn ^boolean nil?
+ "Returns true if x is nil, false otherwise."
+ [x]
+ (coercive-= x nil))
+
+(defn ^boolean array?
+ "Returns true if x is a JavaScript array."
+ [x]
+ (if (identical? *target* "nodejs")
+ (.isArray js/Array x)
+ (instance? js/Array x)))
+
+(defn ^boolean number?
+ "Returns true if x is a JavaScript number."
+ [x]
+ (cljs.core/number? x))
+
+(defn ^boolean not
+ "Returns true if x is logical false, false otherwise."
+ [x]
+ (cond
+ (nil? x) true
+ (false? x) true
+ :else false))
+
+(defn ^boolean some?
+ "Returns true if x is not nil, false otherwise."
+ [x] (not (nil? x)))
+
+(defn ^boolean object?
+ "Returns true if x's constructor is Object"
+ [x]
+ (if-not (nil? x)
+ (identical? (.-constructor x) js/Object)
+ false))
+
+(defn ^boolean string?
+ "Returns true if x is a JavaScript string."
+ [x]
+ (goog/isString x))
+
+(defn ^boolean char?
+ "Returns true if x is a JavaScript string of length one."
+ [x]
+ (and (string? x) (== 1 (.-length x))))
+
+(defn ^boolean any?
+ "Returns true if given any argument."
+ [x] true)
+
+(set! *unchecked-if* true)
+(defn ^boolean native-satisfies?
+ "Internal - do not use!"
+ [p x]
+ (let [x (if (nil? x) nil x)]
+ (cond
+ (unchecked-get p (goog/typeOf x)) true
+ (unchecked-get p "_") true
+ :else false)))
+(set! *unchecked-if* false)
+
+(defn is_proto_
+ [x]
+ (identical? (.-prototype (.-constructor x)) x))
+
+(def
+ ^{:doc "When compiled for a command-line target, whatever function
+ *main-cli-fn* is set to will be called with the command-line
+ argv as arguments"}
+ *main-cli-fn* nil)
+
+(def
+ ^{:doc "A sequence of the supplied command line arguments, or nil if
+ none were supplied"}
+ *command-line-args* nil)
+
+(defn type
+ "Return x's constructor."
+ [x]
+ (when-not (nil? x)
+ (.-constructor x)))
+
+(defn missing-protocol [proto obj]
+ (let [ty (type obj)
+ ty (if (and ty (.-cljs$lang$type ty))
+ (.-cljs$lang$ctorStr ty)
+ (goog/typeOf obj))]
+ (js/Error.
+ (.join (array "No protocol method " proto
+ " defined for type " ty ": " obj) ""))))
+
+(defn type->str [ty]
+ (if-let [s (.-cljs$lang$ctorStr ty)]
+ s
+ (str ty)))
+
+;; INTERNAL - do not use, only for Node.js
+(defn load-file [file]
+ (when-not js/COMPILED
+ (cljs.core/load-file* file)))
+
+(if (and (exists? js/Symbol)
+ (identical? (goog/typeOf js/Symbol) "function"))
+ (def ITER_SYMBOL (.-iterator js/Symbol))
+ (def ITER_SYMBOL "@@iterator"))
+
+(def ^{:jsdoc ["@enum {string}"]}
+ CHAR_MAP
+ #js {"-" "_"
+ ":" "_COLON_"
+ "+" "_PLUS_"
+ ">" "_GT_"
+ "<" "_LT_"
+ "=" "_EQ_"
+ "~" "_TILDE_"
+ "!" "_BANG_"
+ "@" "_CIRCA_"
+ "#" "_SHARP_"
+ "'" "_SINGLEQUOTE_"
+ "\\\"" "_DOUBLEQUOTE_"
+ "%" "_PERCENT_"
+ "^" "_CARET_"
+ "&" "_AMPERSAND_"
+ "*" "_STAR_"
+ "|" "_BAR_"
+ "{" "_LBRACE_"
+ "}" "_RBRACE_"
+ "[" "_LBRACK_"
+ "]" "_RBRACK_"
+ "/" "_SLASH_"
+ "\\\\" "_BSLASH_"
+ "?" "_QMARK_"})
+
+(def ^{:jsdoc ["@enum {string}"]}
+ DEMUNGE_MAP
+ #js {"_" "-"
+ "_COLON_" ":"
+ "_PLUS_" "+"
+ "_GT_" ">"
+ "_LT_" "<"
+ "_EQ_" "="
+ "_TILDE_" "~"
+ "_BANG_" "!"
+ "_CIRCA_" "@"
+ "_SHARP_" "#"
+ "_SINGLEQUOTE_" "'"
+ "_DOUBLEQUOTE_" "\\\""
+ "_PERCENT_" "%"
+ "_CARET_" "^"
+ "_AMPERSAND_" "&"
+ "_STAR_" "*"
+ "_BAR_" "|"
+ "_LBRACE_" "{"
+ "_RBRACE_" "}"
+ "_LBRACK_" "["
+ "_RBRACK_" "]"
+ "_SLASH_" "/"
+ "_BSLASH_" "\\\\"
+ "_QMARK_" "?"})
+
+(def DEMUNGE_PATTERN nil)
+
+(defn system-time
+ "Returns highest resolution time offered by host in milliseconds."
+ []
+ (cond
+ (and (exists? js/performance)
+ (not (nil? (. js/performance -now))))
+ (.now js/performance)
+
+ (and (exists? js/process)
+ (not (nil? (. js/process -hrtime))))
+ (let [t (.hrtime js/process)]
+ (/ (+ (* (aget t 0) 1e9) (aget t 1)) 1e6))
+
+ :else (.getTime (js/Date.))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; arrays ;;;;;;;;;;;;;;;;
+
+(declare apply)
+
+(defn ^array make-array
+ "Construct a JavaScript array of the specified dimensions. Accepts ignored
+ type argument for compatibility with Clojure. Note that there is no efficient
+ way to allocate multi-dimensional arrays in JavaScript; as such, this function
+ will run in polynomial time when called with 3 or more arguments."
+ ([size]
+ (js/Array. size))
+ ([type size]
+ (make-array size))
+ ([type size & more-sizes]
+ (let [dims more-sizes
+ dimarray (make-array size)]
+ (dotimes [i (alength dimarray)]
+ (aset dimarray i (apply make-array nil dims)))
+ dimarray)))
+
+(defn aclone
+ "Returns a javascript array, cloned from the passed in array"
+ [arr]
+ (let [len (alength arr)
+ new-arr (make-array len)]
+ (dotimes [i len]
+ (aset new-arr i (aget arr i)))
+ new-arr))
+
+(defn ^array array
+ "Creates a new javascript array.
+@param {...*} var_args" ;;array is a special case, don't emulate this doc string
+ [var-args] ;; [& items]
+ (let [a (js/Array. (alength (cljs.core/js-arguments)))]
+ (loop [i 0]
+ (if (< i (alength a))
+ (do
+ (aset a i (aget (cljs.core/js-arguments) i))
+ (recur (inc i)))
+ a))))
+
+(defn- maybe-warn
+ [e]
+ (when *print-err-fn*
+ (*print-err-fn* e)))
+
+(defn- checked-aget
+ ([array idx]
+ (when-assert
+ (try
+ (assert (or (array? array) (goog/isArrayLike array)))
+ (assert (number? idx))
+ (assert (not (neg? idx)))
+ (assert (< idx (alength array)))
+ (catch :default e
+ (maybe-warn e))))
+ (unchecked-get array idx))
+ ([array idx & idxs]
+ (apply checked-aget (checked-aget array idx) idxs)))
+
+(defn- checked-aset
+ ([array idx val]
+ (when-assert
+ (try
+ (assert (or (array? array) (goog/isArrayLike array)))
+ (assert (number? idx))
+ (assert (not (neg? idx)))
+ (assert (< idx (alength array)))
+ (catch :default e
+ (maybe-warn e))))
+ (unchecked-set array idx val))
+ ([array idx idx2 & idxv]
+ (apply checked-aset (checked-aget array idx) idx2 idxv)))
+
+(defn- checked-aget'
+ ([array idx]
+ {:pre [(or (array? array) (goog/isArrayLike array))
+ (number? idx) (not (neg? idx)) (< idx (alength array))]}
+ (unchecked-get array idx))
+ ([array idx & idxs]
+ (apply checked-aget' (checked-aget' array idx) idxs)))
+
+(defn- checked-aset'
+ ([array idx val]
+ {:pre [(or (array? array) (goog/isArrayLike array))
+ (number? idx) (not (neg? idx)) (< idx (alength array))]}
+ (unchecked-set array idx val))
+ ([array idx idx2 & idxv]
+ (apply checked-aset' (checked-aget' array idx) idx2 idxv)))
+
+(defn aget
+ "Returns the value at the index/indices. Works on JavaScript arrays."
+ ([array idx]
+ (cljs.core/aget array idx))
+ ([array idx & idxs]
+ (apply aget (aget array idx) idxs)))
+
+(defn aset
+ "Sets the value at the index/indices. Works on JavaScript arrays.
+ Returns val."
+ ([array idx val]
+ (cljs.core/aset array idx val))
+ ([array idx idx2 & idxv]
+ (apply aset (aget array idx) idx2 idxv)))
+
+(defn ^number alength
+ "Returns the length of the array. Works on arrays of all types."
+ [array]
+ (cljs.core/alength array))
+
+(declare reduce)
+
+(defn ^array into-array
+ "Returns an array with components set to the values in aseq. Optional type
+ argument accepted for compatibility with Clojure."
+ ([aseq]
+ (into-array nil aseq))
+ ([type aseq]
+ (reduce (fn [a x] (.push a x) a) (array) aseq)))
+
+(defn js-invoke
+ "Invoke JavaScript object method via string. Needed when the
+ string is not a valid unquoted property name."
+ [obj s & args]
+ (.apply (unchecked-get obj s) obj (into-array args)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;; core protocols ;;;;;;;;;;;;;
+
+(defprotocol Fn
+ "Marker protocol")
+
+(defprotocol IFn
+ "Protocol for adding the ability to invoke an object as a function.
+ For example, a vector can also be used to look up a value:
+ ([1 2 3 4] 1) => 2"
+ (-invoke
+ [this]
+ [this a]
+ [this a b]
+ [this a b c]
+ [this a b c d]
+ [this a b c d e]
+ [this a b c d e f]
+ [this a b c d e f g]
+ [this a b c d e f g h]
+ [this a b c d e f g h i]
+ [this a b c d e f g h i j]
+ [this a b c d e f g h i j k]
+ [this a b c d e f g h i j k l]
+ [this a b c d e f g h i j k l m]
+ [this a b c d e f g h i j k l m n]
+ [this a b c d e f g h i j k l m n o]
+ [this a b c d e f g h i j k l m n o p]
+ [this a b c d e f g h i j k l m n o p q]
+ [this a b c d e f g h i j k l m n o p q r]
+ [this a b c d e f g h i j k l m n o p q r s]
+ [this a b c d e f g h i j k l m n o p q r s t]
+ [this a b c d e f g h i j k l m n o p q r s t rest]))
+
+(defprotocol ICloneable
+ "Protocol for cloning a value."
+ (^clj -clone [value]
+ "Creates a clone of value."))
+
+(defprotocol ICounted
+ "Protocol for adding the ability to count a collection in constant time."
+ (^number -count [coll]
+ "Calculates the count of coll in constant time. Used by cljs.core/count."))
+
+(defprotocol IEmptyableCollection
+ "Protocol for creating an empty collection."
+ (-empty [coll]
+ "Returns an empty collection of the same category as coll. Used
+ by cljs.core/empty."))
+
+(defprotocol ICollection
+ "Protocol for adding to a collection."
+ (^clj -conj [coll o]
+ "Returns a new collection of coll with o added to it. The new item
+ should be added to the most efficient place, e.g.
+ (conj [1 2 3 4] 5) => [1 2 3 4 5]
+ (conj '(2 3 4 5) 1) => '(1 2 3 4 5)"))
+
+#_(defprotocol IOrdinal
+ (-index [coll]))
+
+(defprotocol IIndexed
+ "Protocol for collections to provide indexed-based access to their items."
+ (-nth [coll n] [coll n not-found]
+ "Returns the value at the index n in the collection coll.
+ Returns not-found if index n is out of bounds and not-found is supplied."))
+
+(defprotocol ASeq
+ "Marker protocol indicating an array sequence.")
+
+(defprotocol ISeq
+ "Protocol for collections to provide access to their items as sequences."
+ (-first [coll]
+ "Returns the first item in the collection coll. Used by cljs.core/first.")
+ (^clj -rest [coll]
+ "Returns a new collection of coll without the first item. It should
+ always return a seq, e.g.
+ (rest []) => ()
+ (rest nil) => ()"))
+
+(defprotocol INext
+ "Protocol for accessing the next items of a collection."
+ (^clj-or-nil -next [coll]
+ "Returns a new collection of coll without the first item. In contrast to
+ rest, it should return nil if there are no more items, e.g.
+ (next []) => nil
+ (next nil) => nil"))
+
+(defprotocol ILookup
+ "Protocol for looking up a value in a data structure."
+ (-lookup [o k] [o k not-found]
+ "Use k to look up a value in o. If not-found is supplied and k is not
+ a valid value that can be used for look up, not-found is returned."))
+
+(defprotocol IAssociative
+ "Protocol for adding associativity to collections."
+ (^boolean -contains-key? [coll k]
+ "Returns true if k is a key in coll.")
+ #_(-entry-at [coll k])
+ (^clj -assoc [coll k v]
+ "Returns a new collection of coll with a mapping from key k to
+ value v added to it."))
+
+(defprotocol IFind
+ "Protocol for implementing entry finding in collections."
+ (-find [coll k] "Returns the map entry for key, or nil if key not present."))
+
+(defprotocol IMap
+ "Protocol for adding mapping functionality to collections."
+ #_(-assoc-ex [coll k v])
+ (^clj -dissoc [coll k]
+ "Returns a new collection of coll without the mapping for key k."))
+
+(defprotocol IMapEntry
+ "Protocol for examining a map entry."
+ (-key [coll]
+ "Returns the key of the map entry.")
+ (-val [coll]
+ "Returns the value of the map entry."))
+
+(defprotocol ISet
+ "Protocol for adding set functionality to a collection."
+ (^clj -disjoin [coll v]
+ "Returns a new collection of coll that does not contain v."))
+
+(defprotocol IStack
+ "Protocol for collections to provide access to their items as stacks. The top
+ of the stack should be accessed in the most efficient way for the different
+ data structures."
+ (-peek [coll]
+ "Returns the item from the top of the stack. Is used by cljs.core/peek.")
+ (^clj -pop [coll]
+ "Returns a new stack without the item on top of the stack. Is used
+ by cljs.core/pop."))
+
+(defprotocol IVector
+ "Protocol for adding vector functionality to collections."
+ (^clj -assoc-n [coll n val]
+ "Returns a new vector with value val added at position n."))
+
+(defprotocol IDeref
+ "Protocol for adding dereference functionality to a reference."
+ (-deref [o]
+ "Returns the value of the reference o."))
+
+(defprotocol IDerefWithTimeout
+ (-deref-with-timeout [o msec timeout-val]))
+
+(defprotocol IMeta
+ "Protocol for accessing the metadata of an object."
+ (^clj-or-nil -meta [o]
+ "Returns the metadata of object o."))
+
+(defprotocol IWithMeta
+ "Protocol for adding metadata to an object."
+ (^clj -with-meta [o meta]
+ "Returns a new object with value of o and metadata meta added to it."))
+
+(defprotocol IReduce
+ "Protocol for seq types that can reduce themselves.
+ Called by cljs.core/reduce."
+ (-reduce [coll f] [coll f start]
+ "f should be a function of 2 arguments. If start is not supplied,
+ returns the result of applying f to the first 2 items in coll, then
+ applying f to that result and the 3rd item, etc."))
+
+(defprotocol IKVReduce
+ "Protocol for associative types that can reduce themselves
+ via a function of key and val. Called by cljs.core/reduce-kv."
+ (-kv-reduce [coll f init]
+ "Reduces an associative collection and returns the result. f should be
+ a function that takes three arguments."))
+
+(defprotocol IEquiv
+ "Protocol for adding value comparison functionality to a type."
+ (^boolean -equiv [o other]
+ "Returns true if o and other are equal, false otherwise."))
+
+(defprotocol IHash
+ "Protocol for adding hashing functionality to a type."
+ (-hash [o]
+ "Returns the hash code of o."))
+
+(defprotocol ISeqable
+ "Protocol for adding the ability to a type to be transformed into a sequence."
+ (^clj-or-nil -seq [o]
+ "Returns a seq of o, or nil if o is empty."))
+
+(defprotocol ISequential
+ "Marker interface indicating a persistent collection of sequential items")
+
+(defprotocol IList
+ "Marker interface indicating a persistent list")
+
+(defprotocol IRecord
+ "Marker interface indicating a record object")
+
+(defprotocol IReversible
+ "Protocol for reversing a seq."
+ (^clj -rseq [coll]
+ "Returns a seq of the items in coll in reversed order."))
+
+(defprotocol ISorted
+ "Protocol for a collection which can represent their items
+ in a sorted manner. "
+ (^clj -sorted-seq [coll ascending?]
+ "Returns a sorted seq from coll in either ascending or descending order.")
+ (^clj -sorted-seq-from [coll k ascending?]
+ "Returns a sorted seq from coll in either ascending or descending order.
+ If ascending is true, the result should contain all items which are > or >=
+ than k. If ascending is false, the result should contain all items which
+ are < or <= than k, e.g.
+ (-sorted-seq-from (sorted-set 1 2 3 4 5) 3 true) => (3 4 5)
+ (-sorted-seq-from (sorted-set 1 2 3 4 5) 3 false) => (3 2 1)")
+ (-entry-key [coll entry]
+ "Returns the key for entry.")
+ (-comparator [coll]
+ "Returns the comparator for coll."))
+
+(defprotocol IWriter
+ "Protocol for writing. Currently only implemented by StringBufferWriter."
+ (-write [writer s]
+ "Writes s with writer and returns the result.")
+ (-flush [writer]
+ "Flush writer."))
+
+(defprotocol IPrintWithWriter
+ "The old IPrintable protocol's implementation consisted of building a giant
+ list of strings to concatenate. This involved lots of concat calls,
+ intermediate vectors, and lazy-seqs, and was very slow in some older JS
+ engines. IPrintWithWriter implements printing via the IWriter protocol, so it
+ be implemented efficiently in terms of e.g. a StringBuffer append."
+ (-pr-writer [o writer opts]))
+
+(defprotocol IPending
+ "Protocol for types which can have a deferred realization. Currently only
+ implemented by Delay and LazySeq."
+ (^boolean -realized? [x]
+ "Returns true if a value for x has been produced, false otherwise."))
+
+(defprotocol IWatchable
+ "Protocol for types that can be watched. Currently only implemented by Atom."
+ (-notify-watches [this oldval newval]
+ "Calls all watchers with this, oldval and newval.")
+ (-add-watch [this key f]
+ "Adds a watcher function f to this. Keys must be unique per reference,
+ and can be used to remove the watch with -remove-watch.")
+ (-remove-watch [this key]
+ "Removes watcher that corresponds to key from this."))
+
+(defprotocol IEditableCollection
+ "Protocol for collections which can transformed to transients."
+ (^clj -as-transient [coll]
+ "Returns a new, transient version of the collection, in constant time."))
+
+(defprotocol ITransientCollection
+ "Protocol for adding basic functionality to transient collections."
+ (^clj -conj! [tcoll val]
+ "Adds value val to tcoll and returns tcoll.")
+ (^clj -persistent! [tcoll]
+ "Creates a persistent data structure from tcoll and returns it."))
+
+(defprotocol ITransientAssociative
+ "Protocol for adding associativity to transient collections."
+ (^clj -assoc! [tcoll key val]
+ "Returns a new transient collection of tcoll with a mapping from key to
+ val added to it."))
+
+(defprotocol ITransientMap
+ "Protocol for adding mapping functionality to transient collections."
+ (^clj -dissoc! [tcoll key]
+ "Returns a new transient collection of tcoll without the mapping for key."))
+
+(defprotocol ITransientVector
+ "Protocol for adding vector functionality to transient collections."
+ (^clj -assoc-n! [tcoll n val]
+ "Returns tcoll with value val added at position n.")
+ (^clj -pop! [tcoll]
+ "Returns tcoll with the last item removed from it."))
+
+(defprotocol ITransientSet
+ "Protocol for adding set functionality to a transient collection."
+ (^clj -disjoin! [tcoll v]
+ "Returns tcoll without v."))
+
+(defprotocol IComparable
+ "Protocol for values that can be compared."
+ (^number -compare [x y]
+ "Returns a negative number, zero, or a positive number when x is logically
+ 'less than', 'equal to', or 'greater than' y."))
+
+(defprotocol IChunk
+ "Protocol for accessing the items of a chunk."
+ (-drop-first [coll]
+ "Return a new chunk of coll with the first item removed."))
+
+(defprotocol IChunkedSeq
+ "Protocol for accessing a collection as sequential chunks."
+ (-chunked-first [coll]
+ "Returns the first chunk in coll.")
+ (-chunked-rest [coll]
+ "Return a new collection of coll with the first chunk removed."))
+
+(defprotocol IChunkedNext
+ "Protocol for accessing the chunks of a collection."
+ (-chunked-next [coll]
+ "Returns a new collection of coll without the first chunk."))
+
+(defprotocol INamed
+ "Protocol for adding a name."
+ (^string -name [x]
+ "Returns the name String of x.")
+ (^string -namespace [x]
+ "Returns the namespace String of x."))
+
+(defprotocol IAtom
+ "Marker protocol indicating an atom.")
+
+(defprotocol IReset
+ "Protocol for adding resetting functionality."
+ (-reset! [o new-value]
+ "Sets the value of o to new-value."))
+
+(defprotocol ISwap
+ "Protocol for adding swapping functionality."
+ (-swap! [o f] [o f a] [o f a b] [o f a b xs]
+ "Swaps the value of o to be (apply f current-value-of-atom args)."))
+
+(defprotocol IVolatile
+ "Protocol for adding volatile functionality."
+ (-vreset! [o new-value]
+ "Sets the value of volatile o to new-value without regard for the
+ current value. Returns new-value."))
+
+(defprotocol IIterable
+ "Protocol for iterating over a collection."
+ (-iterator [coll]
+ "Returns an iterator for coll."))
+
+;; Printing support
+
+(deftype StringBufferWriter [sb]
+ IWriter
+ (-write [_ s] (.append sb s))
+ (-flush [_] nil))
+
+(defn pr-str*
+ "Support so that collections can implement toString without
+ loading all the printing machinery."
+ [^not-native obj]
+ (let [sb (StringBuffer.)
+ writer (StringBufferWriter. sb)]
+ (-pr-writer obj writer (pr-opts))
+ (-flush writer)
+ (str sb)))
+
+;;;;;;;;;;;;;;;;;;; Murmur3 ;;;;;;;;;;;;;;;
+
+;;http://hg.openjdk.java.net/jdk7u/jdk7u6/jdk/file/8c2c5d63a17e/src/share/classes/java/lang/Integer.java
+(defn ^number int-rotate-left [x n]
+ (bit-or
+ (bit-shift-left x n)
+ (unsigned-bit-shift-right x (- n))))
+
+;; http://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
+(if (and (exists? Math/imul)
+ (not (zero? (Math/imul 0xffffffff 5))))
+ (defn ^number imul [a b] (Math/imul a b))
+ (defn ^number imul [a b]
+ (let [ah (bit-and (unsigned-bit-shift-right a 16) 0xffff)
+ al (bit-and a 0xffff)
+ bh (bit-and (unsigned-bit-shift-right b 16) 0xffff)
+ bl (bit-and b 0xffff)]
+ (bit-or
+ (+ (* al bl)
+ (unsigned-bit-shift-right
+ (bit-shift-left (+ (* ah bl) (* al bh)) 16) 0)) 0))))
+
+;; http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp
+(def m3-seed 0)
+(def m3-C1 (int 0xcc9e2d51))
+(def m3-C2 (int 0x1b873593))
+
+(defn ^number m3-mix-K1 [k1]
+ (-> (int k1) (imul m3-C1) (int-rotate-left 15) (imul m3-C2)))
+
+(defn ^number m3-mix-H1 [h1 k1]
+ (int (-> (int h1) (bit-xor (int k1)) (int-rotate-left 13) (imul 5) (+ (int 0xe6546b64)))))
+
+(defn ^number m3-fmix [h1 len]
+ (as-> (int h1) h1
+ (bit-xor h1 len)
+ (bit-xor h1 (unsigned-bit-shift-right h1 16))
+ (imul h1 (int 0x85ebca6b))
+ (bit-xor h1 (unsigned-bit-shift-right h1 13))
+ (imul h1 (int 0xc2b2ae35))
+ (bit-xor h1 (unsigned-bit-shift-right h1 16))))
+
+(defn ^number m3-hash-int [in]
+ (if (zero? in)
+ in
+ (let [k1 (m3-mix-K1 in)
+ h1 (m3-mix-H1 m3-seed k1)]
+ (m3-fmix h1 4))))
+
+(defn ^number m3-hash-unencoded-chars [in]
+ (let [h1 (loop [i 1 h1 m3-seed]
+ (if (< i (.-length in))
+ (recur (+ i 2)
+ (m3-mix-H1 h1
+ (m3-mix-K1
+ (bit-or (.charCodeAt in (dec i))
+ (bit-shift-left (.charCodeAt in i) 16)))))
+ h1))
+ h1 (if (== (bit-and (.-length in) 1) 1)
+ (bit-xor h1 (m3-mix-K1 (.charCodeAt in (dec (.-length in)))))
+ h1)]
+ (m3-fmix h1 (imul 2 (.-length in)))))
+
+;;;;;;;;;;;;;;;;;;; symbols ;;;;;;;;;;;;;;;
+
+(declare list Symbol = compare)
+
+;; Simple caching of string hashcode
+(def string-hash-cache (js-obj))
+(def string-hash-cache-count 0)
+
+;;http://hg.openjdk.java.net/jdk7u/jdk7u6/jdk/file/8c2c5d63a17e/src/share/classes/java/lang/String.java
+(defn hash-string* [s]
+ (if-not (nil? s)
+ (let [len (.-length s)]
+ (if (pos? len)
+ (loop [i 0 hash 0]
+ (if (< i len)
+ (recur (inc i) (+ (imul 31 hash) (.charCodeAt s i)))
+ hash))
+ 0))
+ 0))
+
+(defn add-to-string-hash-cache [k]
+ (let [h (hash-string* k)]
+ (gobject/set string-hash-cache k h)
+ (set! string-hash-cache-count (inc string-hash-cache-count))
+ h))
+
+(defn hash-string [k]
+ (when (> string-hash-cache-count 255)
+ (set! string-hash-cache (js-obj))
+ (set! string-hash-cache-count 0))
+ (if (nil? k)
+ 0
+ (let [h (unchecked-get string-hash-cache k)]
+ (if (number? h)
+ h
+ (add-to-string-hash-cache k)))))
+
+(defn hash
+ "Returns the hash code of its argument. Note this is the hash code
+ consistent with =."
+ [o]
+ (cond
+ (implements? IHash o)
+ (bit-xor (-hash ^not-native o) 0)
+
+ (number? o)
+ (if (js/isFinite o)
+ (js-mod (Math/floor o) 2147483647)
+ (case o
+ ##Inf
+ 2146435072
+ ##-Inf
+ -1048576
+ 2146959360))
+
+ ;; note: mirrors Clojure's behavior on the JVM, where the hashCode is
+ ;; 1231 for true and 1237 for false
+ ;; http://docs.oracle.com/javase/7/docs/api/java/lang/Boolean.html#hashCode%28%29
+ (true? o) 1231
+
+ (false? o) 1237
+
+ (string? o)
+ (m3-hash-int (hash-string o))
+
+ (instance? js/Date o)
+ (bit-xor (.valueOf o) 0)
+
+ (nil? o) 0
+
+ :else
+ (bit-xor (-hash o) 0)))
+
+(defn hash-combine [seed hash]
+ ; a la boost
+ (bit-xor seed
+ (+ hash 0x9e3779b9
+ (bit-shift-left seed 6)
+ (bit-shift-right seed 2))))
+
+(defn ^boolean instance?
+ "Evaluates x and tests if it is an instance of the type
+ c. Returns true or false"
+ [c x]
+ (cljs.core/instance? c x))
+
+(defn ^boolean symbol?
+ "Return true if x is a Symbol"
+ [x]
+ (instance? Symbol x))
+
+(defn- hash-symbol [sym]
+ (hash-combine
+ (m3-hash-unencoded-chars (.-name sym))
+ (hash-string (.-ns sym))))
+
+(defn- compare-symbols [a b]
+ (cond
+ (identical? (.-str a) (.-str b)) 0
+ (and (not (.-ns a)) (.-ns b)) -1
+ (.-ns a) (if-not (.-ns b)
+ 1
+ (let [nsc (garray/defaultCompare (.-ns a) (.-ns b))]
+ (if (== 0 nsc)
+ (garray/defaultCompare (.-name a) (.-name b))
+ nsc)))
+ :default (garray/defaultCompare (.-name a) (.-name b))))
+
+(declare get)
+
+(deftype Symbol [ns name str ^:mutable _hash _meta]
+ Object
+ (toString [_] str)
+ (equiv [this other] (-equiv this other))
+
+ IEquiv
+ (-equiv [_ other]
+ (if (instance? Symbol other)
+ (identical? str (.-str other))
+ false))
+
+ IFn
+ (-invoke [sym coll]
+ (get coll sym))
+ (-invoke [sym coll not-found]
+ (get coll sym not-found))
+
+ IMeta
+ (-meta [_] _meta)
+
+ IWithMeta
+ (-with-meta [_ new-meta] (Symbol. ns name str _hash new-meta))
+
+ IHash
+ (-hash [sym]
+ (caching-hash sym hash-symbol _hash))
+
+ INamed
+ (-name [_] name)
+ (-namespace [_] ns)
+
+ IPrintWithWriter
+ (-pr-writer [o writer _] (-write writer str)))
+
+(defn symbol
+ "Returns a Symbol with the given namespace and name."
+ ([name]
+ (if (symbol? name)
+ name
+ (let [idx (.indexOf name "/")]
+ (if (< idx 1)
+ (symbol nil name)
+ (symbol (.substring name 0 idx)
+ (.substring name (inc idx) (. name -length)))))))
+ ([ns name]
+ (let [sym-str (if-not (nil? ns)
+ (str ns "/" name)
+ name)]
+ (Symbol. ns name sym-str nil nil))))
+
+(deftype Var [val sym _meta]
+ Object
+ (isMacro [_]
+ (. (val) -cljs$lang$macro))
+ (toString [_]
+ (str "#'" sym))
+ IDeref
+ (-deref [_] (val))
+ IMeta
+ (-meta [_] _meta)
+ IWithMeta
+ (-with-meta [_ new-meta]
+ (Var. val sym new-meta))
+ IEquiv
+ (-equiv [this other]
+ (if (instance? Var other)
+ (= (.-sym this) (.-sym other))
+ false))
+ IHash
+ (-hash [_]
+ (hash-symbol sym))
+ Fn
+ IFn
+ (-invoke [_]
+ ((val)))
+ (-invoke [_ a]
+ ((val) a))
+ (-invoke [_ a b]
+ ((val) a b))
+ (-invoke [_ a b c]
+ ((val) a b c))
+ (-invoke [_ a b c d]
+ ((val) a b c d))
+ (-invoke [_ a b c d e]
+ ((val) a b c d e))
+ (-invoke [_ a b c d e f]
+ ((val) a b c d e f))
+ (-invoke [_ a b c d e f g]
+ ((val) a b c d e f g))
+ (-invoke [_ a b c d e f g h]
+ ((val) a b c d e f g h))
+ (-invoke [_ a b c d e f g h i]
+ ((val) a b c d e f g h i))
+ (-invoke [_ a b c d e f g h i j]
+ ((val) a b c d e f g h i j))
+ (-invoke [_ a b c d e f g h i j k]
+ ((val) a b c d e f g h i j k))
+ (-invoke [_ a b c d e f g h i j k l]
+ ((val) a b c d e f g h i j k l))
+ (-invoke [_ a b c d e f g h i j k l m]
+ ((val) a b c d e f g h i j k l m))
+ (-invoke [_ a b c d e f g h i j k l m n]
+ ((val) a b c d e f g h i j k l m n))
+ (-invoke [_ a b c d e f g h i j k l m n o]
+ ((val) a b c d e f g h i j k l m n o))
+ (-invoke [_ a b c d e f g h i j k l m n o p]
+ ((val) a b c d e f g h i j k l m n o p))
+ (-invoke [_ a b c d e f g h i j k l m n o p q]
+ ((val) a b c d e f g h i j k l m n o p q))
+ (-invoke [_ a b c d e f g h i j k l m n o p q r]
+ ((val) a b c d e f g h i j k l m n o p q r))
+ (-invoke [_ a b c d e f g h i j k l m n o p q r s]
+ ((val) a b c d e f g h i j k l m n o p q r s))
+ (-invoke [_ a b c d e f g h i j k l m n o p q r s t]
+ ((val) a b c d e f g h i j k l m n o p q r s t))
+ (-invoke [_ a b c d e f g h i j k l m n o p q r s t rest]
+ (apply (val) a b c d e f g h i j k l m n o p q r s t rest)))
+
+(defn ^boolean var?
+ "Returns true if v is of type cljs.core.Var"
+ [v]
+ (instance? cljs.core.Var v))
+
+;;;;;;;;;;;;;;;;;;; fundamentals ;;;;;;;;;;;;;;;
+
+(declare array-seq prim-seq IndexedSeq)
+
+(defn ^boolean iterable?
+ "Return true if x implements IIterable protocol."
+ [x]
+ (satisfies? IIterable x))
+
+(defn clone
+ "Clone the supplied value which must implement ICloneable."
+ [value]
+ (-clone value))
+
+(defn ^boolean cloneable?
+ "Return true if x implements ICloneable protocol."
+ [value]
+ (satisfies? ICloneable value))
+
+(defn ^seq seq
+ "Returns a seq on the collection. If the collection is
+ empty, returns nil. (seq nil) returns nil. seq also works on
+ Strings."
+ [coll]
+ (when-not (nil? coll)
+ (cond
+ (implements? ISeqable coll)
+ (-seq ^not-native coll)
+
+ (array? coll)
+ (when-not (zero? (alength coll))
+ (IndexedSeq. coll 0 nil))
+
+ (string? coll)
+ (when-not (zero? (.-length coll))
+ (IndexedSeq. coll 0 nil))
+
+ (native-satisfies? ISeqable coll)
+ (-seq coll)
+
+ :else (throw (js/Error. (str coll " is not ISeqable"))))))
+
+(defn first
+ "Returns the first item in the collection. Calls seq on its
+ argument. If coll is nil, returns nil."
+ [coll]
+ (when-not (nil? coll)
+ (if (implements? ISeq coll)
+ (-first ^not-native coll)
+ (let [s (seq coll)]
+ (when-not (nil? s)
+ (-first s))))))
+
+(defn ^seq rest
+ "Returns a possibly empty seq of the items after the first. Calls seq on its
+ argument."
+ [coll]
+ (if-not (nil? coll)
+ (if (implements? ISeq coll)
+ (-rest ^not-native coll)
+ (let [s (seq coll)]
+ (if s
+ (-rest ^not-native s)
+ ())))
+ ()))
+
+(defn ^seq next
+ "Returns a seq of the items after the first. Calls seq on its
+ argument. If there are no more items, returns nil"
+ [coll]
+ (when-not (nil? coll)
+ (if (implements? INext coll)
+ (-next ^not-native coll)
+ (seq (rest coll)))))
+
+(defn ^boolean =
+ "Equality. Returns true if x equals y, false if not. Compares
+ numbers and collections in a type-independent manner. Clojure's immutable data
+ structures define -equiv (and thus =) as a value, not an identity,
+ comparison."
+ ([x] true)
+ ([x y]
+ (if (nil? x)
+ (nil? y)
+ (or (identical? x y)
+ ^boolean (-equiv x y))))
+ ([x y & more]
+ (if (= x y)
+ (if (next more)
+ (recur y (first more) (next more))
+ (= y (first more)))
+ false)))
+
+;; EXPERIMENTAL: subject to change
+(deftype ES6Iterator [^:mutable s]
+ Object
+ (next [_]
+ (if-not (nil? s)
+ (let [x (first s)]
+ (set! s (next s))
+ #js {:value x :done false})
+ #js {:value nil :done true})))
+
+(defn es6-iterator
+ "EXPERIMENTAL: Return a ES2015 compatible iterator for coll."
+ [coll]
+ (ES6Iterator. (seq coll)))
+
+(declare es6-iterator-seq)
+
+(deftype ES6IteratorSeq [value iter ^:mutable _rest]
+ ISeqable
+ (-seq [this] this)
+ ISeq
+ (-first [_] value)
+ (-rest [_]
+ (when (nil? _rest)
+ (set! _rest (es6-iterator-seq iter)))
+ _rest))
+
+(defn es6-iterator-seq
+ "EXPERIMENTAL: Given an ES2015 compatible iterator return a seq."
+ [iter]
+ (let [v (.next iter)]
+ (if (.-done v)
+ ()
+ (ES6IteratorSeq. (.-value v) iter nil))))
+
+;;;;;;;;;;;;;;;;;;; Murmur3 Helpers ;;;;;;;;;;;;;;;;
+
+(defn ^number mix-collection-hash
+ "Mix final collection hash for ordered or unordered collections.
+ hash-basis is the combined collection hash, count is the number
+ of elements included in the basis. Note this is the hash code
+ consistent with =, different from .hashCode.
+ See http://clojure.org/data_structures#hash for full algorithms."
+ [hash-basis count]
+ (let [h1 m3-seed
+ k1 (m3-mix-K1 hash-basis)
+ h1 (m3-mix-H1 h1 k1)]
+ (m3-fmix h1 count)))
+
+(defn ^number hash-ordered-coll
+ "Returns the hash code, consistent with =, for an external ordered
+ collection implementing Iterable.
+ See http://clojure.org/data_structures#hash for full algorithms."
+ [coll]
+ (loop [n 0 hash-code 1 coll (seq coll)]
+ (if-not (nil? coll)
+ (recur (inc n) (bit-or (+ (imul 31 hash-code) (hash (first coll))) 0)
+ (next coll))
+ (mix-collection-hash hash-code n))))
+
+(def ^:private empty-ordered-hash
+ (mix-collection-hash 1 0))
+
+(defn ^number hash-unordered-coll
+ "Returns the hash code, consistent with =, for an external unordered
+ collection implementing Iterable. For maps, the iterator should
+ return map entries whose hash is computed as
+ (hash-ordered-coll [k v]).
+ See http://clojure.org/data_structures#hash for full algorithms."
+ [coll]
+ (loop [n 0 hash-code 0 coll (seq coll)]
+ (if-not (nil? coll)
+ (recur (inc n) (bit-or (+ hash-code (hash (first coll))) 0) (next coll))
+ (mix-collection-hash hash-code n))))
+
+(def ^:private empty-unordered-hash
+ (mix-collection-hash 0 0))
+
+;;;;;;;;;;;;;;;;;;; protocols on primitives ;;;;;;;;
+(declare hash-map list equiv-sequential)
+
+(extend-type nil
+ ICounted
+ (-count [_] 0))
+
+;; TODO: we should remove this and handle date equality checking
+;; by some other means, probably by adding a new primitive type
+;; case to the hash table lookup - David
+
+(extend-type js/Date
+ IEquiv
+ (-equiv [o other]
+ (and (instance? js/Date other)
+ (== (.valueOf o) (.valueOf other))))
+
+ IComparable
+ (-compare [this other]
+ (if (instance? js/Date other)
+ (garray/defaultCompare (.valueOf this) (.valueOf other))
+ (throw (js/Error. (str "Cannot compare " this " to " other))))))
+
+(defprotocol Inst
+ (inst-ms* [inst]))
+
+(extend-protocol Inst
+ js/Date
+ (inst-ms* [inst] (.getTime inst)))
+
+(defn inst-ms
+ "Return the number of milliseconds since January 1, 1970, 00:00:00 GMT"
+ [inst]
+ (inst-ms* inst))
+
+(defn ^boolean inst?
+ "Return true if x satisfies Inst"
+ [x]
+ (satisfies? Inst x))
+
+(extend-type number
+ IEquiv
+ (-equiv [x o] (identical? x o)))
+
+(declare with-meta)
+
+(extend-type function
+ Fn
+ IMeta
+ (-meta [_] nil))
+
+(extend-type default
+ IHash
+ (-hash [o]
+ (goog/getUid o)))
+
+;;this is primitive because & emits call to array-seq
+(defn inc
+ "Returns a number one greater than num."
+ [x] (cljs.core/+ x 1))
+
+(declare deref)
+
+(deftype Reduced [val]
+ IDeref
+ (-deref [o] val))
+
+(defn reduced
+ "Wraps x in a way such that a reduce will terminate with the value x"
+ [x]
+ (Reduced. x))
+
+(defn ^boolean reduced?
+ "Returns true if x is the result of a call to reduced"
+ [r]
+ (instance? Reduced r))
+
+(defn ensure-reduced
+ "If x is already reduced?, returns it, else returns (reduced x)"
+ [x]
+ (if (reduced? x) x (reduced x)))
+
+(defn unreduced
+ "If x is reduced?, returns (deref x), else returns x"
+ [x]
+ (if (reduced? x) (deref x) x))
+
+;; generic to all refs
+;; (but currently hard-coded to atom!)
+(defn deref
+ "Also reader macro: @var/@atom/@delay. Returns the
+ most-recently-committed value of ref. When applied to a var
+ or atom, returns its current state. When applied to a delay, forces
+ it if not already forced. See also - realized?."
+ [o]
+ (-deref o))
+
+(defn- ci-reduce
+ "Accepts any collection which satisfies the ICount and IIndexed protocols and
+reduces them without incurring seq initialization"
+ ([cicoll f]
+ (let [cnt (-count cicoll)]
+ (if (zero? cnt)
+ (f)
+ (loop [val (-nth cicoll 0), n 1]
+ (if (< n cnt)
+ (let [nval (f val (-nth cicoll n))]
+ (if (reduced? nval)
+ @nval
+ (recur nval (inc n))))
+ val)))))
+ ([cicoll f val]
+ (let [cnt (-count cicoll)]
+ (loop [val val, n 0]
+ (if (< n cnt)
+ (let [nval (f val (-nth cicoll n))]
+ (if (reduced? nval)
+ @nval
+ (recur nval (inc n))))
+ val))))
+ ([cicoll f val idx]
+ (let [cnt (-count cicoll)]
+ (loop [val val, n idx]
+ (if (< n cnt)
+ (let [nval (f val (-nth cicoll n))]
+ (if (reduced? nval)
+ @nval
+ (recur nval (inc n))))
+ val)))))
+
+(defn- array-reduce
+ ([arr f]
+ (let [cnt (alength arr)]
+ (if (zero? (alength arr))
+ (f)
+ (loop [val (aget arr 0), n 1]
+ (if (< n cnt)
+ (let [nval (f val (aget arr n))]
+ (if (reduced? nval)
+ @nval
+ (recur nval (inc n))))
+ val)))))
+ ([arr f val]
+ (let [cnt (alength arr)]
+ (loop [val val, n 0]
+ (if (< n cnt)
+ (let [nval (f val (aget arr n))]
+ (if (reduced? nval)
+ @nval
+ (recur nval (inc n))))
+ val))))
+ ([arr f val idx]
+ (let [cnt (alength arr)]
+ (loop [val val, n idx]
+ (if (< n cnt)
+ (let [nval (f val (aget arr n))]
+ (if (reduced? nval)
+ @nval
+ (recur nval (inc n))))
+ val)))))
+
+(declare hash-coll cons drop count nth RSeq List)
+
+(defn ^boolean counted?
+ "Returns true if coll implements count in constant time"
+ [x] (satisfies? ICounted x))
+
+(defn ^boolean indexed?
+ "Returns true if coll implements nth in constant time"
+ [x] (satisfies? IIndexed x))
+
+(defn- -indexOf
+ ([coll x]
+ (-indexOf coll x 0))
+ ([coll x start]
+ (let [len (count coll)]
+ (if (>= start len)
+ -1
+ (loop [idx (cond
+ (pos? start) start
+ (neg? start) (max 0 (+ start len))
+ :else start)]
+ (if (< idx len)
+ (if (= (nth coll idx) x)
+ idx
+ (recur (inc idx)))
+ -1))))))
+
+(defn- -lastIndexOf
+ ([coll x]
+ (-lastIndexOf coll x (count coll)))
+ ([coll x start]
+ (let [len (count coll)]
+ (if (zero? len)
+ -1
+ (loop [idx (cond
+ (pos? start) (min (dec len) start)
+ (neg? start) (+ len start)
+ :else start)]
+ (if (>= idx 0)
+ (if (= (nth coll idx) x)
+ idx
+ (recur (dec idx)))
+ -1))))))
+
+(deftype IndexedSeqIterator [arr ^:mutable i]
+ Object
+ (hasNext [_]
+ (< i (alength arr)))
+ (next [_]
+ (let [ret (aget arr i)]
+ (set! i (inc i))
+ ret)))
+
+(deftype IndexedSeq [arr i meta]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ ICloneable
+ (-clone [_] (IndexedSeq. arr i meta))
+
+ ISeqable
+ (-seq [this]
+ (when (< i (alength arr))
+ this))
+
+ IMeta
+ (-meta [coll] meta)
+ IWithMeta
+ (-with-meta [coll new-meta]
+ (IndexedSeq. arr i new-meta))
+
+ ASeq
+ ISeq
+ (-first [_] (aget arr i))
+ (-rest [_] (if (< (inc i) (alength arr))
+ (IndexedSeq. arr (inc i) nil)
+ (list)))
+
+ INext
+ (-next [_] (if (< (inc i) (alength arr))
+ (IndexedSeq. arr (inc i) nil)
+ nil))
+
+ ICounted
+ (-count [_]
+ (max 0 (- (alength arr) i)))
+
+ IIndexed
+ (-nth [coll n]
+ (let [i (+ n i)]
+ (if (and (<= 0 i) (< i (alength arr)))
+ (aget arr i)
+ (throw (js/Error. "Index out of bounds")))))
+ (-nth [coll n not-found]
+ (let [i (+ n i)]
+ (if (and (<= 0 i) (< i (alength arr)))
+ (aget arr i)
+ not-found)))
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IIterable
+ (-iterator [coll]
+ (IndexedSeqIterator. arr i))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (.-EMPTY List))
+
+ IReduce
+ (-reduce [coll f]
+ (array-reduce arr f (aget arr i) (inc i)))
+ (-reduce [coll f start]
+ (array-reduce arr f start i))
+
+ IHash
+ (-hash [coll] (hash-ordered-coll coll))
+
+ IReversible
+ (-rseq [coll]
+ (let [c (-count coll)]
+ (if (pos? c)
+ (RSeq. coll (dec c) nil)))))
+
+(es6-iterable IndexedSeq)
+
+(defn prim-seq
+ "Create seq from a primitive JavaScript Array-like."
+ ([prim]
+ (prim-seq prim 0))
+ ([prim i]
+ (when (< i (alength prim))
+ (IndexedSeq. prim i nil))))
+
+(defn array-seq
+ "Create a seq from a JavaScript array."
+ ([array]
+ (prim-seq array 0))
+ ([array i]
+ (prim-seq array i)))
+
+(declare with-meta seq-reduce)
+
+(deftype RSeq [ci i meta]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ ICloneable
+ (-clone [_] (RSeq. ci i meta))
+
+ IMeta
+ (-meta [coll] meta)
+ IWithMeta
+ (-with-meta [coll new-meta]
+ (RSeq. ci i new-meta))
+
+ ISeqable
+ (-seq [coll] coll)
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ ISeq
+ (-first [coll]
+ (-nth ci i))
+ (-rest [coll]
+ (if (pos? i)
+ (RSeq. ci (dec i) nil)
+ ()))
+
+ INext
+ (-next [coll]
+ (when (pos? i)
+ (RSeq. ci (dec i) nil)))
+
+ ICounted
+ (-count [coll] (inc i))
+
+ ICollection
+ (-conj [coll o]
+ (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ IHash
+ (-hash [coll] (hash-ordered-coll coll))
+
+ IReduce
+ (-reduce [col f] (seq-reduce f col))
+ (-reduce [col f start] (seq-reduce f start col)))
+
+(es6-iterable RSeq)
+
+(defn second
+ "Same as (first (next x))"
+ [coll]
+ (first (next coll)))
+
+(defn ffirst
+ "Same as (first (first x))"
+ [coll]
+ (first (first coll)))
+
+(defn nfirst
+ "Same as (next (first x))"
+ [coll]
+ (next (first coll)))
+
+(defn fnext
+ "Same as (first (next x))"
+ [coll]
+ (first (next coll)))
+
+(defn nnext
+ "Same as (next (next x))"
+ [coll]
+ (next (next coll)))
+
+(defn last
+ "Return the last item in coll, in linear time"
+ [s]
+ (let [sn (next s)]
+ (if-not (nil? sn)
+ (recur sn)
+ (first s))))
+
+(extend-type default
+ IEquiv
+ (-equiv [x o] (identical? x o)))
+
+(defn conj
+ "conj[oin]. Returns a new collection with the xs
+ 'added'. (conj nil item) returns (item). The 'addition' may
+ happen at different 'places' depending on the concrete type."
+ ([] [])
+ ([coll] coll)
+ ([coll x]
+ (if-not (nil? coll)
+ (-conj coll x)
+ (list x)))
+ ([coll x & xs]
+ (if xs
+ (recur (conj coll x) (first xs) (next xs))
+ (conj coll x))))
+
+(defn empty
+ "Returns an empty collection of the same category as coll, or nil"
+ [coll]
+ (when-not (nil? coll)
+ (-empty coll)))
+
+(defn- accumulating-seq-count [coll]
+ (loop [s (seq coll) acc 0]
+ (if (counted? s) ; assumes nil is counted, which it currently is
+ (+ acc (-count s))
+ (recur (next s) (inc acc)))))
+
+(defn count
+ "Returns the number of items in the collection. (count nil) returns
+ 0. Also works on strings, arrays, and Maps"
+ [coll]
+ (if-not (nil? coll)
+ (cond
+ (implements? ICounted coll)
+ (-count ^not-native coll)
+
+ (array? coll)
+ (alength coll)
+
+ (string? coll)
+ (.-length coll)
+
+ (implements? ISeqable coll)
+ (accumulating-seq-count coll)
+
+ :else (-count coll))
+ 0))
+
+(defn- linear-traversal-nth
+ ([coll n]
+ (cond
+ (nil? coll) (throw (js/Error. "Index out of bounds"))
+ (zero? n) (if (seq coll)
+ (first coll)
+ (throw (js/Error. "Index out of bounds")))
+ (indexed? coll) (-nth coll n)
+ (seq coll) (recur (next coll) (dec n))
+ :else (throw (js/Error. "Index out of bounds"))))
+ ([coll n not-found]
+ (cond
+ (nil? coll) not-found
+ (zero? n) (if (seq coll)
+ (first coll)
+ not-found)
+ (indexed? coll) (-nth coll n not-found)
+ (seq coll) (recur (next coll) (dec n) not-found)
+ :else not-found)))
+
+(defn nth
+ "Returns the value at the index. get returns nil if index out of
+ bounds, nth throws an exception unless not-found is supplied. nth
+ also works for strings, arrays, regex Matchers and Lists, and,
+ in O(n) time, for sequences."
+ ([coll n]
+ (cond
+ (not (number? n))
+ (throw (js/Error. "Index argument to nth must be a number"))
+
+ (nil? coll)
+ coll
+
+ (implements? IIndexed coll)
+ (-nth ^not-native coll n)
+
+ (array? coll)
+ (if (and (>= n 0) (< n (.-length coll)))
+ (aget coll n)
+ (throw (js/Error. "Index out of bounds")))
+
+ (string? coll)
+ (if (and (>= n 0) (< n (.-length coll)))
+ (.charAt coll n)
+ (throw (js/Error. "Index out of bounds")))
+
+ (or (implements? ISeq coll)
+ (implements? ISequential coll))
+ (if (neg? n)
+ (throw (js/Error. "Index out of bounds"))
+ (linear-traversal-nth coll n))
+
+ (native-satisfies? IIndexed coll)
+ (-nth coll n)
+
+ :else
+ (throw (js/Error. (str "nth not supported on this type "
+ (type->str (type coll)))))))
+ ([coll n not-found]
+ (cond
+ (not (number? n))
+ (throw (js/Error. "Index argument to nth must be a number."))
+
+ (nil? coll)
+ not-found
+
+ (implements? IIndexed coll)
+ (-nth ^not-native coll n not-found)
+
+ (array? coll)
+ (if (and (>= n 0) (< n (.-length coll)))
+ (aget coll n)
+ not-found)
+
+ (string? coll)
+ (if (and (>= n 0) (< n (.-length coll)))
+ (.charAt coll n)
+ not-found)
+
+ (or (implements? ISeq coll)
+ (implements? ISequential coll))
+ (if (neg? n)
+ not-found
+ (linear-traversal-nth coll n not-found))
+
+ (native-satisfies? IIndexed coll)
+ (-nth coll n not-found)
+
+ :else
+ (throw (js/Error. (str "nth not supported on this type "
+ (type->str (type coll))))))))
+
+(defn nthrest
+ "Returns the nth rest of coll, coll when n is 0."
+ [coll n]
+ (loop [n n xs coll]
+ (if-let [xs (and (pos? n) (seq xs))]
+ (recur (dec n) (rest xs))
+ xs)))
+
+(defn get
+ "Returns the value mapped to key, not-found or nil if key not present."
+ ([o k]
+ (when-not (nil? o)
+ (cond
+ (implements? ILookup o)
+ (-lookup ^not-native o k)
+
+ (array? o)
+ (when (and (some? k) (< k (.-length o)))
+ (aget o (int k)))
+
+ (string? o)
+ (when (and (some? k) (< k (.-length o)))
+ (.charAt o (int k)))
+
+ (native-satisfies? ILookup o)
+ (-lookup o k)
+
+ :else nil)))
+ ([o k not-found]
+ (if-not (nil? o)
+ (cond
+ (implements? ILookup o)
+ (-lookup ^not-native o k not-found)
+
+ (array? o)
+ (if (and (some? k) (>= k 0) (< k (.-length o)))
+ (aget o (int k))
+ not-found)
+
+ (string? o)
+ (if (and (some? k) (>= k 0) (< k (.-length o)))
+ (.charAt o (int k))
+ not-found)
+
+ (native-satisfies? ILookup o)
+ (-lookup o k not-found)
+
+ :else not-found)
+ not-found)))
+
+(declare PersistentHashMap PersistentArrayMap MapEntry)
+
+(defn assoc
+ "assoc[iate]. When applied to a map, returns a new map of the
+ same (hashed/sorted) type, that contains the mapping of key(s) to
+ val(s). When applied to a vector, returns a new vector that
+ contains val at index."
+ ([coll k v]
+ (if-not (nil? coll)
+ (-assoc coll k v)
+ (array-map k v)))
+ ([coll k v & kvs]
+ (let [ret (assoc coll k v)]
+ (if kvs
+ (recur ret (first kvs) (second kvs) (nnext kvs))
+ ret))))
+
+(defn dissoc
+ "dissoc[iate]. Returns a new map of the same (hashed/sorted) type,
+ that does not contain a mapping for key(s)."
+ ([coll] coll)
+ ([coll k]
+ (when-not (nil? coll)
+ (-dissoc coll k)))
+ ([coll k & ks]
+ (when-not (nil? coll)
+ (let [ret (dissoc coll k)]
+ (if ks
+ (recur ret (first ks) (next ks))
+ ret)))))
+
+(defn ^boolean fn?
+ "Return true if f is a JavaScript function or satisfies the Fn protocol."
+ [f]
+ (or ^boolean (goog/isFunction f) (satisfies? Fn f)))
+
+(deftype MetaFn [afn meta]
+ IMeta
+ (-meta [_] meta)
+ IWithMeta
+ (-with-meta [_ new-meta]
+ (MetaFn. afn new-meta))
+ Fn
+ IFn
+ (-invoke [_]
+ (afn))
+ (-invoke [_ a]
+ (afn a))
+ (-invoke [_ a b]
+ (afn a b))
+ (-invoke [_ a b c]
+ (afn a b c))
+ (-invoke [_ a b c d]
+ (afn a b c d))
+ (-invoke [_ a b c d e]
+ (afn a b c d e))
+ (-invoke [_ a b c d e f]
+ (afn a b c d e f))
+ (-invoke [_ a b c d e f g]
+ (afn a b c d e f g))
+ (-invoke [_ a b c d e f g h]
+ (afn a b c d e f g h))
+ (-invoke [_ a b c d e f g h i]
+ (afn a b c d e f g h i))
+ (-invoke [_ a b c d e f g h i j]
+ (afn a b c d e f g h i j))
+ (-invoke [_ a b c d e f g h i j k]
+ (afn a b c d e f g h i j k))
+ (-invoke [_ a b c d e f g h i j k l]
+ (afn a b c d e f g h i j k l))
+ (-invoke [_ a b c d e f g h i j k l m]
+ (afn a b c d e f g h i j k l m))
+ (-invoke [_ a b c d e f g h i j k l m n]
+ (afn a b c d e f g h i j k l m n))
+ (-invoke [_ a b c d e f g h i j k l m n o]
+ (afn a b c d e f g h i j k l m n o))
+ (-invoke [_ a b c d e f g h i j k l m n o p]
+ (afn a b c d e f g h i j k l m n o p))
+ (-invoke [_ a b c d e f g h i j k l m n o p q]
+ (afn a b c d e f g h i j k l m n o p q))
+ (-invoke [_ a b c d e f g h i j k l m n o p q r]
+ (afn a b c d e f g h i j k l m n o p q r))
+ (-invoke [_ a b c d e f g h i j k l m n o p q r s]
+ (afn a b c d e f g h i j k l m n o p q r s))
+ (-invoke [_ a b c d e f g h i j k l m n o p q r s t]
+ (afn a b c d e f g h i j k l m n o p q r s t))
+ (-invoke [_ a b c d e f g h i j k l m n o p q r s t rest]
+ (apply afn a b c d e f g h i j k l m n o p q r s t rest)))
+
+(defn with-meta
+ "Returns an object of the same type and value as obj, with
+ map m as its metadata."
+ [o meta]
+ (if ^boolean (goog/isFunction o)
+ (MetaFn. o meta)
+ (when-not (nil? o)
+ (-with-meta o meta))))
+
+(defn meta
+ "Returns the metadata of obj, returns nil if there is no metadata."
+ [o]
+ (when (and (not (nil? o))
+ (satisfies? IMeta o))
+ (-meta o)))
+
+(defn peek
+ "For a list or queue, same as first, for a vector, same as, but much
+ more efficient than, last. If the collection is empty, returns nil."
+ [coll]
+ (when-not (nil? coll)
+ (-peek coll)))
+
+(defn pop
+ "For a list or queue, returns a new list/queue without the first
+ item, for a vector, returns a new vector without the last item.
+ Note - not the same as next/butlast."
+ [coll]
+ (when-not (nil? coll)
+ (-pop coll)))
+
+(defn disj
+ "disj[oin]. Returns a new set of the same (hashed/sorted) type, that
+ does not contain key(s)."
+ ([coll] coll)
+ ([coll k]
+ (when-not (nil? coll)
+ (-disjoin coll k)))
+ ([coll k & ks]
+ (when-not (nil? coll)
+ (let [ret (disj coll k)]
+ (if ks
+ (recur ret (first ks) (next ks))
+ ret)))))
+
+(defn ^boolean empty?
+ "Returns true if coll has no items - same as (not (seq coll)).
+ Please use the idiom (seq x) rather than (not (empty? x))"
+ [coll] (or (nil? coll)
+ (not (seq coll))))
+
+(defn ^boolean coll?
+ "Returns true if x satisfies ICollection"
+ [x]
+ (if (nil? x)
+ false
+ (satisfies? ICollection x)))
+
+(defn ^boolean set?
+ "Returns true if x satisfies ISet"
+ [x]
+ (if (nil? x)
+ false
+ (satisfies? ISet x)))
+
+(defn ^boolean associative?
+ "Returns true if coll implements IAssociative"
+ [x] (satisfies? IAssociative x))
+
+(defn ^boolean ifind?
+ "Returns true if coll implements IFind"
+ [x] (satisfies? IFind x))
+
+(defn ^boolean sequential?
+ "Returns true if coll satisfies ISequential"
+ [x] (satisfies? ISequential x))
+
+(defn ^boolean sorted?
+ "Returns true if coll satisfies ISorted"
+ [x] (satisfies? ISorted x))
+
+(defn ^boolean reduceable?
+ "Returns true if coll satisfies IReduce"
+ [x] (satisfies? IReduce x))
+
+(defn ^boolean map?
+ "Return true if x satisfies IMap"
+ [x]
+ (if (nil? x)
+ false
+ (satisfies? IMap x)))
+
+(defn ^boolean record?
+ "Return true if x satisfies IRecord"
+ [x]
+ (satisfies? IRecord x))
+
+(defn ^boolean vector?
+ "Return true if x satisfies IVector"
+ [x] (satisfies? IVector x))
+
+(declare ChunkedCons ChunkedSeq)
+
+(defn ^boolean chunked-seq?
+ "Return true if x is satisfies IChunkedSeq."
+ [x] (implements? IChunkedSeq x))
+
+;;;;;;;;;;;;;;;;;;;; js primitives ;;;;;;;;;;;;
+(defn js-obj
+ "Create JavaSript object from an even number arguments representing
+ interleaved keys and values."
+ ([]
+ (cljs.core/js-obj))
+ ([& keyvals]
+ (apply gobject/create keyvals)))
+
+(defn js-keys
+ "Return the JavaScript keys for an object."
+ [obj]
+ (gobject/getKeys obj))
+
+(defn js-delete
+ "Delete a property from a JavaScript object.
+ Returns true upon success, false otherwise."
+ [obj key]
+ (cljs.core/js-delete obj key))
+
+(defn- array-copy
+ ([from i to j len]
+ (loop [i i j j len len]
+ (if (zero? len)
+ to
+ (do (aset to j (aget from i))
+ (recur (inc i) (inc j) (dec len)))))))
+
+(defn- array-copy-downward
+ ([from i to j len]
+ (loop [i (+ i (dec len)) j (+ j (dec len)) len len]
+ (if (zero? len)
+ to
+ (do (aset to j (aget from i))
+ (recur (dec i) (dec j) (dec len)))))))
+
+;;;;;;;;;;;;;;;; preds ;;;;;;;;;;;;;;;;;;
+
+(def ^:private lookup-sentinel (js-obj))
+
+(defn ^boolean false?
+ "Returns true if x is the value false, false otherwise."
+ [x] (cljs.core/false? x))
+
+(defn ^boolean true?
+ "Returns true if x is the value true, false otherwise."
+ [x] (cljs.core/true? x))
+
+(defn ^boolean boolean?
+ "Return true if x is a Boolean"
+ [x] (or (cljs.core/true? x) (cljs.core/false? x)))
+
+(defn ^boolean undefined?
+ "Returns true if x identical to the JavaScript undefined value."
+ [x]
+ (cljs.core/undefined? x))
+
+(defn ^boolean seq?
+ "Return true if s satisfies ISeq"
+ [s]
+ (if (nil? s)
+ false
+ (satisfies? ISeq s)))
+
+(defn ^boolean seqable?
+ "Return true if the seq function is supported for s"
+ [s]
+ (or
+ (nil? s)
+ (satisfies? ISeqable s)
+ (array? s)
+ (string? s)))
+
+(defn ^boolean boolean
+ "Coerce to boolean"
+ [x]
+ (cond
+ (nil? x) false
+ (false? x) false
+ :else true))
+
+(defn ^boolean ifn?
+ "Returns true if f returns true for fn? or satisfies IFn."
+ [f]
+ (or (fn? f) (satisfies? IFn f)))
+
+(defn ^boolean integer?
+ "Returns true if n is a JavaScript number with no decimal part."
+ [n]
+ (and (number? n)
+ (not ^boolean (js/isNaN n))
+ (not (identical? n js/Infinity))
+ (== (js/parseFloat n) (js/parseInt n 10))))
+
+(defn ^boolean int?
+ "Return true if x satisfies integer? or is an instance of goog.math.Integer
+ or goog.math.Long."
+ [x]
+ (or (integer? x)
+ (instance? goog.math.Integer x)
+ (instance? goog.math.Long x)))
+
+(defn ^boolean pos-int?
+ "Return true if x satisfies int? and is positive."
+ [x]
+ (cond
+ (integer? x) (pos? x)
+
+ (instance? goog.math.Integer x)
+ (and (not (.isNegative x))
+ (not (.isZero x)))
+
+ (instance? goog.math.Long x)
+ (and (not (.isNegative x))
+ (not (.isZero x)))
+
+ :else false))
+
+(defn ^boolean neg-int?
+ "Return true if x satisfies int? and is negative."
+ [x]
+ (cond
+ (integer? x) (neg? x)
+
+ (instance? goog.math.Integer x)
+ (.isNegative x)
+
+ (instance? goog.math.Long x)
+ (.isNegative x)
+
+ :else false))
+
+(defn ^boolean nat-int?
+ "Return true if x satisfies int? and is a natural integer value."
+ [x]
+ (cond
+ (integer? x)
+ (not (neg? x))
+
+ (instance? goog.math.Integer x)
+ (not (.isNegative x))
+
+ (instance? goog.math.Long x)
+ (not (.isNegative x))
+
+ :else false))
+
+(defn ^boolean float?
+ "Returns true for JavaScript numbers, false otherwise."
+ [x]
+ (number? x))
+
+(defn ^boolean double?
+ "Returns true for JavaScript numbers, false otherwise."
+ [x]
+ (number? x))
+
+(defn ^boolean infinite?
+ "Returns true for Infinity and -Infinity values."
+ [x]
+ (or (identical? x js/Number.POSITIVE_INFINITY)
+ (identical? x js/Number.NEGATIVE_INFINITY)))
+
+(defn ^boolean contains?
+ "Returns true if key is present in the given collection, otherwise
+ returns false. Note that for numerically indexed collections like
+ vectors and arrays, this tests if the numeric key is within the
+ range of indexes. 'contains?' operates constant or logarithmic time;
+ it will not perform a linear search for a value. See also 'some'."
+ [coll v]
+ (if (identical? (get coll v lookup-sentinel) lookup-sentinel)
+ false
+ true))
+
+(defn find
+ "Returns the map entry for key, or nil if key not present."
+ [coll k]
+ (if (ifind? coll)
+ (-find coll k)
+ (when (and (not (nil? coll))
+ (associative? coll)
+ (contains? coll k))
+ (MapEntry. k (get coll k) nil))))
+
+(defn ^boolean distinct?
+ "Returns true if no two of the arguments are ="
+ ([x] true)
+ ([x y] (not (= x y)))
+ ([x y & more]
+ (if (not (= x y))
+ (loop [s #{x y} xs more]
+ (let [x (first xs)
+ etc (next xs)]
+ (if xs
+ (if (contains? s x)
+ false
+ (recur (conj s x) etc))
+ true)))
+ false)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Seq fns ;;;;;;;;;;;;;;;;
+
+(defn ^number compare
+ "Comparator. Returns a negative number, zero, or a positive number
+ when x is logically 'less than', 'equal to', or 'greater than'
+ y. Uses IComparable if available and google.array.defaultCompare for objects
+ of the same type and special-cases nil to be less than any other object."
+ [x y]
+ (cond
+ (identical? x y) 0
+
+ (nil? x) -1
+
+ (nil? y) 1
+
+ (number? x) (if (number? y)
+ (garray/defaultCompare x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y))))
+
+ (satisfies? IComparable x)
+ (-compare x y)
+
+ :else
+ (if (and (or (string? x) (array? x) (true? x) (false? x))
+ (identical? (type x) (type y)))
+ (garray/defaultCompare x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y))))))
+
+(defn ^:private compare-indexed
+ "Compare indexed collection."
+ ([xs ys]
+ (let [xl (count xs)
+ yl (count ys)]
+ (cond
+ (< xl yl) -1
+ (> xl yl) 1
+ (== xl 0) 0
+ :else (compare-indexed xs ys xl 0))))
+ ([xs ys len n]
+ (let [d (compare (nth xs n) (nth ys n))]
+ (if (and (zero? d) (< (+ n 1) len))
+ (recur xs ys len (inc n))
+ d))))
+
+(defn ^:private fn->comparator
+ "Given a fn that might be boolean valued or a comparator,
+ return a fn that is a comparator."
+ [f]
+ (if (= f compare)
+ compare
+ (fn [x y]
+ (let [r (f x y)]
+ (if (number? r)
+ r
+ (if r
+ -1
+ (if (f y x) 1 0)))))))
+
+(declare to-array)
+
+(defn sort
+ "Returns a sorted sequence of the items in coll. Comp can be
+ boolean-valued comparison function, or a -/0/+ valued comparator.
+ Comp defaults to compare."
+ ([coll]
+ (sort compare coll))
+ ([comp coll]
+ (if (seq coll)
+ (let [a (to-array coll)]
+ ;; matching Clojure's stable sort, though docs don't promise it
+ (garray/stableSort a (fn->comparator comp))
+ (seq a))
+ ())))
+
+(defn sort-by
+ "Returns a sorted sequence of the items in coll, where the sort
+ order is determined by comparing (keyfn item). Comp can be
+ boolean-valued comparison function, or a -/0/+ valued comparator.
+ Comp defaults to compare."
+ ([keyfn coll]
+ (sort-by keyfn compare coll))
+ ([keyfn comp coll]
+ (sort (fn [x y] ((fn->comparator comp) (keyfn x) (keyfn y))) coll)))
+
+; simple reduce based on seqs, used as default
+(defn- seq-reduce
+ ([f coll]
+ (if-let [s (seq coll)]
+ (reduce f (first s) (next s))
+ (f)))
+ ([f val coll]
+ (loop [val val, coll (seq coll)]
+ (if coll
+ (let [nval (f val (first coll))]
+ (if (reduced? nval)
+ @nval
+ (recur nval (next coll))))
+ val))))
+
+(declare vec)
+
+(defn shuffle
+ "Return a random permutation of coll"
+ [coll]
+ (let [a (to-array coll)]
+ (garray/shuffle a)
+ (vec a)))
+
+(defn- iter-reduce
+ ([coll f]
+ (let [iter (-iterator coll)]
+ (if (.hasNext iter)
+ (let [init (.next iter)]
+ (loop [acc init]
+ (if ^boolean (.hasNext iter)
+ (let [nacc (f acc (.next iter))]
+ (if (reduced? nacc)
+ @nacc
+ (recur nacc)))
+ acc)))
+ (f))))
+ ([coll f init]
+ (let [iter (-iterator coll)]
+ (loop [acc init]
+ (if ^boolean (.hasNext iter)
+ (let [nacc (f acc (.next iter))]
+ (if (reduced? nacc)
+ @nacc
+ (recur nacc)))
+ acc)))))
+
+(defn reduce
+ "f should be a function of 2 arguments. If val is not supplied,
+ returns the result of applying f to the first 2 items in coll, then
+ applying f to that result and the 3rd item, etc. If coll contains no
+ items, f must accept no arguments as well, and reduce returns the
+ result of calling f with no arguments. If coll has only 1 item, it
+ is returned and f is not called. If val is supplied, returns the
+ result of applying f to val and the first item in coll, then
+ applying f to that result and the 2nd item, etc. If coll contains no
+ items, returns val and f is not called."
+ ([f coll]
+ (cond
+ (implements? IReduce coll)
+ (-reduce ^not-native coll f)
+
+ (array? coll)
+ (array-reduce coll f)
+
+ (string? coll)
+ (array-reduce coll f)
+
+ (native-satisfies? IReduce coll)
+ (-reduce coll f)
+
+ (iterable? coll)
+ (iter-reduce coll f)
+
+ :else
+ (seq-reduce f coll)))
+ ([f val coll]
+ (cond
+ (implements? IReduce coll)
+ (-reduce ^not-native coll f val)
+
+ (array? coll)
+ (array-reduce coll f val)
+
+ (string? coll)
+ (array-reduce coll f val)
+
+ (native-satisfies? IReduce coll)
+ (-reduce coll f val)
+
+ (iterable? coll)
+ (iter-reduce coll f val)
+
+ :else
+ (seq-reduce f val coll))))
+
+(defn reduce-kv
+ "Reduces an associative collection. f should be a function of 3
+ arguments. Returns the result of applying f to init, the first key
+ and the first value in coll, then applying f to that result and the
+ 2nd key and value, etc. If coll contains no entries, returns init
+ and f is not called. Note that reduce-kv is supported on vectors,
+ where the keys will be the ordinals."
+ ([f init coll]
+ (if-not (nil? coll)
+ (-kv-reduce coll f init)
+ init)))
+
+(defn identity
+ "Returns its argument."
+ [x] x)
+
+(defn completing
+ "Takes a reducing function f of 2 args and returns a fn suitable for
+ transduce by adding an arity-1 signature that calls cf (default -
+ identity) on the result argument."
+ ([f] (completing f identity))
+ ([f cf]
+ (fn
+ ([] (f))
+ ([x] (cf x))
+ ([x y] (f x y)))))
+
+(defn transduce
+ "reduce with a transformation of f (xf). If init is not
+ supplied, (f) will be called to produce it. f should be a reducing
+ step function that accepts both 1 and 2 arguments, if it accepts
+ only 2 you can add the arity-1 with 'completing'. Returns the result
+ of applying (the transformed) xf to init and the first item in coll,
+ then applying xf to that result and the 2nd item, etc. If coll
+ contains no items, returns init and f is not called. Note that
+ certain transforms may inject or skip items."
+ ([xform f coll] (transduce xform f (f) coll))
+ ([xform f init coll]
+ (let [f (xform f)
+ ret (reduce f init coll)]
+ (f ret))))
+
+;;; Math - variadic forms will not work until the following implemented:
+;;; first, next, reduce
+
+(defn ^number +
+ "Returns the sum of nums. (+) returns 0."
+ ([] 0)
+ ([x] x)
+ ([x y] (cljs.core/+ x y))
+ ([x y & more]
+ (reduce + (cljs.core/+ x y) more)))
+
+(defn ^number -
+ "If no ys are supplied, returns the negation of x, else subtracts
+ the ys from x and returns the result."
+ ([x] (cljs.core/- x))
+ ([x y] (cljs.core/- x y))
+ ([x y & more] (reduce - (cljs.core/- x y) more)))
+
+(defn ^number *
+ "Returns the product of nums. (*) returns 1."
+ ([] 1)
+ ([x] x)
+ ([x y] (cljs.core/* x y))
+ ([x y & more] (reduce * (cljs.core/* x y) more)))
+
+(declare divide)
+
+(defn ^number /
+ "If no denominators are supplied, returns 1/numerator,
+ else returns numerator divided by all of the denominators."
+ ([x] (/ 1 x))
+ ([x y] (cljs.core/divide x y)) ;; FIXME: waiting on cljs.core//
+ ([x y & more] (reduce / (/ x y) more)))
+
+(defn ^boolean <
+ "Returns non-nil if nums are in monotonically increasing order,
+ otherwise false."
+ ([x] true)
+ ([x y] (cljs.core/< x y))
+ ([x y & more]
+ (if (cljs.core/< x y)
+ (if (next more)
+ (recur y (first more) (next more))
+ (cljs.core/< y (first more)))
+ false)))
+
+(defn ^boolean <=
+ "Returns non-nil if nums are in monotonically non-decreasing order,
+ otherwise false."
+ ([x] true)
+ ([x y] (cljs.core/<= x y))
+ ([x y & more]
+ (if (cljs.core/<= x y)
+ (if (next more)
+ (recur y (first more) (next more))
+ (cljs.core/<= y (first more)))
+ false)))
+
+(defn ^boolean >
+ "Returns non-nil if nums are in monotonically decreasing order,
+ otherwise false."
+ ([x] true)
+ ([x y] (cljs.core/> x y))
+ ([x y & more]
+ (if (cljs.core/> x y)
+ (if (next more)
+ (recur y (first more) (next more))
+ (cljs.core/> y (first more)))
+ false)))
+
+(defn ^boolean >=
+ "Returns non-nil if nums are in monotonically non-increasing order,
+ otherwise false."
+ ([x] true)
+ ([x y] (cljs.core/>= x y))
+ ([x y & more]
+ (if (cljs.core/>= x y)
+ (if (next more)
+ (recur y (first more) (next more))
+ (cljs.core/>= y (first more)))
+ false)))
+
+(defn dec
+ "Returns a number one less than num."
+ [x] (- x 1))
+
+(defn ^number max
+ "Returns the greatest of the nums."
+ ([x] x)
+ ([x y] (cljs.core/max x y))
+ ([x y & more]
+ (reduce max (cljs.core/max x y) more)))
+
+(defn ^number min
+ "Returns the least of the nums."
+ ([x] x)
+ ([x y] (cljs.core/min x y))
+ ([x y & more]
+ (reduce min (cljs.core/min x y) more)))
+
+(defn ^number byte [x] x)
+
+(defn char
+ "Coerce to char"
+ [x]
+ (cond
+ (number? x) (.fromCharCode js/String x)
+ (and (string? x) (== (.-length x) 1)) x
+ :else (throw (js/Error. "Argument to char must be a character or number"))))
+
+(defn ^number short [x] x)
+(defn ^number float [x] x)
+(defn ^number double [x] x)
+
+(defn ^number unchecked-byte [x] x)
+(defn ^number unchecked-char [x] x)
+(defn ^number unchecked-short [x] x)
+(defn ^number unchecked-float [x] x)
+(defn ^number unchecked-double [x] x)
+
+(defn ^number unchecked-add
+ "Returns the sum of nums. (+) returns 0."
+ ([] 0)
+ ([x] x)
+ ([x y] (cljs.core/unchecked-add x y))
+ ([x y & more] (reduce unchecked-add (cljs.core/unchecked-add x y) more)))
+
+(defn ^number unchecked-add-int
+ "Returns the sum of nums. (+) returns 0."
+ ([] 0)
+ ([x] x)
+ ([x y] (cljs.core/unchecked-add-int x y))
+ ([x y & more] (reduce unchecked-add-int (cljs.core/unchecked-add-int x y) more)))
+
+(defn unchecked-dec
+ "Returns a number one less than x, an int."
+ [x]
+ (cljs.core/unchecked-dec x))
+
+(defn unchecked-dec-int
+ "Returns a number one less than x, an int."
+ [x]
+ (cljs.core/unchecked-dec-int x))
+
+(defn ^number unchecked-divide-int
+ "If no denominators are supplied, returns 1/numerator,
+ else returns numerator divided by all of the denominators."
+ ([x] (unchecked-divide-int 1 x))
+ ([x y] (cljs.core/divide x y)) ;; FIXME: waiting on cljs.core//
+ ([x y & more] (reduce unchecked-divide-int (unchecked-divide-int x y) more)))
+
+(defn unchecked-inc [x]
+ (cljs.core/unchecked-inc x))
+
+(defn unchecked-inc-int [x]
+ (cljs.core/unchecked-inc-int x))
+
+(defn ^number unchecked-multiply
+ "Returns the product of nums. (*) returns 1."
+ ([] 1)
+ ([x] x)
+ ([x y] (cljs.core/unchecked-multiply x y))
+ ([x y & more] (reduce unchecked-multiply (cljs.core/unchecked-multiply x y) more)))
+
+(defn ^number unchecked-multiply-int
+ "Returns the product of nums. (*) returns 1."
+ ([] 1)
+ ([x] x)
+ ([x y] (cljs.core/unchecked-multiply-int x y))
+ ([x y & more] (reduce unchecked-multiply-int (cljs.core/unchecked-multiply-int x y) more)))
+
+(defn unchecked-negate [x]
+ (cljs.core/unchecked-negate x))
+
+(defn unchecked-negate-int [x]
+ (cljs.core/unchecked-negate-int x))
+
+(declare mod)
+
+(defn unchecked-remainder-int [x n]
+ (cljs.core/unchecked-remainder-int x n))
+
+(defn ^number unchecked-subtract
+ "If no ys are supplied, returns the negation of x, else subtracts
+ the ys from x and returns the result."
+ ([x] (cljs.core/unchecked-subtract x))
+ ([x y] (cljs.core/unchecked-subtract x y))
+ ([x y & more] (reduce unchecked-subtract (cljs.core/unchecked-subtract x y) more)))
+
+(defn ^number unchecked-subtract-int
+ "If no ys are supplied, returns the negation of x, else subtracts
+ the ys from x and returns the result."
+ ([x] (cljs.core/unchecked-subtract-int x))
+ ([x y] (cljs.core/unchecked-subtract-int x y))
+ ([x y & more] (reduce unchecked-subtract-int (cljs.core/unchecked-subtract-int x y) more)))
+
+(defn- ^number fix [q]
+ (if (>= q 0)
+ (Math/floor q)
+ (Math/ceil q)))
+
+(defn int
+ "Coerce to int by stripping decimal places."
+ [x]
+ (bit-or x 0))
+
+(defn unchecked-int
+ "Coerce to int by stripping decimal places."
+ [x]
+ (fix x))
+
+(defn long
+ "Coerce to long by stripping decimal places. Identical to `int'."
+ [x]
+ (fix x))
+
+(defn unchecked-long
+ "Coerce to long by stripping decimal places. Identical to `int'."
+ [x]
+ (fix x))
+
+(defn booleans [x] x)
+(defn bytes [x] x)
+(defn chars [x] x)
+(defn shorts [x] x)
+(defn ints [x] x)
+(defn floats [x] x)
+(defn doubles [x] x)
+(defn longs [x] x)
+
+(defn js-mod
+ "Modulus of num and div with original javascript behavior. i.e. bug for negative numbers"
+ [n d]
+ (cljs.core/js-mod n d))
+
+(defn mod
+ "Modulus of num and div. Truncates toward negative infinity."
+ [n d]
+ (js-mod (+ (js-mod n d) d) d))
+
+(defn quot
+ "quot[ient] of dividing numerator by denominator."
+ [n d]
+ (let [rem (js-mod n d)]
+ (fix (/ (- n rem) d))))
+
+(defn rem
+ "remainder of dividing numerator by denominator."
+ [n d]
+ (let [q (quot n d)]
+ (- n (* d q))))
+
+(defn bit-xor
+ "Bitwise exclusive or"
+ ([x y] (cljs.core/bit-xor x y))
+ ([x y & more]
+ (reduce bit-xor (cljs.core/bit-xor x y) more)))
+
+(defn bit-and
+ "Bitwise and"
+ ([x y] (cljs.core/bit-and x y))
+ ([x y & more]
+ (reduce bit-and (cljs.core/bit-and x y) more)))
+
+(defn bit-or
+ "Bitwise or"
+ ([x y] (cljs.core/bit-or x y))
+ ([x y & more]
+ (reduce bit-or (cljs.core/bit-or x y) more)))
+
+(defn bit-and-not
+ "Bitwise and with complement"
+ ([x y] (cljs.core/bit-and-not x y))
+ ([x y & more]
+ (reduce bit-and-not (cljs.core/bit-and-not x y) more)))
+
+(defn bit-clear
+ "Clear bit at index n"
+ [x n]
+ (cljs.core/bit-clear x n))
+
+(defn bit-flip
+ "Flip bit at index n"
+ [x n]
+ (cljs.core/bit-flip x n))
+
+(defn bit-not
+ "Bitwise complement"
+ [x] (cljs.core/bit-not x))
+
+(defn bit-set
+ "Set bit at index n"
+ [x n]
+ (cljs.core/bit-set x n))
+
+(defn ^boolean bit-test
+ "Test bit at index n"
+ [x n]
+ (cljs.core/bit-test x n))
+
+(defn bit-shift-left
+ "Bitwise shift left"
+ [x n] (cljs.core/bit-shift-left x n))
+
+(defn bit-shift-right
+ "Bitwise shift right"
+ [x n] (cljs.core/bit-shift-right x n))
+
+(defn bit-shift-right-zero-fill
+ "DEPRECATED: Bitwise shift right with zero fill"
+ [x n] (cljs.core/bit-shift-right-zero-fill x n))
+
+(defn unsigned-bit-shift-right
+ "Bitwise shift right with zero fill"
+ [x n] (cljs.core/unsigned-bit-shift-right x n))
+
+(defn bit-count
+ "Counts the number of bits set in n"
+ [v]
+ (let [v (- v (bit-and (bit-shift-right v 1) 0x55555555))
+ v (+ (bit-and v 0x33333333) (bit-and (bit-shift-right v 2) 0x33333333))]
+ (bit-shift-right (* (bit-and (+ v (bit-shift-right v 4)) 0xF0F0F0F) 0x1010101) 24)))
+
+(defn ^boolean ==
+ "Returns non-nil if nums all have the equivalent
+ value, otherwise false. Behavior on non nums is
+ undefined."
+ ([x] true)
+ ([x y] (-equiv x y))
+ ([x y & more]
+ (if (== x y)
+ (if (next more)
+ (recur y (first more) (next more))
+ (== y (first more)))
+ false)))
+
+(defn ^boolean pos?
+ "Returns true if num is greater than zero, else false"
+ [x] (cljs.core/pos? x))
+
+(defn ^boolean zero?
+ "Returns true if num is zero, else false"
+ [x]
+ (cljs.core/zero? x))
+
+(defn ^boolean neg?
+ "Returns true if num is less than zero, else false"
+ [x] (cljs.core/neg? x))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; protocols for host types ;;;;;;
+
+(defn nthnext
+ "Returns the nth next of coll, (seq coll) when n is 0."
+ [coll n]
+ (loop [n n xs (seq coll)]
+ (if (and xs (pos? n))
+ (recur (dec n) (next xs))
+ xs)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; basics ;;;;;;;;;;;;;;;;;;
+
+(defn str
+ "With no args, returns the empty string. With one arg x, returns
+ x.toString(). (str nil) returns the empty string. With more than
+ one arg, returns the concatenation of the str values of the args."
+ ([] "")
+ ([x] (if (nil? x)
+ ""
+ (.join #js [x] "")))
+ ([x & ys]
+ (loop [sb (StringBuffer. (str x)) more ys]
+ (if more
+ (recur (. sb (append (str (first more)))) (next more))
+ (.toString sb)))))
+
+(defn subs
+ "Returns the substring of s beginning at start inclusive, and ending
+ at end (defaults to length of string), exclusive."
+ ([s start] (.substring s start))
+ ([s start end] (.substring s start end)))
+
+(declare map name)
+
+(defn- equiv-sequential
+ "Assumes x is sequential. Returns true if x equals y, otherwise
+ returns false."
+ [x y]
+ (boolean
+ (when (sequential? y)
+ (if (and (counted? x) (counted? y)
+ (not (== (count x) (count y))))
+ false
+ (loop [xs (seq x) ys (seq y)]
+ (cond (nil? xs) (nil? ys)
+ (nil? ys) false
+ (= (first xs) (first ys)) (recur (next xs) (next ys))
+ :else false))))))
+
+(defn- hash-coll [coll]
+ (if (seq coll)
+ (loop [res (hash (first coll)) s (next coll)]
+ (if (nil? s)
+ res
+ (recur (hash-combine res (hash (first s))) (next s))))
+ 0))
+
+(declare key val)
+
+(defn- hash-imap [m]
+ ;; a la clojure.lang.APersistentMap
+ (loop [h 0 s (seq m)]
+ (if s
+ (let [e (first s)]
+ (recur (js-mod (+ h (bit-xor (hash (key e)) (hash (val e))))
+ 4503599627370496)
+ (next s)))
+ h)))
+
+(defn- hash-iset [s]
+ ;; a la clojure.lang.APersistentSet
+ (loop [h 0 s (seq s)]
+ (if s
+ (let [e (first s)]
+ (recur (js-mod (+ h (hash e)) 4503599627370496)
+ (next s)))
+ h)))
+
+(declare name chunk-first chunk-rest)
+
+(defn- extend-object!
+ "Takes a JavaScript object and a map of names to functions and
+ attaches said functions as methods on the object. Any references to
+ JavaScript's implicit this (via the this-as macro) will resolve to the
+ object that the function is attached."
+ [obj fn-map]
+ (doseq [[key-name f] fn-map]
+ (let [str-name (name key-name)]
+ (gobject/set obj str-name f)))
+ obj)
+
+;;;;;;;;;;;;;;;; cons ;;;;;;;;;;;;;;;;
+(deftype List [meta first rest count ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x count))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IList
+
+ ICloneable
+ (-clone [_] (List. meta first rest count __hash))
+
+ IWithMeta
+ (-with-meta [coll meta] (List. meta first rest count __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ASeq
+ ISeq
+ (-first [coll] first)
+ (-rest [coll]
+ (if (== count 1)
+ ()
+ rest))
+
+ INext
+ (-next [coll]
+ (if (== count 1)
+ nil
+ rest))
+
+ IStack
+ (-peek [coll] first)
+ (-pop [coll] (-rest coll))
+
+ ICollection
+ (-conj [coll o] (List. meta o coll (inc count) nil))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ ISeqable
+ (-seq [coll] coll)
+
+ ICounted
+ (-count [coll] count)
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(defn ^boolean list?
+ "Returns true if x implements IList"
+ [x]
+ (satisfies? IList x))
+
+(es6-iterable List)
+
+(deftype EmptyList [meta]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IList
+
+ ICloneable
+ (-clone [_] (EmptyList. meta))
+
+ IWithMeta
+ (-with-meta [coll meta] (EmptyList. meta))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ISeq
+ (-first [coll] nil)
+ (-rest [coll] ())
+
+ INext
+ (-next [coll] nil)
+
+ IStack
+ (-peek [coll] nil)
+ (-pop [coll] (throw (js/Error. "Can't pop empty list")))
+
+ ICollection
+ (-conj [coll o] (List. meta o nil 1 nil))
+
+ IEmptyableCollection
+ (-empty [coll] coll)
+
+ ISequential
+ IEquiv
+ (-equiv [coll other]
+ (if (or (list? other)
+ (sequential? other))
+ (nil? (seq other))
+ false))
+
+ IHash
+ (-hash [coll] empty-ordered-hash)
+
+ ISeqable
+ (-seq [coll] nil)
+
+ ICounted
+ (-count [coll] 0)
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(set! (.-EMPTY List) (EmptyList. nil))
+
+(es6-iterable EmptyList)
+
+(defn ^boolean reversible?
+ "Returns true if coll satisfies? IReversible."
+ [coll]
+ (satisfies? IReversible coll))
+
+(defn ^seq rseq
+ "Returns, in constant time, a seq of the items in rev (which
+ can be a vector or sorted-map), in reverse order. If rev is empty returns nil"
+ [rev]
+ (-rseq rev))
+
+(defn reverse
+ "Returns a seq of the items in coll in reverse order. Not lazy."
+ [coll]
+ (if (reversible? coll)
+ (or (rseq coll) ())
+ (reduce conj () coll)))
+
+(defn list
+ "Creates a new list containing the items."
+ [& xs]
+ (let [arr (if (and (instance? IndexedSeq xs) (zero? (.-i xs)))
+ (.-arr xs)
+ (let [arr (array)]
+ (loop [^not-native xs xs]
+ (if-not (nil? xs)
+ (do
+ (.push arr (-first xs))
+ (recur (-next xs)))
+ arr))))]
+ (loop [i (alength arr) ^not-native r ()]
+ (if (> i 0)
+ (recur (dec i) (-conj r (aget arr (dec i))))
+ r))))
+
+(deftype Cons [meta first rest ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IList
+
+ ICloneable
+ (-clone [_] (Cons. meta first rest __hash))
+
+ IWithMeta
+ (-with-meta [coll meta] (Cons. meta first rest __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ASeq
+ ISeq
+ (-first [coll] first)
+ (-rest [coll] (if (nil? rest) () rest))
+
+ INext
+ (-next [coll]
+ (if (nil? rest) nil (seq rest)))
+
+ ICollection
+ (-conj [coll o] (Cons. nil o coll nil))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ ISeqable
+ (-seq [coll] coll)
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(es6-iterable Cons)
+
+(defn cons
+ "Returns a new seq where x is the first element and coll is the rest."
+ [x coll]
+ (if (or (nil? coll)
+ (implements? ISeq coll))
+ (Cons. nil x coll nil)
+ (Cons. nil x (seq coll) nil)))
+
+(defn hash-keyword [k]
+ (int (+ (hash-symbol k) 0x9e3779b9)))
+
+(defn- compare-keywords [a b]
+ (cond
+ (identical? (.-fqn a) (.-fqn b)) 0
+ (and (not (.-ns a)) (.-ns b)) -1
+ (.-ns a) (if-not (.-ns b)
+ 1
+ (let [nsc (garray/defaultCompare (.-ns a) (.-ns b))]
+ (if (== 0 nsc)
+ (garray/defaultCompare (.-name a) (.-name b))
+ nsc)))
+ :default (garray/defaultCompare (.-name a) (.-name b))))
+
+(deftype Keyword [ns name fqn ^:mutable _hash]
+ Object
+ (toString [_] (str ":" fqn))
+ (equiv [this other]
+ (-equiv this other))
+
+ IEquiv
+ (-equiv [_ other]
+ (if (instance? Keyword other)
+ (identical? fqn (.-fqn other))
+ false))
+ IFn
+ (-invoke [kw coll]
+ (get coll kw))
+ (-invoke [kw coll not-found]
+ (get coll kw not-found))
+
+ IHash
+ (-hash [this]
+ (caching-hash this hash-keyword _hash))
+
+ INamed
+ (-name [_] name)
+ (-namespace [_] ns)
+
+ IPrintWithWriter
+ (-pr-writer [o writer _] (-write writer (str ":" fqn))))
+
+(defn ^boolean keyword?
+ "Return true if x is a Keyword"
+ [x]
+ (instance? Keyword x))
+
+(defn ^boolean keyword-identical?
+ "Efficient test to determine that two keywords are identical."
+ [x y]
+ (if (identical? x y)
+ true
+ (if (and (keyword? x) (keyword? y))
+ (identical? (.-fqn x) (.-fqn y))
+ false)))
+
+(defn ^boolean symbol-identical?
+ "Efficient test to determine that two symbols are identical."
+ [x y]
+ (if (identical? x y)
+ true
+ (if (and (symbol? x) (symbol? y))
+ (identical? (.-str x) (.-str y))
+ false)))
+
+(defn namespace
+ "Returns the namespace String of a symbol or keyword, or nil if not present."
+ [x]
+ (if (implements? INamed x)
+ (-namespace ^not-native x)
+ (throw (js/Error. (str "Doesn't support namespace: " x)))))
+
+(defn ^boolean ident?
+ "Return true if x is a symbol or keyword"
+ [x] (or (keyword? x) (symbol? x)))
+
+(defn ^boolean simple-ident?
+ "Return true if x is a symbol or keyword without a namespace"
+ [x] (and (ident? x) (nil? (namespace x))))
+
+(defn ^boolean qualified-ident?
+ "Return true if x is a symbol or keyword with a namespace"
+ [x] (boolean (and (ident? x) (namespace x) true)))
+
+(defn ^boolean simple-symbol?
+ "Return true if x is a symbol without a namespace"
+ [x] (and (symbol? x) (nil? (namespace x))))
+
+(defn ^boolean qualified-symbol?
+ "Return true if x is a symbol with a namespace"
+ [x] (boolean (and (symbol? x) (namespace x) true)))
+
+(defn ^boolean simple-keyword?
+ "Return true if x is a keyword without a namespace"
+ [x] (and (keyword? x) (nil? (namespace x))))
+
+(defn ^boolean qualified-keyword?
+ "Return true if x is a keyword with a namespace"
+ [x] (boolean (and (keyword? x) (namespace x) true)))
+
+(defn keyword
+ "Returns a Keyword with the given namespace and name. Do not use :
+ in the keyword strings, it will be added automatically."
+ ([name] (cond
+ (keyword? name) name
+ (symbol? name) (Keyword.
+ (cljs.core/namespace name)
+ (cljs.core/name name) (.-str name) nil)
+ (string? name) (let [parts (.split name "/")]
+ (if (== (alength parts) 2)
+ (Keyword. (aget parts 0) (aget parts 1) name nil)
+ (Keyword. nil (aget parts 0) name nil)))))
+ ([ns name]
+ (let [ns (cond
+ (keyword? ns) (cljs.core/name ns)
+ (symbol? ns) (cljs.core/name ns)
+ :else ns)
+ name (cond
+ (keyword? name) (cljs.core/name name)
+ (symbol? name) (cljs.core/name name)
+ :else name)]
+ (Keyword. ns name (str (when ns (str ns "/")) name) nil))))
+
+
+(deftype LazySeq [meta ^:mutable fn ^:mutable s ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (sval [coll]
+ (if (nil? fn)
+ s
+ (do
+ (set! s (fn))
+ (set! fn nil)
+ s)))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IPending
+ (-realized? [coll]
+ (not fn))
+
+ IWithMeta
+ (-with-meta [coll meta] (LazySeq. meta #(-seq coll) nil __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ISeq
+ (-first [coll]
+ (-seq coll)
+ (when-not (nil? s)
+ (first s)))
+ (-rest [coll]
+ (-seq coll)
+ (if-not (nil? s)
+ (rest s)
+ ()))
+
+ INext
+ (-next [coll]
+ (-seq coll)
+ (when-not (nil? s)
+ (next s)))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ ISeqable
+ (-seq [coll]
+ (.sval coll)
+ (when-not (nil? s)
+ (loop [ls s]
+ (if (instance? LazySeq ls)
+ (recur (.sval ls))
+ (do (set! s ls)
+ (seq s))))))
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(es6-iterable LazySeq)
+
+(declare ArrayChunk)
+
+(deftype ChunkBuffer [^:mutable buf ^:mutable end]
+ Object
+ (add [_ o]
+ (aset buf end o)
+ (set! end (inc end)))
+
+ (chunk [_]
+ (let [ret (ArrayChunk. buf 0 end)]
+ (set! buf nil)
+ ret))
+
+ ICounted
+ (-count [_] end))
+
+(defn chunk-buffer [capacity]
+ (ChunkBuffer. (make-array capacity) 0))
+
+(deftype ArrayChunk [arr off end]
+ ICounted
+ (-count [_] (- end off))
+
+ IIndexed
+ (-nth [coll i]
+ (aget arr (+ off i)))
+ (-nth [coll i not-found]
+ (if (and (>= i 0) (< i (- end off)))
+ (aget arr (+ off i))
+ not-found))
+
+ IChunk
+ (-drop-first [coll]
+ (if (== off end)
+ (throw (js/Error. "-drop-first of empty chunk"))
+ (ArrayChunk. arr (inc off) end)))
+
+ IReduce
+ (-reduce [coll f]
+ (array-reduce arr f (aget arr off) (inc off)))
+ (-reduce [coll f start]
+ (array-reduce arr f start off)))
+
+(defn array-chunk
+ ([arr]
+ (ArrayChunk. arr 0 (alength arr)))
+ ([arr off]
+ (ArrayChunk. arr off (alength arr)))
+ ([arr off end]
+ (ArrayChunk. arr off end)))
+
+(deftype ChunkedCons [chunk more meta ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IWithMeta
+ (-with-meta [coll m]
+ (ChunkedCons. chunk more m __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ ISeqable
+ (-seq [coll] coll)
+
+ ASeq
+ ISeq
+ (-first [coll] (-nth chunk 0))
+ (-rest [coll]
+ (if (> (-count chunk) 1)
+ (ChunkedCons. (-drop-first chunk) more meta nil)
+ (if (nil? more)
+ ()
+ more)))
+
+ INext
+ (-next [coll]
+ (if (> (-count chunk) 1)
+ (ChunkedCons. (-drop-first chunk) more meta nil)
+ (when-not (nil? more)
+ (-seq more))))
+
+ IChunkedSeq
+ (-chunked-first [coll] chunk)
+ (-chunked-rest [coll]
+ (if (nil? more)
+ ()
+ more))
+
+ IChunkedNext
+ (-chunked-next [coll]
+ (if (nil? more)
+ nil
+ more))
+
+ ICollection
+ (-conj [this o]
+ (cons o this))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash)))
+
+(es6-iterable ChunkedCons)
+
+(defn chunk-cons [chunk rest]
+ (if (zero? (-count chunk))
+ rest
+ (ChunkedCons. chunk rest nil nil)))
+
+(defn chunk-append [b x]
+ (.add b x))
+
+(defn chunk [b]
+ (.chunk b))
+
+(defn chunk-first [s]
+ (-chunked-first s))
+
+(defn chunk-rest [s]
+ (-chunked-rest s))
+
+(defn chunk-next [s]
+ (if (implements? IChunkedNext s)
+ (-chunked-next s)
+ (seq (-chunked-rest s))))
+
+;;;;;;;;;;;;;;;;
+
+(defn to-array
+ "Returns an array containing the contents of coll."
+ [coll]
+ (let [ary (array)]
+ (loop [s (seq coll)]
+ (if-not (nil? s)
+ (do (. ary push (first s))
+ (recur (next s)))
+ ary))))
+
+(defn to-array-2d
+ "Returns a (potentially-ragged) 2-dimensional array
+ containing the contents of coll."
+ [coll]
+ (let [ret (make-array (count coll))]
+ (loop [i 0 xs (seq coll)]
+ (when-not (nil? xs)
+ (aset ret i (to-array (first xs)))
+ (recur (inc i) (next xs))))
+ ret))
+
+(defn int-array
+ "Creates an array of ints. Does not coerce array, provided for compatibility
+ with Clojure."
+ ([size-or-seq]
+ (if (number? size-or-seq)
+ (int-array size-or-seq nil)
+ (into-array size-or-seq)))
+ ([size init-val-or-seq]
+ (let [a (make-array size)]
+ (if (seq? init-val-or-seq)
+ (let [s (seq init-val-or-seq)]
+ (loop [i 0 s s]
+ (if (and s (< i size))
+ (do
+ (aset a i (first s))
+ (recur (inc i) (next s)))
+ a)))
+ (do
+ (dotimes [i size]
+ (aset a i init-val-or-seq))
+ a)))))
+
+(defn long-array
+ "Creates an array of longs. Does not coerce array, provided for compatibility
+ with Clojure."
+ ([size-or-seq]
+ (if (number? size-or-seq)
+ (long-array size-or-seq nil)
+ (into-array size-or-seq)))
+ ([size init-val-or-seq]
+ (let [a (make-array size)]
+ (if (seq? init-val-or-seq)
+ (let [s (seq init-val-or-seq)]
+ (loop [i 0 s s]
+ (if (and s (< i size))
+ (do
+ (aset a i (first s))
+ (recur (inc i) (next s)))
+ a)))
+ (do
+ (dotimes [i size]
+ (aset a i init-val-or-seq))
+ a)))))
+
+(defn double-array
+ "Creates an array of doubles. Does not coerce array, provided for compatibility
+ with Clojure."
+ ([size-or-seq]
+ (if (number? size-or-seq)
+ (double-array size-or-seq nil)
+ (into-array size-or-seq)))
+ ([size init-val-or-seq]
+ (let [a (make-array size)]
+ (if (seq? init-val-or-seq)
+ (let [s (seq init-val-or-seq)]
+ (loop [i 0 s s]
+ (if (and s (< i size))
+ (do
+ (aset a i (first s))
+ (recur (inc i) (next s)))
+ a)))
+ (do
+ (dotimes [i size]
+ (aset a i init-val-or-seq))
+ a)))))
+
+(defn object-array
+ "Creates an array of objects. Does not coerce array, provided for compatibility
+ with Clojure."
+ ([size-or-seq]
+ (if (number? size-or-seq)
+ (object-array size-or-seq nil)
+ (into-array size-or-seq)))
+ ([size init-val-or-seq]
+ (let [a (make-array size)]
+ (if (seq? init-val-or-seq)
+ (let [s (seq init-val-or-seq)]
+ (loop [i 0 s s]
+ (if (and s (< i size))
+ (do
+ (aset a i (first s))
+ (recur (inc i) (next s)))
+ a)))
+ (do
+ (dotimes [i size]
+ (aset a i init-val-or-seq))
+ a)))))
+
+(defn bounded-count
+ "If coll is counted? returns its count, else will count at most the first n
+ elements of coll using its seq"
+ {:added "1.9"}
+ [n coll]
+ (if (counted? coll)
+ (count coll)
+ (loop [i 0 s (seq coll)]
+ (if (and (not (nil? s)) (< i n))
+ (recur (inc i) (next s))
+ i))))
+
+(defn spread
+ [arglist]
+ (when-not (nil? arglist)
+ (let [n (next arglist)]
+ (if (nil? n)
+ (seq (first arglist))
+ (cons (first arglist)
+ (spread n))))))
+
+(defn concat
+ "Returns a lazy seq representing the concatenation of the elements in the supplied colls."
+ ([] (lazy-seq nil))
+ ([x] (lazy-seq x))
+ ([x y]
+ (lazy-seq
+ (let [s (seq x)]
+ (if s
+ (if (chunked-seq? s)
+ (chunk-cons (chunk-first s) (concat (chunk-rest s) y))
+ (cons (first s) (concat (rest s) y)))
+ y))))
+ ([x y & zs]
+ (let [cat (fn cat [xys zs]
+ (lazy-seq
+ (let [xys (seq xys)]
+ (if xys
+ (if (chunked-seq? xys)
+ (chunk-cons (chunk-first xys)
+ (cat (chunk-rest xys) zs))
+ (cons (first xys) (cat (rest xys) zs)))
+ (when zs
+ (cat (first zs) (next zs)))))))]
+ (cat (concat x y) zs))))
+
+(defn list*
+ "Creates a new list containing the items prepended to the rest, the
+ last of which will be treated as a sequence."
+ ([args] (seq args))
+ ([a args] (cons a args))
+ ([a b args] (cons a (cons b args)))
+ ([a b c args] (cons a (cons b (cons c args))))
+ ([a b c d & more]
+ (cons a (cons b (cons c (cons d (spread more)))))))
+
+
+;;; Transients
+
+(defn transient
+ "Returns a new, transient version of the collection, in constant time."
+ [coll]
+ (-as-transient coll))
+
+(defn persistent!
+ "Returns a new, persistent version of the transient collection, in
+ constant time. The transient collection cannot be used after this
+ call, any such use will throw an exception."
+ [tcoll]
+ (-persistent! tcoll))
+
+(defn conj!
+ "Adds val to the transient collection, and return tcoll. The 'addition'
+ may happen at different 'places' depending on the concrete type."
+ ([] (transient []))
+ ([tcoll] tcoll)
+ ([tcoll val]
+ (-conj! tcoll val))
+ ([tcoll val & vals]
+ (let [ntcoll (-conj! tcoll val)]
+ (if vals
+ (recur ntcoll (first vals) (next vals))
+ ntcoll))))
+
+(defn assoc!
+ "When applied to a transient map, adds mapping of key(s) to
+ val(s). When applied to a transient vector, sets the val at index.
+ Note - index must be <= (count vector). Returns coll."
+ ([tcoll key val]
+ (-assoc! tcoll key val))
+ ([tcoll key val & kvs]
+ (let [ntcoll (-assoc! tcoll key val)]
+ (if kvs
+ (recur ntcoll (first kvs) (second kvs) (nnext kvs))
+ ntcoll))))
+
+(defn dissoc!
+ "Returns a transient map that doesn't contain a mapping for key(s)."
+ ([tcoll key]
+ (-dissoc! tcoll key))
+ ([tcoll key & ks]
+ (let [ntcoll (-dissoc! tcoll key)]
+ (if ks
+ (recur ntcoll (first ks) (next ks))
+ ntcoll))))
+
+(defn pop!
+ "Removes the last item from a transient vector. If
+ the collection is empty, throws an exception. Returns tcoll"
+ [tcoll]
+ (-pop! tcoll))
+
+(defn disj!
+ "disj[oin]. Returns a transient set of the same (hashed/sorted) type, that
+ does not contain key(s)."
+ ([tcoll val]
+ (-disjoin! tcoll val))
+ ([tcoll val & vals]
+ (let [ntcoll (-disjoin! tcoll val)]
+ (if vals
+ (recur ntcoll (first vals) (next vals))
+ ntcoll))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; apply ;;;;;;;;;;;;;;;;
+
+;; see core.clj
+(gen-apply-to)
+
+(set! *unchecked-if* true)
+
+(defn- apply-to-simple
+ "Internal. DO NOT USE!
+ Assumes args was already called with seq beforehand!"
+ ([f ^seq args]
+ (if (nil? args)
+ (if (.-cljs$core$IFn$_invoke$arity$0 f)
+ (.cljs$core$IFn$_invoke$arity$0 f)
+ (.call f f))
+ (apply-to-simple f (-first args) (next args))))
+ ([f a0 ^seq args]
+ (if (nil? args)
+ (if (.-cljs$core$IFn$_invoke$arity$1 f)
+ (.cljs$core$IFn$_invoke$arity$1 f a0)
+ (.call f f a0))
+ (apply-to-simple f a0 (-first args) (next args))))
+ ([f a0 a1 ^seq args]
+ (if (nil? args)
+ (if (.-cljs$core$IFn$_invoke$arity$2 f)
+ (.cljs$core$IFn$_invoke$arity$2 f a0 a1)
+ (.call f f a0 a1))
+ (apply-to-simple f a0 a1 (-first args) (next args))))
+ ([f a0 a1 a2 ^seq args]
+ (if (nil? args)
+ (if (.-cljs$core$IFn$_invoke$arity$3 f)
+ (.cljs$core$IFn$_invoke$arity$3 f a0 a1 a2)
+ (.call f f a0 a1 a2))
+ (apply-to-simple f a0 a1 a2 (-first args) (next args))))
+ ([f a0 a1 a2 a3 ^seq args]
+ (if (nil? args)
+ (if (.-cljs$core$IFn$_invoke$arity$4 f)
+ (.cljs$core$IFn$_invoke$arity$4 f a0 a1 a2 a3)
+ (.call f f a0 a1 a2 a3))
+ (gen-apply-to-simple f 4 args))))
+
+(defn apply
+ "Applies fn f to the argument list formed by prepending intervening arguments to args."
+ ([f args]
+ (if (.-cljs$lang$applyTo f)
+ (let [fixed-arity (.-cljs$lang$maxFixedArity f)
+ bc (bounded-count (inc fixed-arity) args)]
+ (if (<= bc fixed-arity)
+ (apply-to f bc args)
+ (.cljs$lang$applyTo f args)))
+ (apply-to-simple f (seq args))))
+ ([f x args]
+ (if (.-cljs$lang$applyTo f)
+ (let [arglist (list* x args)
+ fixed-arity (.-cljs$lang$maxFixedArity f)
+ bc (inc (bounded-count fixed-arity args))]
+ (if (<= bc fixed-arity)
+ (apply-to f bc arglist)
+ (.cljs$lang$applyTo f arglist)))
+ (apply-to-simple f x (seq args))))
+ ([f x y args]
+ (if (.-cljs$lang$applyTo f)
+ (let [arglist (list* x y args)
+ fixed-arity (.-cljs$lang$maxFixedArity f)
+ bc (+ 2 (bounded-count (dec fixed-arity) args))]
+ (if (<= bc fixed-arity)
+ (apply-to f bc arglist)
+ (.cljs$lang$applyTo f arglist)))
+ (apply-to-simple f x y (seq args))))
+ ([f x y z args]
+ (if (.-cljs$lang$applyTo f)
+ (let [arglist (list* x y z args)
+ fixed-arity (.-cljs$lang$maxFixedArity f)
+ bc (+ 3 (bounded-count (- fixed-arity 2) args))]
+ (if (<= bc fixed-arity)
+ (apply-to f bc arglist)
+ (.cljs$lang$applyTo f arglist)))
+ (apply-to-simple f x y z (seq args))))
+ ([f a b c d & args]
+ (if (.-cljs$lang$applyTo f)
+ (let [spread-args (spread args)
+ arglist (cons a (cons b (cons c (cons d spread-args))))
+ fixed-arity (.-cljs$lang$maxFixedArity f)
+ bc (+ 4 (bounded-count (- fixed-arity 3) spread-args))]
+ (if (<= bc fixed-arity)
+ (apply-to f bc arglist)
+ (.cljs$lang$applyTo f arglist)))
+ (apply-to-simple f a b c d (spread args)))))
+
+(set! *unchecked-if* false)
+
+(defn vary-meta
+ "Returns an object of the same type and value as obj, with
+ (apply f (meta obj) args) as its metadata."
+ ([obj f]
+ (with-meta obj (f (meta obj))))
+ ([obj f a]
+ (with-meta obj (f (meta obj) a)))
+ ([obj f a b]
+ (with-meta obj (f (meta obj) a b)))
+ ([obj f a b c]
+ (with-meta obj (f (meta obj) a b c)))
+ ([obj f a b c d]
+ (with-meta obj (f (meta obj) a b c d)))
+ ([obj f a b c d & args]
+ (with-meta obj (apply f (meta obj) a b c d args))))
+
+(defn ^boolean not=
+ "Same as (not (= obj1 obj2))"
+ ([x] false)
+ ([x y] (not (= x y)))
+ ([x y & more]
+ (not (apply = x y more))))
+
+(defn not-empty
+ "If coll is empty, returns nil, else coll"
+ [coll] (when (seq coll) coll))
+
+(defn nil-iter []
+ (reify
+ Object
+ (hasNext [_] false)
+ (next [_] (js/Error. "No such element"))
+ (remove [_] (js/Error. "Unsupported operation"))))
+
+(deftype StringIter [s ^:mutable i]
+ Object
+ (hasNext [_] (< i (.-length s)))
+ (next [_]
+ (let [ret (.charAt s i)]
+ (set! i (inc i))
+ ret))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+(defn string-iter [x]
+ (StringIter. x 0))
+
+(deftype ArrayIter [arr ^:mutable i]
+ Object
+ (hasNext [_] (< i (alength arr)))
+ (next [_]
+ (let [ret (aget arr i)]
+ (set! i (inc i))
+ ret))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+(defn array-iter [x]
+ (ArrayIter. x 0))
+
+(def INIT #js {})
+(def START #js {})
+
+(deftype SeqIter [^:mutable _seq ^:mutable _next]
+ Object
+ (hasNext [_]
+ (if (identical? _seq INIT)
+ (do
+ (set! _seq START)
+ (set! _next (seq _next)))
+ (if (identical? _seq _next)
+ (set! _next (next _seq))))
+ (not (nil? _next)))
+ (next [this]
+ (if-not ^boolean (.hasNext this)
+ (throw (js/Error. "No such element"))
+ (do
+ (set! _seq _next)
+ (first _next))))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+(defn seq-iter [coll]
+ (SeqIter. INIT coll))
+
+(defn iter [coll]
+ (cond
+ (iterable? coll) (-iterator coll)
+ (nil? coll) (nil-iter)
+ (string? coll) (string-iter coll)
+ (array? coll) (array-iter coll)
+ (seqable? coll) (seq-iter coll)
+ :else (throw (js/Error. (str "Cannot create iterator from " coll)))))
+
+(deftype Many [vals]
+ Object
+ (add [this o]
+ (.push vals o)
+ this)
+ (remove [this]
+ (.shift vals))
+ (isEmpty [this]
+ (zero? (.-length vals)))
+ (toString [this]
+ (str "Many: " vals)))
+
+(def ^:private NONE #js {})
+
+(deftype Single [^:mutable val]
+ Object
+ (add [this o]
+ (if (identical? val NONE)
+ (do
+ (set! val o)
+ this)
+ (Many. #js [val o])))
+ (remove [this]
+ (if (identical? val NONE)
+ (throw (js/Error. (str "Removing object from empty buffer")))
+ (let [ret val]
+ (set! val NONE)
+ ret)))
+ (isEmpty [this]
+ (identical? val NONE))
+ (toString [this]
+ (str "Single: " val)))
+
+(deftype Empty []
+ Object
+ (add [this o]
+ (Single. o))
+ (remove [this]
+ (throw (js/Error. (str "Removing object from empty buffer"))))
+ (isEmpty [this]
+ true)
+ (toString [this]
+ "Empty"))
+
+(def ^:private EMPTY (Empty.))
+
+(deftype MultiIterator [iters]
+ Object
+ (hasNext [_]
+ (loop [iters (seq iters)]
+ (if-not (nil? iters)
+ (let [iter (first iters)]
+ (if-not ^boolean (.hasNext iter)
+ false
+ (recur (next iters))))
+ true)))
+ (next [_]
+ (let [nexts (array)]
+ (dotimes [i (alength iters)]
+ (aset nexts i (.next (aget iters i))))
+ (prim-seq nexts 0))))
+
+(defn- chunkIteratorSeq [iter]
+ (lazy-seq
+ (when ^boolean (.hasNext iter)
+ (let [arr (array)]
+ (loop [n 0]
+ (if (and (.hasNext iter) (< n 32))
+ (do
+ (aset arr n (.next iter))
+ (recur (inc n)))
+ (chunk-cons (array-chunk arr 0 n) (chunkIteratorSeq iter))))))))
+
+(deftype TransformerIterator [^:mutable buffer ^:mutable _next ^:mutable completed ^:mutable xf sourceIter multi]
+ Object
+ (step [this]
+ (if-not (identical? _next NONE)
+ true
+ (loop []
+ (if (identical? _next NONE)
+ (if ^boolean (.isEmpty buffer)
+ (if ^boolean completed
+ false
+ (if ^boolean (.hasNext sourceIter)
+ (let [iter (if ^boolean multi
+ (apply xf (cons nil (.next sourceIter)))
+ (xf nil (.next sourceIter)))]
+ (when (reduced? iter)
+ (xf nil)
+ (set! completed true))
+ (recur))
+ (do
+ (xf nil)
+ (set! completed true)
+ (recur))))
+ (do
+ (set! _next (.remove buffer))
+ (recur)))
+ true))))
+ (hasNext [this]
+ (.step this))
+ (next [this]
+ (if ^boolean (.hasNext this)
+ (let [ret _next]
+ (set! _next NONE)
+ ret)
+ (throw (js/Error. "No such element"))))
+ (remove [_]
+ (js/Error. "Unsupported operation")))
+
+(es6-iterable TransformerIterator)
+
+(defn transformer-iterator
+ [xform sourceIter multi]
+ (let [iterator (TransformerIterator. EMPTY NONE false nil sourceIter multi)]
+ (set! (.-xf iterator)
+ (xform (fn
+ ([] nil)
+ ([acc] acc)
+ ([acc o]
+ (set! (.-buffer iterator) (.add (.-buffer iterator) o))
+ acc))))
+ iterator))
+
+(set! (.-create TransformerIterator)
+ (fn [xform source]
+ (transformer-iterator xform source false)))
+
+(set! (.-createMulti TransformerIterator)
+ (fn [xform sources]
+ (transformer-iterator xform (MultiIterator. (to-array sources)) true)))
+
+(defn sequence
+ "Coerces coll to a (possibly empty) sequence, if it is not already
+ one. Will not force a lazy seq. (sequence nil) yields (), When a
+ transducer is supplied, returns a lazy sequence of applications of
+ the transform to the items in coll(s), i.e. to the set of first
+ items of each coll, followed by the set of second
+ items in each coll, until any one of the colls is exhausted. Any
+ remaining items in other colls are ignored. The transform should accept
+ number-of-colls arguments"
+ ([coll]
+ (if (seq? coll)
+ coll
+ (or (seq coll) ())))
+ ([xform coll]
+ (or (chunkIteratorSeq
+ (.create TransformerIterator xform (iter coll)))
+ ()))
+ ([xform coll & colls]
+ (or (chunkIteratorSeq
+ (.createMulti TransformerIterator xform (map iter (cons coll colls))))
+ ())))
+
+(defn ^boolean every?
+ "Returns true if (pred x) is logical true for every x in coll, else
+ false."
+ [pred coll]
+ (cond
+ (nil? (seq coll)) true
+ (pred (first coll)) (recur pred (next coll))
+ :else false))
+
+(defn ^boolean not-every?
+ "Returns false if (pred x) is logical true for every x in
+ coll, else true."
+ [pred coll] (not (every? pred coll)))
+
+(defn some
+ "Returns the first logical true value of (pred x) for any x in coll,
+ else nil. One common idiom is to use a set as pred, for example
+ this will return :fred if :fred is in the sequence, otherwise nil:
+ (some #{:fred} coll)"
+ [pred coll]
+ (when (seq coll)
+ (or (pred (first coll)) (recur pred (next coll)))))
+
+(defn ^boolean not-any?
+ "Returns false if (pred x) is logical true for any x in coll,
+ else true."
+ [pred coll] (not (some pred coll)))
+
+(defn ^boolean even?
+ "Returns true if n is even, throws an exception if n is not an integer"
+ [n] (if (integer? n)
+ (zero? (bit-and n 1))
+ (throw (js/Error. (str "Argument must be an integer: " n)))))
+
+(defn ^boolean odd?
+ "Returns true if n is odd, throws an exception if n is not an integer"
+ [n] (not (even? n)))
+
+(defn complement
+ "Takes a fn f and returns a fn that takes the same arguments as f,
+ has the same effects, if any, and returns the opposite truth value."
+ [f]
+ (fn
+ ([] (not (f)))
+ ([x] (not (f x)))
+ ([x y] (not (f x y)))
+ ([x y & zs] (not (apply f x y zs)))))
+
+(defn constantly
+ "Returns a function that takes any number of arguments and returns x."
+ [x] (fn [& args] x))
+
+(defn comp
+ "Takes a set of functions and returns a fn that is the composition
+ of those fns. The returned fn takes a variable number of args,
+ applies the rightmost of fns to the args, the next
+ fn (right-to-left) to the result, etc."
+ ([] identity)
+ ([f] f)
+ ([f g]
+ (fn
+ ([] (f (g)))
+ ([x] (f (g x)))
+ ([x y] (f (g x y)))
+ ([x y z] (f (g x y z)))
+ ([x y z & args] (f (apply g x y z args)))))
+ ([f g h]
+ (fn
+ ([] (f (g (h))))
+ ([x] (f (g (h x))))
+ ([x y] (f (g (h x y))))
+ ([x y z] (f (g (h x y z))))
+ ([x y z & args] (f (g (apply h x y z args))))))
+ ([f1 f2 f3 & fs]
+ (let [fs (reverse (list* f1 f2 f3 fs))]
+ (fn [& args]
+ (loop [ret (apply (first fs) args) fs (next fs)]
+ (if fs
+ (recur ((first fs) ret) (next fs))
+ ret))))))
+
+(defn partial
+ "Takes a function f and fewer than the normal arguments to f, and
+ returns a fn that takes a variable number of additional args. When
+ called, the returned function calls f with args + additional args."
+ ([f] f)
+ ([f arg1]
+ (fn
+ ([] (f arg1))
+ ([x] (f arg1 x))
+ ([x y] (f arg1 x y))
+ ([x y z] (f arg1 x y z))
+ ([x y z & args] (apply f arg1 x y z args))))
+ ([f arg1 arg2]
+ (fn
+ ([] (f arg1 arg2))
+ ([x] (f arg1 arg2 x))
+ ([x y] (f arg1 arg2 x y))
+ ([x y z] (f arg1 arg2 x y z))
+ ([x y z & args] (apply f arg1 arg2 x y z args))))
+ ([f arg1 arg2 arg3]
+ (fn
+ ([] (f arg1 arg2 arg3))
+ ([x] (f arg1 arg2 arg3 x))
+ ([x y] (f arg1 arg2 arg3 x y))
+ ([x y z] (f arg1 arg2 arg3 x y z))
+ ([x y z & args] (apply f arg1 arg2 arg3 x y z args))))
+ ([f arg1 arg2 arg3 & more]
+ (fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))
+
+(defn fnil
+ "Takes a function f, and returns a function that calls f, replacing
+ a nil first argument to f with the supplied value x. Higher arity
+ versions can replace arguments in the second and third
+ positions (y, z). Note that the function f can take any number of
+ arguments, not just the one(s) being nil-patched."
+ ([f x]
+ (fn
+ ([a] (f (if (nil? a) x a)))
+ ([a b] (f (if (nil? a) x a) b))
+ ([a b c] (f (if (nil? a) x a) b c))
+ ([a b c & ds] (apply f (if (nil? a) x a) b c ds))))
+ ([f x y]
+ (fn
+ ([a b] (f (if (nil? a) x a) (if (nil? b) y b)))
+ ([a b c] (f (if (nil? a) x a) (if (nil? b) y b) c))
+ ([a b c & ds] (apply f (if (nil? a) x a) (if (nil? b) y b) c ds))))
+ ([f x y z]
+ (fn
+ ([a b] (f (if (nil? a) x a) (if (nil? b) y b)))
+ ([a b c] (f (if (nil? a) x a) (if (nil? b) y b) (if (nil? c) z c)))
+ ([a b c & ds] (apply f (if (nil? a) x a) (if (nil? b) y b) (if (nil? c) z c) ds)))))
+
+(declare volatile!)
+
+(defn map-indexed
+ "Returns a lazy sequence consisting of the result of applying f to 0
+ and the first item of coll, followed by applying f to 1 and the second
+ item in coll, etc, until coll is exhausted. Thus function f should
+ accept 2 arguments, index and item. Returns a stateful transducer when
+ no collection is provided."
+ ([f]
+ (fn [rf]
+ (let [i (volatile! -1)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (rf result (f (vswap! i inc) input)))))))
+ ([f coll]
+ (letfn [(mapi [idx coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (if (chunked-seq? s)
+ (let [c (chunk-first s)
+ size (count c)
+ b (chunk-buffer size)]
+ (dotimes [i size]
+ (chunk-append b (f (+ idx i) (-nth c i))))
+ (chunk-cons (chunk b) (mapi (+ idx size) (chunk-rest s))))
+ (cons (f idx (first s)) (mapi (inc idx) (rest s)))))))]
+ (mapi 0 coll))))
+
+(defn keep
+ "Returns a lazy sequence of the non-nil results of (f item). Note,
+ this means false return values will be included. f must be free of
+ side-effects. Returns a transducer when no collection is provided."
+ ([f]
+ (fn [rf]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (let [v (f input)]
+ (if (nil? v)
+ result
+ (rf result v)))))))
+ ([f coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (if (chunked-seq? s)
+ (let [c (chunk-first s)
+ size (count c)
+ b (chunk-buffer size)]
+ (dotimes [i size]
+ (let [x (f (-nth c i))]
+ (when-not (nil? x)
+ (chunk-append b x))))
+ (chunk-cons (chunk b) (keep f (chunk-rest s))))
+ (let [x (f (first s))]
+ (if (nil? x)
+ (keep f (rest s))
+ (cons x (keep f (rest s))))))))))
+
+;; =============================================================================
+;; Atom
+
+(deftype Atom [state meta validator watches]
+ Object
+ (equiv [this other]
+ (-equiv this other))
+
+ IAtom
+
+ IEquiv
+ (-equiv [o other] (identical? o other))
+
+ IDeref
+ (-deref [_] state)
+
+ IMeta
+ (-meta [_] meta)
+
+ IWatchable
+ (-notify-watches [this oldval newval]
+ (doseq [[key f] watches]
+ (f key this oldval newval)))
+ (-add-watch [this key f]
+ (set! (.-watches this) (assoc watches key f))
+ this)
+ (-remove-watch [this key]
+ (set! (.-watches this) (dissoc watches key)))
+
+ IHash
+ (-hash [this] (goog/getUid this)))
+
+(defn atom
+ "Creates and returns an Atom with an initial value of x and zero or
+ more options (in any order):
+
+ :meta metadata-map
+
+ :validator validate-fn
+
+ If metadata-map is supplied, it will be come the metadata on the
+ atom. validate-fn must be nil or a side-effect-free fn of one
+ argument, which will be passed the intended new state on any state
+ change. If the new state is unacceptable, the validate-fn should
+ return false or throw an Error. If either of these error conditions
+ occur, then the value of the atom will not change."
+ ([x] (Atom. x nil nil nil))
+ ([x & {:keys [meta validator]}] (Atom. x meta validator nil)))
+
+(declare pr-str)
+
+(defn reset!
+ "Sets the value of atom to newval without regard for the
+ current value. Returns new-value."
+ [a new-value]
+ (if (instance? Atom a)
+ (let [validate (.-validator a)]
+ (when-not (nil? validate)
+ (when-not (validate new-value)
+ (throw (js/Error. "Validator rejected reference state"))))
+ (let [old-value (.-state a)]
+ (set! (.-state a) new-value)
+ (when-not (nil? (.-watches a))
+ (-notify-watches a old-value new-value))
+ new-value))
+ (-reset! a new-value)))
+
+(defn reset-vals!
+ "Sets the value of atom to newval. Returns [old new], the value of the
+ atom before and after the reset."
+ {:added "1.9"}
+ [a new-value]
+ (let [validate (.-validator a)]
+ (when-not (nil? validate)
+ (when-not (validate new-value)
+ (throw (js/Error. "Validator rejected reference state"))))
+ (let [old-value (.-state a)]
+ (set! (.-state a) new-value)
+ (when-not (nil? (.-watches a))
+ (-notify-watches a old-value new-value))
+ [old-value new-value])))
+
+(defn swap!
+ "Atomically swaps the value of atom to be:
+ (apply f current-value-of-atom args). Note that f may be called
+ multiple times, and thus should be free of side effects. Returns
+ the value that was swapped in."
+ ([a f]
+ (if (instance? Atom a)
+ (reset! a (f (.-state a)))
+ (-swap! a f)))
+ ([a f x]
+ (if (instance? Atom a)
+ (reset! a (f (.-state a) x))
+ (-swap! a f x)))
+ ([a f x y]
+ (if (instance? Atom a)
+ (reset! a (f (.-state a) x y))
+ (-swap! a f x y)))
+ ([a f x y & more]
+ (if (instance? Atom a)
+ (reset! a (apply f (.-state a) x y more))
+ (-swap! a f x y more))))
+
+(defn swap-vals!
+ "Atomically swaps the value of atom to be:
+ (apply f current-value-of-atom args). Note that f may be called
+ multiple times, and thus should be free of side effects.
+ Returns [old new], the value of the atom before and after the swap."
+ {:added "1.9"}
+ ([a f]
+ (reset-vals! a (f (.-state a))))
+ ([a f x]
+ (reset-vals! a (f (.-state a) x)))
+ ([a f x y]
+ (reset-vals! a (f (.-state a) x y)))
+ ([a f x y & more]
+ (reset-vals! a (apply f (.-state a) x y more))))
+
+(defn compare-and-set!
+ "Atomically sets the value of atom to newval if and only if the
+ current value of the atom is equal to oldval. Returns true if
+ set happened, else false."
+ [^not-native a oldval newval]
+ (if (= (-deref a) oldval)
+ (do (reset! a newval) true)
+ false))
+
+(defn set-validator!
+ "Sets the validator-fn for an atom. validator-fn must be nil or a
+ side-effect-free fn of one argument, which will be passed the intended
+ new state on any state change. If the new state is unacceptable, the
+ validator-fn should return false or throw an Error. If the current state
+ is not acceptable to the new validator, an Error will be thrown and the
+ validator will not be changed."
+ [iref val]
+ (when (and (some? val)
+ (not (val (-deref iref))))
+ (throw (js/Error. "Validator rejected reference state")))
+ (set! (.-validator iref) val))
+
+(defn get-validator
+ "Gets the validator-fn for a var/ref/agent/atom."
+ [iref]
+ (.-validator iref))
+
+(deftype Volatile [^:mutable state]
+ IVolatile
+ (-vreset! [_ new-state]
+ (set! state new-state))
+
+ IDeref
+ (-deref [_] state))
+
+(defn volatile!
+ "Creates and returns a Volatile with an initial value of val."
+ [val]
+ (Volatile. val))
+
+(defn ^boolean volatile?
+ "Returns true if x is a volatile."
+ [x] (instance? Volatile x))
+
+(defn vreset!
+ "Sets the value of volatile to newval without regard for the
+ current value. Returns newval."
+ [vol newval] (-vreset! vol newval))
+
+(defn keep-indexed
+ "Returns a lazy sequence of the non-nil results of (f index item). Note,
+ this means false return values will be included. f must be free of
+ side-effects. Returns a stateful transducer when no collection is
+ provided."
+ ([f]
+ (fn [rf]
+ (let [ia (volatile! -1)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (let [i (vswap! ia inc)
+ v (f i input)]
+ (if (nil? v)
+ result
+ (rf result v))))))))
+ ([f coll]
+ (letfn [(keepi [idx coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (if (chunked-seq? s)
+ (let [c (chunk-first s)
+ size (count c)
+ b (chunk-buffer size)]
+ (dotimes [i size]
+ (let [x (f (+ idx i) (-nth c i))]
+ (when-not (nil? x)
+ (chunk-append b x))))
+ (chunk-cons (chunk b) (keepi (+ idx size) (chunk-rest s))))
+ (let [x (f idx (first s))]
+ (if (nil? x)
+ (keepi (inc idx) (rest s))
+ (cons x (keepi (inc idx) (rest s)))))))))]
+ (keepi 0 coll))))
+
+(defn every-pred
+ "Takes a set of predicates and returns a function f that returns true if all of its
+ composing predicates return a logical true value against all of its arguments, else it returns
+ false. Note that f is short-circuiting in that it will stop execution on the first
+ argument that triggers a logical false result against the original predicates."
+ ([p]
+ (fn ep1
+ ([] true)
+ ([x] (boolean (p x)))
+ ([x y] (boolean (and (p x) (p y))))
+ ([x y z] (boolean (and (p x) (p y) (p z))))
+ ([x y z & args] (boolean (and (ep1 x y z)
+ (every? p args))))))
+ ([p1 p2]
+ (fn ep2
+ ([] true)
+ ([x] (boolean (and (p1 x) (p2 x))))
+ ([x y] (boolean (and (p1 x) (p1 y) (p2 x) (p2 y))))
+ ([x y z] (boolean (and (p1 x) (p1 y) (p1 z) (p2 x) (p2 y) (p2 z))))
+ ([x y z & args] (boolean (and (ep2 x y z)
+ (every? #(and (p1 %) (p2 %)) args))))))
+ ([p1 p2 p3]
+ (fn ep3
+ ([] true)
+ ([x] (boolean (and (p1 x) (p2 x) (p3 x))))
+ ([x y] (boolean (and (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y))))
+ ([x y z] (boolean (and (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y) (p1 z) (p2 z) (p3 z))))
+ ([x y z & args] (boolean (and (ep3 x y z)
+ (every? #(and (p1 %) (p2 %) (p3 %)) args))))))
+ ([p1 p2 p3 & ps]
+ (let [ps (list* p1 p2 p3 ps)]
+ (fn epn
+ ([] true)
+ ([x] (every? #(% x) ps))
+ ([x y] (every? #(and (% x) (% y)) ps))
+ ([x y z] (every? #(and (% x) (% y) (% z)) ps))
+ ([x y z & args] (boolean (and (epn x y z)
+ (every? #(every? % args) ps))))))))
+
+(defn some-fn
+ "Takes a set of predicates and returns a function f that returns the first logical true value
+ returned by one of its composing predicates against any of its arguments, else it returns
+ logical false. Note that f is short-circuiting in that it will stop execution on the first
+ argument that triggers a logical true result against the original predicates."
+ ([p]
+ (fn sp1
+ ([] nil)
+ ([x] (p x))
+ ([x y] (or (p x) (p y)))
+ ([x y z] (or (p x) (p y) (p z)))
+ ([x y z & args] (or (sp1 x y z)
+ (some p args)))))
+ ([p1 p2]
+ (fn sp2
+ ([] nil)
+ ([x] (or (p1 x) (p2 x)))
+ ([x y] (or (p1 x) (p1 y) (p2 x) (p2 y)))
+ ([x y z] (or (p1 x) (p1 y) (p1 z) (p2 x) (p2 y) (p2 z)))
+ ([x y z & args] (or (sp2 x y z)
+ (some #(or (p1 %) (p2 %)) args)))))
+ ([p1 p2 p3]
+ (fn sp3
+ ([] nil)
+ ([x] (or (p1 x) (p2 x) (p3 x)))
+ ([x y] (or (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y)))
+ ([x y z] (or (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y) (p1 z) (p2 z) (p3 z)))
+ ([x y z & args] (or (sp3 x y z)
+ (some #(or (p1 %) (p2 %) (p3 %)) args)))))
+ ([p1 p2 p3 & ps]
+ (let [ps (list* p1 p2 p3 ps)]
+ (fn spn
+ ([] nil)
+ ([x] (some #(% x) ps))
+ ([x y] (some #(or (% x) (% y)) ps))
+ ([x y z] (some #(or (% x) (% y) (% z)) ps))
+ ([x y z & args] (or (spn x y z)
+ (some #(some % args) ps)))))))
+
+(defn map
+ "Returns a lazy sequence consisting of the result of applying f to
+ the set of first items of each coll, followed by applying f to the
+ set of second items in each coll, until any one of the colls is
+ exhausted. Any remaining items in other colls are ignored. Function
+ f should accept number-of-colls arguments. Returns a transducer when
+ no collection is provided."
+ ([f]
+ (fn [rf]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (rf result (f input)))
+ ([result input & inputs]
+ (rf result (apply f input inputs))))))
+ ([f coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (if (chunked-seq? s)
+ (let [c (chunk-first s)
+ size (count c)
+ b (chunk-buffer size)]
+ (dotimes [i size]
+ (chunk-append b (f (-nth c i))))
+ (chunk-cons (chunk b) (map f (chunk-rest s))))
+ (cons (f (first s)) (map f (rest s)))))))
+ ([f c1 c2]
+ (lazy-seq
+ (let [s1 (seq c1) s2 (seq c2)]
+ (when (and s1 s2)
+ (cons (f (first s1) (first s2))
+ (map f (rest s1) (rest s2)))))))
+ ([f c1 c2 c3]
+ (lazy-seq
+ (let [s1 (seq c1) s2 (seq c2) s3 (seq c3)]
+ (when (and s1 s2 s3)
+ (cons (f (first s1) (first s2) (first s3))
+ (map f (rest s1) (rest s2) (rest s3)))))))
+ ([f c1 c2 c3 & colls]
+ (let [step (fn step [cs]
+ (lazy-seq
+ (let [ss (map seq cs)]
+ (when (every? identity ss)
+ (cons (map first ss) (step (map rest ss)))))))]
+ (map #(apply f %) (step (conj colls c3 c2 c1))))))
+
+(defn take
+ "Returns a lazy sequence of the first n items in coll, or all items if
+ there are fewer than n. Returns a stateful transducer when
+ no collection is provided."
+ ([n]
+ {:pre [(number? n)]}
+ (fn [rf]
+ (let [na (volatile! n)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (let [n @na
+ nn (vswap! na dec)
+ result (if (pos? n)
+ (rf result input)
+ result)]
+ (if (not (pos? nn))
+ (ensure-reduced result)
+ result)))))))
+ ([n coll]
+ {:pre [(number? n)]}
+ (lazy-seq
+ (when (pos? n)
+ (when-let [s (seq coll)]
+ (cons (first s) (take (dec n) (rest s))))))))
+
+(defn drop
+ "Returns a lazy sequence of all but the first n items in coll.
+ Returns a stateful transducer when no collection is provided."
+ ([n]
+ {:pre [(number? n)]}
+ (fn [rf]
+ (let [na (volatile! n)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (let [n @na]
+ (vswap! na dec)
+ (if (pos? n)
+ result
+ (rf result input))))))))
+ ([n coll]
+ {:pre [(number? n)]}
+ (let [step (fn [n coll]
+ (let [s (seq coll)]
+ (if (and (pos? n) s)
+ (recur (dec n) (rest s))
+ s)))]
+ (lazy-seq (step n coll)))))
+
+(defn drop-last
+ "Return a lazy sequence of all but the last n (default 1) items in coll"
+ ([s] (drop-last 1 s))
+ ([n s] (map (fn [x _] x) s (drop n s))))
+
+(defn take-last
+ "Returns a seq of the last n items in coll. Depending on the type
+ of coll may be no better than linear time. For vectors, see also subvec."
+ [n coll]
+ (loop [s (seq coll), lead (seq (drop n coll))]
+ (if lead
+ (recur (next s) (next lead))
+ s)))
+
+(defn drop-while
+ "Returns a lazy sequence of the items in coll starting from the
+ first item for which (pred item) returns logical false. Returns a
+ stateful transducer when no collection is provided."
+ ([pred]
+ (fn [rf]
+ (let [da (volatile! true)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (let [drop? @da]
+ (if (and drop? (pred input))
+ result
+ (do
+ (vreset! da nil)
+ (rf result input)))))))))
+ ([pred coll]
+ (let [step (fn [pred coll]
+ (let [s (seq coll)]
+ (if (and s (pred (first s)))
+ (recur pred (rest s))
+ s)))]
+ (lazy-seq (step pred coll)))))
+
+(deftype Cycle [meta all prev ^:mutable current ^:mutable _next]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (currentval [coll]
+ (when-not ^seq current
+ (if-let [c (next prev)]
+ (set! current c)
+ (set! current all)))
+ current)
+
+ IPending
+ (-realized? [coll]
+ (some? current))
+
+ IWithMeta
+ (-with-meta [coll meta] (Cycle. meta all prev current _next))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ISeq
+ (-first [coll]
+ (first (.currentval coll)))
+ (-rest [coll]
+ (when (nil? _next)
+ (set! _next (Cycle. nil all (.currentval coll) nil nil)))
+ _next)
+
+ INext
+ (-next [coll]
+ (-rest coll))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ ISeqable
+ (-seq [coll] coll)
+
+ IReduce
+ (-reduce [coll f]
+ (loop [s (.currentval coll) ret (first s)]
+ (let [s (or (next s) all)
+ ret (f ret (first s))]
+ (if (reduced? ret)
+ @ret
+ (recur s ret)))))
+ (-reduce [coll f start]
+ (loop [s (.currentval coll) ret start]
+ (let [ret (f ret (first s))]
+ (if (reduced? ret)
+ @ret
+ (recur (or (next s) all) ret))))))
+
+(defn cycle
+ "Returns a lazy (infinite!) sequence of repetitions of the items in coll."
+ [coll] (if-let [vals (seq coll)]
+ (Cycle. nil vals nil vals nil)
+ (.-EMPTY List)))
+
+(defn split-at
+ "Returns a vector of [(take n coll) (drop n coll)]"
+ [n coll]
+ [(take n coll) (drop n coll)])
+
+(deftype Repeat [meta count val ^:mutable next ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x count))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IPending
+ (-realized? [coll] false)
+
+ IWithMeta
+ (-with-meta [coll meta] (Repeat. meta count val next nil))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ISeq
+ (-first [coll]
+ val)
+ (-rest [coll]
+ (if (nil? next)
+ (if (> count 1)
+ (do
+ (set! next (Repeat. nil (dec count) val nil nil))
+ next)
+ (if (== -1 count)
+ coll
+ ()))
+ next))
+
+ INext
+ (-next [coll]
+ (if (nil? next)
+ (if (> count 1)
+ (do
+ (set! next (Repeat. nil (dec count) val nil nil))
+ next)
+ (if (== -1 count)
+ coll
+ nil))
+ next))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ ISequential
+ ISeqable
+ (-seq [coll] coll)
+
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IReduce
+ (-reduce [coll f]
+ (if (== count -1)
+ (loop [ret (f val val)]
+ (if (reduced? ret)
+ @ret
+ (recur (f ret val))))
+ (loop [i 1 ret val]
+ (if (< i count)
+ (let [ret (f ret val)]
+ (if (reduced? ret)
+ @ret
+ (recur (inc i) ret)))
+ ret))))
+ (-reduce [coll f start]
+ (if (== count -1)
+ (loop [ret (f start val)]
+ (if (reduced? ret)
+ @ret
+ (recur (f ret val))))
+ (loop [i 0 ret start]
+ (if (< i count)
+ (let [ret (f ret val)]
+ (if (reduced? ret)
+ @ret
+ (recur (inc i) ret)))
+ ret)))))
+
+(defn repeat
+ "Returns a lazy (infinite!, or length n if supplied) sequence of xs."
+ ([x] (Repeat. nil -1 x nil nil))
+ ([n x] (if (pos? n)
+ (Repeat. nil n x nil nil)
+ (.-EMPTY List))))
+
+(defn replicate
+ "DEPRECATED: Use 'repeat' instead.
+ Returns a lazy seq of n xs."
+ [n x] (take n (repeat x)))
+
+(defn repeatedly
+ "Takes a function of no args, presumably with side effects, and
+ returns an infinite (or length n if supplied) lazy sequence of calls
+ to it"
+ ([f] (lazy-seq (cons (f) (repeatedly f))))
+ ([n f] (take n (repeatedly f))))
+
+(def ^:private UNREALIZED-SEED #js {})
+
+(deftype Iterate [meta f prev-seed ^:mutable seed ^:mutable next]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+
+ IPending
+ (-realized? [coll]
+ (not (identical? seed UNREALIZED-SEED)))
+
+ IWithMeta
+ (-with-meta [coll meta] (Iterate. meta f prev-seed seed next))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ISeq
+ (-first [coll]
+ (when (identical? UNREALIZED-SEED seed)
+ (set! seed (f prev-seed)))
+ seed)
+ (-rest [coll]
+ (when (nil? next)
+ (set! next (Iterate. nil f (-first coll) UNREALIZED-SEED nil)))
+ next)
+
+ INext
+ (-next [coll]
+ (-rest coll))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ ISeqable
+ (-seq [coll] coll)
+
+ IReduce
+ (-reduce [coll rf]
+ (let [first (-first coll)
+ v (f first)]
+ (loop [ret (rf first v) v v]
+ (if (reduced? ret)
+ @ret
+ (let [v (f v)]
+ (recur (rf ret v) v))))))
+ (-reduce [coll rf start]
+ (let [v (-first coll)]
+ (loop [ret (rf start v) v v]
+ (if (reduced? ret)
+ @ret
+ (let [v (f v)]
+ (recur (rf ret v) v)))))))
+
+(defn iterate
+ "Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects"
+ {:added "1.0"}
+ [f x] (Iterate. nil f nil x nil))
+
+(defn interleave
+ "Returns a lazy seq of the first item in each coll, then the second etc."
+ ([] ())
+ ([c1] (lazy-seq c1))
+ ([c1 c2]
+ (lazy-seq
+ (let [s1 (seq c1) s2 (seq c2)]
+ (when (and s1 s2)
+ (cons (first s1) (cons (first s2)
+ (interleave (rest s1) (rest s2))))))))
+ ([c1 c2 & colls]
+ (lazy-seq
+ (let [ss (map seq (conj colls c2 c1))]
+ (when (every? identity ss)
+ (concat (map first ss) (apply interleave (map rest ss))))))))
+
+(defn interpose
+ "Returns a lazy seq of the elements of coll separated by sep.
+ Returns a stateful transducer when no collection is provided."
+ ([sep]
+ (fn [rf]
+ (let [started (volatile! false)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (if @started
+ (let [sepr (rf result sep)]
+ (if (reduced? sepr)
+ sepr
+ (rf sepr input)))
+ (do
+ (vreset! started true)
+ (rf result input))))))))
+ ([sep coll] (drop 1 (interleave (repeat sep) coll))))
+
+
+
+(defn- flatten1
+ "Take a collection of collections, and return a lazy seq
+ of items from the inner collection"
+ [colls]
+ (let [cat (fn cat [coll colls]
+ (lazy-seq
+ (if-let [coll (seq coll)]
+ (cons (first coll) (cat (rest coll) colls))
+ (when (seq colls)
+ (cat (first colls) (rest colls))))))]
+ (cat nil colls)))
+
+(declare cat)
+
+(defn mapcat
+ "Returns the result of applying concat to the result of applying map
+ to f and colls. Thus function f should return a collection. Returns
+ a transducer when no collections are provided"
+ {:added "1.0"
+ :static true}
+ ([f] (comp (map f) cat))
+ ([f & colls]
+ (apply concat (apply map f colls))))
+
+(defn filter
+ "Returns a lazy sequence of the items in coll for which
+ (pred item) returns logical true. pred must be free of side-effects.
+ Returns a transducer when no collection is provided."
+ ([pred]
+ (fn [rf]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (if (pred input)
+ (rf result input)
+ result)))))
+ ([pred coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (if (chunked-seq? s)
+ (let [c (chunk-first s)
+ size (count c)
+ b (chunk-buffer size)]
+ (dotimes [i size]
+ (when (pred (-nth c i))
+ (chunk-append b (-nth c i))))
+ (chunk-cons (chunk b) (filter pred (chunk-rest s))))
+ (let [f (first s) r (rest s)]
+ (if (pred f)
+ (cons f (filter pred r))
+ (filter pred r))))))))
+
+(defn remove
+ "Returns a lazy sequence of the items in coll for which
+ (pred item) returns logical false. pred must be free of side-effects.
+ Returns a transducer when no collection is provided."
+ ([pred] (filter (complement pred)))
+ ([pred coll]
+ (filter (complement pred) coll)))
+
+(defn tree-seq
+ "Returns a lazy sequence of the nodes in a tree, via a depth-first walk.
+ branch? must be a fn of one arg that returns true if passed a node
+ that can have children (but may not). children must be a fn of one
+ arg that returns a sequence of the children. Will only be called on
+ nodes for which branch? returns true. Root is the root node of the
+ tree."
+ [branch? children root]
+ (let [walk (fn walk [node]
+ (lazy-seq
+ (cons node
+ (when (branch? node)
+ (mapcat walk (children node))))))]
+ (walk root)))
+
+(defn flatten
+ "Takes any nested combination of sequential things (lists, vectors,
+ etc.) and returns their contents as a single, flat sequence.
+ (flatten nil) returns nil."
+ [x]
+ (filter #(not (sequential? %))
+ (rest (tree-seq sequential? seq x))))
+
+(defn into
+ "Returns a new coll consisting of to-coll with all of the items of
+ from-coll conjoined. A transducer may be supplied."
+ ([] [])
+ ([to] to)
+ ([to from]
+ (if-not (nil? to)
+ (if (implements? IEditableCollection to)
+ (-with-meta (persistent! (reduce -conj! (transient to) from)) (meta to))
+ (reduce -conj to from))
+ (reduce conj () from)))
+ ([to xform from]
+ (if (implements? IEditableCollection to)
+ (-with-meta (persistent! (transduce xform conj! (transient to) from)) (meta to))
+ (transduce xform conj to from))))
+
+(defn mapv
+ "Returns a vector consisting of the result of applying f to the
+ set of first items of each coll, followed by applying f to the set
+ of second items in each coll, until any one of the colls is
+ exhausted. Any remaining items in other colls are ignored. Function
+ f should accept number-of-colls arguments."
+ ([f coll]
+ (-> (reduce (fn [v o] (conj! v (f o))) (transient []) coll)
+ persistent!))
+ ([f c1 c2]
+ (into [] (map f c1 c2)))
+ ([f c1 c2 c3]
+ (into [] (map f c1 c2 c3)))
+ ([f c1 c2 c3 & colls]
+ (into [] (apply map f c1 c2 c3 colls))))
+
+(defn filterv
+ "Returns a vector of the items in coll for which
+ (pred item) returns logical true. pred must be free of side-effects."
+ [pred coll]
+ (-> (reduce (fn [v o] (if (pred o) (conj! v o) v))
+ (transient [])
+ coll)
+ persistent!))
+
+(defn partition
+ "Returns a lazy sequence of lists of n items each, at offsets step
+ apart. If step is not supplied, defaults to n, i.e. the partitions
+ do not overlap. If a pad collection is supplied, use its elements as
+ necessary to complete last partition up to n items. In case there are
+ not enough padding elements, return a partition with less than n items."
+ ([n coll]
+ (partition n n coll))
+ ([n step coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (let [p (take n s)]
+ (when (== n (count p))
+ (cons p (partition n step (drop step s))))))))
+ ([n step pad coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (let [p (take n s)]
+ (if (== n (count p))
+ (cons p (partition n step pad (drop step s)))
+ (list (take n (concat p pad)))))))))
+
+(defn get-in
+ "Returns the value in a nested associative structure,
+ where ks is a sequence of keys. Returns nil if the key is not present,
+ or the not-found value if supplied."
+ {:added "1.2"
+ :static true}
+ ([m ks]
+ (reduce get m ks))
+ ([m ks not-found]
+ (loop [sentinel lookup-sentinel
+ m m
+ ks (seq ks)]
+ (if-not (nil? ks)
+ (let [m (get m (first ks) sentinel)]
+ (if (identical? sentinel m)
+ not-found
+ (recur sentinel m (next ks))))
+ m))))
+
+(defn assoc-in
+ "Associates a value in a nested associative structure, where ks is a
+ sequence of keys and v is the new value and returns a new nested structure.
+ If any levels do not exist, hash-maps will be created."
+ [m [k & ks] v]
+ (if ks
+ (assoc m k (assoc-in (get m k) ks v))
+ (assoc m k v)))
+
+(defn update-in
+ "'Updates' a value in a nested associative structure, where ks is a
+ sequence of keys and f is a function that will take the old value
+ and any supplied args and return the new value, and returns a new
+ nested structure. If any levels do not exist, hash-maps will be
+ created."
+ ([m [k & ks] f]
+ (if ks
+ (assoc m k (update-in (get m k) ks f))
+ (assoc m k (f (get m k)))))
+ ([m [k & ks] f a]
+ (if ks
+ (assoc m k (update-in (get m k) ks f a))
+ (assoc m k (f (get m k) a))))
+ ([m [k & ks] f a b]
+ (if ks
+ (assoc m k (update-in (get m k) ks f a b))
+ (assoc m k (f (get m k) a b))))
+ ([m [k & ks] f a b c]
+ (if ks
+ (assoc m k (update-in (get m k) ks f a b c))
+ (assoc m k (f (get m k) a b c))))
+ ([m [k & ks] f a b c & args]
+ (if ks
+ (assoc m k (apply update-in (get m k) ks f a b c args))
+ (assoc m k (apply f (get m k) a b c args)))))
+
+(defn update
+ "'Updates' a value in an associative structure, where k is a
+ key and f is a function that will take the old value
+ and any supplied args and return the new value, and returns a new
+ structure. If the key does not exist, nil is passed as the old value."
+ ([m k f]
+ (assoc m k (f (get m k))))
+ ([m k f x]
+ (assoc m k (f (get m k) x)))
+ ([m k f x y]
+ (assoc m k (f (get m k) x y)))
+ ([m k f x y z]
+ (assoc m k (f (get m k) x y z)))
+ ([m k f x y z & more]
+ (assoc m k (apply f (get m k) x y z more))))
+
+;;; PersistentVector
+
+(deftype VectorNode [edit arr])
+
+(defn- pv-fresh-node [edit]
+ (VectorNode. edit (make-array 32)))
+
+(defn- pv-aget [node idx]
+ (aget (.-arr node) idx))
+
+(defn- pv-aset [node idx val]
+ (aset (.-arr node) idx val))
+
+(defn- pv-clone-node [node]
+ (VectorNode. (.-edit node) (aclone (.-arr node))))
+
+(defn- tail-off [pv]
+ (let [cnt (.-cnt pv)]
+ (if (< cnt 32)
+ 0
+ (bit-shift-left (bit-shift-right-zero-fill (dec cnt) 5) 5))))
+
+(defn- new-path [edit level node]
+ (loop [ll level
+ ret node]
+ (if (zero? ll)
+ ret
+ (let [embed ret
+ r (pv-fresh-node edit)
+ _ (pv-aset r 0 embed)]
+ (recur (- ll 5) r)))))
+
+(defn- push-tail [pv level parent tailnode]
+ (let [ret (pv-clone-node parent)
+ subidx (bit-and (bit-shift-right-zero-fill (dec (.-cnt pv)) level) 0x01f)]
+ (if (== 5 level)
+ (do
+ (pv-aset ret subidx tailnode)
+ ret)
+ (let [child (pv-aget parent subidx)]
+ (if-not (nil? child)
+ (let [node-to-insert (push-tail pv (- level 5) child tailnode)]
+ (pv-aset ret subidx node-to-insert)
+ ret)
+ (let [node-to-insert (new-path nil (- level 5) tailnode)]
+ (pv-aset ret subidx node-to-insert)
+ ret))))))
+
+(defn- vector-index-out-of-bounds [i cnt]
+ (throw (js/Error. (str "No item " i " in vector of length " cnt))))
+
+(defn- first-array-for-longvec [pv]
+ ;; invariants: (count pv) > 32.
+ (loop [node (.-root pv)
+ level (.-shift pv)]
+ (if (pos? level)
+ (recur (pv-aget node 0) (- level 5))
+ (.-arr node))))
+
+(defn- unchecked-array-for [pv i]
+ ;; invariant: i is a valid index of pv (use array-for if unknown).
+ (if (>= i (tail-off pv))
+ (.-tail pv)
+ (loop [node (.-root pv)
+ level (.-shift pv)]
+ (if (pos? level)
+ (recur (pv-aget node (bit-and (bit-shift-right-zero-fill i level) 0x01f))
+ (- level 5))
+ (.-arr node)))))
+
+(defn- array-for [pv i]
+ (if (and (<= 0 i) (< i (.-cnt pv)))
+ (unchecked-array-for pv i)
+ (vector-index-out-of-bounds i (.-cnt pv))))
+
+(defn- do-assoc [pv level node i val]
+ (let [ret (pv-clone-node node)]
+ (if (zero? level)
+ (do
+ (pv-aset ret (bit-and i 0x01f) val)
+ ret)
+ (let [subidx (bit-and (bit-shift-right-zero-fill i level) 0x01f)]
+ (pv-aset ret subidx (do-assoc pv (- level 5) (pv-aget node subidx) i val))
+ ret))))
+
+(defn- pop-tail [pv level node]
+ (let [subidx (bit-and (bit-shift-right-zero-fill (- (.-cnt pv) 2) level) 0x01f)]
+ (cond
+ (> level 5) (let [new-child (pop-tail pv (- level 5) (pv-aget node subidx))]
+ (if (and (nil? new-child) (zero? subidx))
+ nil
+ (let [ret (pv-clone-node node)]
+ (pv-aset ret subidx new-child)
+ ret)))
+ (zero? subidx) nil
+ :else (let [ret (pv-clone-node node)]
+ (pv-aset ret subidx nil)
+ ret))))
+
+(deftype RangedIterator [^:mutable i ^:mutable base ^:mutable arr v start end]
+ Object
+ (hasNext [this]
+ (< i end))
+ (next [this]
+ (when (== (- i base) 32)
+ (set! arr (unchecked-array-for v i))
+ (set! base (+ base 32)))
+ (let [ret (aget arr (bit-and i 0x01f))]
+ (set! i (inc i))
+ ret)))
+
+(defn ranged-iterator [v start end]
+ (let [i start]
+ (RangedIterator. i (- i (js-mod i 32))
+ (when (< start (count v))
+ (unchecked-array-for v i))
+ v start end)))
+
+(defn- pv-reduce
+ ([pv f start end]
+ (if (< start end)
+ (pv-reduce pv f (nth pv start) (inc start) end)
+ (f)))
+ ([pv f init start end]
+ (loop [acc init i start arr (unchecked-array-for pv start)]
+ (if (< i end)
+ (let [j (bit-and i 0x01f)
+ arr (if (zero? j) (unchecked-array-for pv i) arr)
+ nacc (f acc (aget arr j))]
+ (if (reduced? nacc)
+ @nacc
+ (recur nacc (inc i) arr)))
+ acc))))
+
+(declare tv-editable-root tv-editable-tail TransientVector deref
+ pr-sequential-writer pr-writer chunked-seq)
+
+(defprotocol APersistentVector
+ "Marker protocol")
+
+(deftype PersistentVector [meta cnt shift root tail ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ ICloneable
+ (-clone [_] (PersistentVector. meta cnt shift root tail __hash))
+
+ IWithMeta
+ (-with-meta [coll meta] (PersistentVector. meta cnt shift root tail __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ IStack
+ (-peek [coll]
+ (when (> cnt 0)
+ (-nth coll (dec cnt))))
+ (-pop [coll]
+ (cond
+ (zero? cnt) (throw (js/Error. "Can't pop empty vector"))
+ (== 1 cnt) (-with-meta (.-EMPTY PersistentVector) meta)
+ (< 1 (- cnt (tail-off coll)))
+ (PersistentVector. meta (dec cnt) shift root (.slice tail 0 -1) nil)
+ :else (let [new-tail (unchecked-array-for coll (- cnt 2))
+ nr (pop-tail coll shift root)
+ new-root (if (nil? nr) (.-EMPTY-NODE PersistentVector) nr)
+ cnt-1 (dec cnt)]
+ (if (and (< 5 shift) (nil? (pv-aget new-root 1)))
+ (PersistentVector. meta cnt-1 (- shift 5) (pv-aget new-root 0) new-tail nil)
+ (PersistentVector. meta cnt-1 shift new-root new-tail nil)))))
+
+ ICollection
+ (-conj [coll o]
+ (if (< (- cnt (tail-off coll)) 32)
+ (let [len (alength tail)
+ new-tail (make-array (inc len))]
+ (dotimes [i len]
+ (aset new-tail i (aget tail i)))
+ (aset new-tail len o)
+ (PersistentVector. meta (inc cnt) shift root new-tail nil))
+ (let [root-overflow? (> (bit-shift-right-zero-fill cnt 5) (bit-shift-left 1 shift))
+ new-shift (if root-overflow? (+ shift 5) shift)
+ new-root (if root-overflow?
+ (let [n-r (pv-fresh-node nil)]
+ (pv-aset n-r 0 root)
+ (pv-aset n-r 1 (new-path nil shift (VectorNode. nil tail)))
+ n-r)
+ (push-tail coll shift root (VectorNode. nil tail)))]
+ (PersistentVector. meta (inc cnt) new-shift new-root (array o) nil))))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY PersistentVector) meta))
+
+ ISequential
+ IEquiv
+ (-equiv [coll other]
+ (if (instance? PersistentVector other)
+ (if (== cnt (count other))
+ (let [me-iter (-iterator coll)
+ you-iter (-iterator other)]
+ (loop []
+ (if ^boolean (.hasNext me-iter)
+ (let [x (.next me-iter)
+ y (.next you-iter)]
+ (if (= x y)
+ (recur)
+ false))
+ true)))
+ false)
+ (equiv-sequential coll other)))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ ISeqable
+ (-seq [coll]
+ (cond
+ (zero? cnt) nil
+ (<= cnt 32) (IndexedSeq. tail 0 nil)
+ :else (chunked-seq coll (first-array-for-longvec coll) 0 0)))
+
+ ICounted
+ (-count [coll] cnt)
+
+ IIndexed
+ (-nth [coll n]
+ (aget (array-for coll n) (bit-and n 0x01f)))
+ (-nth [coll n not-found]
+ (if (and (<= 0 n) (< n cnt))
+ (aget (unchecked-array-for coll n) (bit-and n 0x01f))
+ not-found))
+
+ ILookup
+ (-lookup [coll k] (-lookup coll k nil))
+ (-lookup [coll k not-found] (if (number? k)
+ (-nth coll k not-found)
+ not-found))
+
+ IAssociative
+ (-assoc [coll k v]
+ (if (number? k)
+ (-assoc-n coll k v)
+ (throw (js/Error. "Vector's key for assoc must be a number."))))
+ (-contains-key? [coll k]
+ (if (integer? k)
+ (and (<= 0 k) (< k cnt))
+ false))
+
+ IFind
+ (-find [coll n]
+ (when (and (<= 0 n) (< n cnt))
+ (MapEntry. n (aget (unchecked-array-for coll n) (bit-and n 0x01f)) nil)))
+
+ APersistentVector
+ IVector
+ (-assoc-n [coll n val]
+ (cond
+ (and (<= 0 n) (< n cnt))
+ (if (<= (tail-off coll) n)
+ (let [new-tail (aclone tail)]
+ (aset new-tail (bit-and n 0x01f) val)
+ (PersistentVector. meta cnt shift root new-tail nil))
+ (PersistentVector. meta cnt shift (do-assoc coll shift root n val) tail nil))
+ (== n cnt) (-conj coll val)
+ :else (throw (js/Error. (str "Index " n " out of bounds [0," cnt "]")))))
+
+ IReduce
+ (-reduce [v f]
+ (pv-reduce v f 0 cnt))
+ (-reduce [v f init]
+ (loop [i 0 init init]
+ (if (< i cnt)
+ (let [arr (unchecked-array-for v i)
+ len (alength arr)
+ init (loop [j 0 init init]
+ (if (< j len)
+ (let [init (f init (aget arr j))]
+ (if (reduced? init)
+ init
+ (recur (inc j) init)))
+ init))]
+ (if (reduced? init)
+ @init
+ (recur (+ i len) init)))
+ init)))
+
+ IKVReduce
+ (-kv-reduce [v f init]
+ (loop [i 0 init init]
+ (if (< i cnt)
+ (let [arr (unchecked-array-for v i)
+ len (alength arr)
+ init (loop [j 0 init init]
+ (if (< j len)
+ (let [init (f init (+ j i) (aget arr j))]
+ (if (reduced? init)
+ init
+ (recur (inc j) init)))
+ init))]
+ (if (reduced? init)
+ @init
+ (recur (+ i len) init)))
+ init)))
+
+ IFn
+ (-invoke [coll k]
+ (-nth coll k))
+ (-invoke [coll k not-found]
+ (-nth coll k not-found))
+
+ IEditableCollection
+ (-as-transient [coll]
+ (TransientVector. cnt shift (tv-editable-root root) (tv-editable-tail tail)))
+
+ IReversible
+ (-rseq [coll]
+ (when (pos? cnt)
+ (RSeq. coll (dec cnt) nil)))
+
+ IIterable
+ (-iterator [this]
+ (ranged-iterator this 0 cnt)))
+
+(set! (.-EMPTY-NODE PersistentVector) (VectorNode. nil (make-array 32)))
+
+(set! (.-EMPTY PersistentVector)
+ (PersistentVector. nil 0 5 (.-EMPTY-NODE PersistentVector) (array) empty-ordered-hash))
+
+(set! (.-fromArray PersistentVector)
+ (fn [xs ^boolean no-clone]
+ (let [l (alength xs)
+ xs (if no-clone xs (aclone xs))]
+ (if (< l 32)
+ (PersistentVector. nil l 5 (.-EMPTY-NODE PersistentVector) xs nil)
+ (let [node (.slice xs 0 32)
+ v (PersistentVector. nil 32 5 (.-EMPTY-NODE PersistentVector) node nil)]
+ (loop [i 32 out (-as-transient v)]
+ (if (< i l)
+ (recur (inc i) (conj! out (aget xs i)))
+ (persistent! out))))))))
+
+(es6-iterable PersistentVector)
+
+(declare map-entry?)
+
+(defn vec
+ "Creates a new vector containing the contents of coll. JavaScript arrays
+ will be aliased and should not be modified."
+ [coll]
+ (cond
+ (map-entry? coll)
+ [(key coll) (val coll)]
+
+ (vector? coll)
+ (with-meta coll nil)
+
+ (array? coll)
+ (.fromArray PersistentVector coll true)
+
+ :else
+ (-persistent!
+ (reduce -conj!
+ (-as-transient (.-EMPTY PersistentVector))
+ coll))))
+
+(defn vector
+ "Creates a new vector containing the args."
+ [& args]
+ (if (and (instance? IndexedSeq args) (zero? (.-i args)))
+ (.fromArray PersistentVector (.-arr args) true)
+ (vec args)))
+
+(declare subvec)
+
+(deftype ChunkedSeq [vec node i off meta ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IWithMeta
+ (-with-meta [coll m]
+ (chunked-seq vec node i off m))
+ IMeta
+ (-meta [coll] meta)
+
+ ISeqable
+ (-seq [coll] coll)
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ ASeq
+ ISeq
+ (-first [coll]
+ (aget node off))
+ (-rest [coll]
+ (if (< (inc off) (alength node))
+ (let [s (chunked-seq vec node i (inc off))]
+ (if (nil? s)
+ ()
+ s))
+ (-chunked-rest coll)))
+
+ INext
+ (-next [coll]
+ (if (< (inc off) (alength node))
+ (let [s (chunked-seq vec node i (inc off))]
+ (if (nil? s)
+ nil
+ s))
+ (-chunked-next coll)))
+
+ ICollection
+ (-conj [coll o]
+ (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll]
+ ())
+
+ IChunkedSeq
+ (-chunked-first [coll]
+ (array-chunk node off))
+ (-chunked-rest [coll]
+ (let [end (+ i (alength node))]
+ (if (< end (-count vec))
+ (chunked-seq vec (unchecked-array-for vec end) end 0)
+ ())))
+
+ IChunkedNext
+ (-chunked-next [coll]
+ (let [end (+ i (alength node))]
+ (when (< end (-count vec))
+ (chunked-seq vec (unchecked-array-for vec end) end 0))))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ IReduce
+ (-reduce [coll f]
+ (pv-reduce vec f (+ i off) (count vec)))
+
+ (-reduce [coll f start]
+ (pv-reduce vec f start (+ i off) (count vec))))
+
+(es6-iterable ChunkedSeq)
+
+(defn chunked-seq
+ ([vec i off] (ChunkedSeq. vec (array-for vec i) i off nil nil))
+ ([vec node i off] (ChunkedSeq. vec node i off nil nil))
+ ([vec node i off meta]
+ (ChunkedSeq. vec node i off meta nil)))
+
+(declare build-subvec)
+
+(deftype Subvec [meta v start end ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ ICloneable
+ (-clone [_] (Subvec. meta v start end __hash))
+
+ IWithMeta
+ (-with-meta [coll meta] (build-subvec meta v start end __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ IStack
+ (-peek [coll]
+ (-nth v (dec end)))
+ (-pop [coll]
+ (if (== start end)
+ (throw (js/Error. "Can't pop empty vector"))
+ (build-subvec meta v start (dec end) nil)))
+
+ ICollection
+ (-conj [coll o]
+ (build-subvec meta (-assoc-n v end o) start (inc end) nil))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY PersistentVector) meta))
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ ISeqable
+ (-seq [coll]
+ (let [subvec-seq (fn subvec-seq [i]
+ (when-not (== i end)
+ (cons (-nth v i)
+ (lazy-seq
+ (subvec-seq (inc i))))))]
+ (subvec-seq start)))
+
+ IReversible
+ (-rseq [coll]
+ (if-not (== start end)
+ (RSeq. coll (dec (- end start)) nil)))
+
+ ICounted
+ (-count [coll] (- end start))
+
+ IIndexed
+ (-nth [coll n]
+ (if (or (neg? n) (<= end (+ start n)))
+ (vector-index-out-of-bounds n (- end start))
+ (-nth v (+ start n))))
+ (-nth [coll n not-found]
+ (if (or (neg? n) (<= end (+ start n)))
+ not-found
+ (-nth v (+ start n) not-found)))
+
+ ILookup
+ (-lookup [coll k] (-lookup coll k nil))
+ (-lookup [coll k not-found] (if (number? k)
+ (-nth coll k not-found)
+ not-found))
+
+ IAssociative
+ (-assoc [coll key val]
+ (if (number? key)
+ (-assoc-n coll key val)
+ (throw (js/Error. "Subvec's key for assoc must be a number."))))
+
+ IFind
+ (-find [coll n]
+ (when-not (neg? n)
+ (let [idx (+ start n)]
+ (when (< idx end)
+ (MapEntry. n (-lookup v idx) nil)))))
+
+ IVector
+ (-assoc-n [coll n val]
+ (let [v-pos (+ start n)]
+ (if (or (neg? n) (<= (inc end) v-pos))
+ (throw (js/Error. (str "Index " n " out of bounds [0," (-count coll) "]")))
+ (build-subvec meta (assoc v v-pos val) start (max end (inc v-pos)) nil))))
+
+ IReduce
+ (-reduce [coll f]
+ (if (implements? APersistentVector v)
+ (pv-reduce v f start end)
+ (ci-reduce coll f)))
+ (-reduce [coll f init]
+ (if (implements? APersistentVector v)
+ (pv-reduce v f init start end)
+ (ci-reduce coll f init)))
+
+ IKVReduce
+ (-kv-reduce [coll f init]
+ (loop [i start j 0 init init]
+ (if (< i end)
+ (let [init (f init j (-nth v i))]
+ (if (reduced? init)
+ @init
+ (recur (inc i) (inc j) init)))
+ init)))
+
+ IFn
+ (-invoke [coll k]
+ (-nth coll k))
+ (-invoke [coll k not-found]
+ (-nth coll k not-found))
+
+ IIterable
+ (-iterator [coll]
+ (if (implements? APersistentVector v)
+ (ranged-iterator v start end)
+ (seq-iter coll))))
+
+(es6-iterable Subvec)
+
+(defn- build-subvec [meta v start end __hash]
+ (if (instance? Subvec v)
+ (recur meta (.-v v) (+ (.-start v) start) (+ (.-start v) end) __hash)
+ (do
+ (when-not (vector? v)
+ (throw (js/Error. "v must satisfy IVector")))
+ (let [c (count v)]
+ (when (or (neg? start)
+ (neg? end)
+ (> start c)
+ (> end c))
+ (throw (js/Error. "Index out of bounds"))))
+ (Subvec. meta v start end __hash))))
+
+(defn subvec
+ "Returns a persistent vector of the items in vector from
+ start (inclusive) to end (exclusive). If end is not supplied,
+ defaults to (count vector). This operation is O(1) and very fast, as
+ the resulting vector shares structure with the original and no
+ trimming is done."
+ ([v start]
+ (subvec v start (count v)))
+ ([v start end]
+ (assert (and (not (nil? start)) (not (nil? end))))
+ (build-subvec nil v (int start) (int end) nil)))
+
+(defn- tv-ensure-editable [edit node]
+ (if (identical? edit (.-edit node))
+ node
+ (VectorNode. edit (aclone (.-arr node)))))
+
+(defn- tv-editable-root [node]
+ (VectorNode. (js-obj) (aclone (.-arr node))))
+
+(defn- tv-editable-tail [tl]
+ (let [ret (make-array 32)]
+ (array-copy tl 0 ret 0 (alength tl))
+ ret))
+
+(defn- tv-push-tail [tv level parent tail-node]
+ (let [ret (tv-ensure-editable (.. tv -root -edit) parent)
+ subidx (bit-and (bit-shift-right-zero-fill (dec (.-cnt tv)) level) 0x01f)]
+ (pv-aset ret subidx
+ (if (== level 5)
+ tail-node
+ (let [child (pv-aget ret subidx)]
+ (if-not (nil? child)
+ (tv-push-tail tv (- level 5) child tail-node)
+ (new-path (.. tv -root -edit) (- level 5) tail-node)))))
+ ret))
+
+(defn- tv-pop-tail [tv level node]
+ (let [node (tv-ensure-editable (.. tv -root -edit) node)
+ subidx (bit-and (bit-shift-right-zero-fill (- (.-cnt tv) 2) level) 0x01f)]
+ (cond
+ (> level 5) (let [new-child (tv-pop-tail
+ tv (- level 5) (pv-aget node subidx))]
+ (if (and (nil? new-child) (zero? subidx))
+ nil
+ (do (pv-aset node subidx new-child)
+ node)))
+ (zero? subidx) nil
+ :else (do (pv-aset node subidx nil)
+ node))))
+
+(defn- unchecked-editable-array-for [tv i]
+ ;; invariant: i is a valid index of tv.
+ (if (>= i (tail-off tv))
+ (.-tail tv)
+ (let [root (.-root tv)]
+ (loop [node root
+ level (.-shift tv)]
+ (if (pos? level)
+ (recur (tv-ensure-editable
+ (.-edit root)
+ (pv-aget node
+ (bit-and (bit-shift-right-zero-fill i level)
+ 0x01f)))
+ (- level 5))
+ (.-arr node))))))
+
+(deftype TransientVector [^:mutable cnt
+ ^:mutable shift
+ ^:mutable root
+ ^:mutable tail]
+ ITransientCollection
+ (-conj! [tcoll o]
+ (if ^boolean (.-edit root)
+ (if (< (- cnt (tail-off tcoll)) 32)
+ (do (aset tail (bit-and cnt 0x01f) o)
+ (set! cnt (inc cnt))
+ tcoll)
+ (let [tail-node (VectorNode. (.-edit root) tail)
+ new-tail (make-array 32)]
+ (aset new-tail 0 o)
+ (set! tail new-tail)
+ (if (> (bit-shift-right-zero-fill cnt 5)
+ (bit-shift-left 1 shift))
+ (let [new-root-array (make-array 32)
+ new-shift (+ shift 5)]
+ (aset new-root-array 0 root)
+ (aset new-root-array 1 (new-path (.-edit root) shift tail-node))
+ (set! root (VectorNode. (.-edit root) new-root-array))
+ (set! shift new-shift)
+ (set! cnt (inc cnt))
+ tcoll)
+ (let [new-root (tv-push-tail tcoll shift root tail-node)]
+ (set! root new-root)
+ (set! cnt (inc cnt))
+ tcoll))))
+ (throw (js/Error. "conj! after persistent!"))))
+
+ (-persistent! [tcoll]
+ (if ^boolean (.-edit root)
+ (do (set! (.-edit root) nil)
+ (let [len (- cnt (tail-off tcoll))
+ trimmed-tail (make-array len)]
+ (array-copy tail 0 trimmed-tail 0 len)
+ (PersistentVector. nil cnt shift root trimmed-tail nil)))
+ (throw (js/Error. "persistent! called twice"))))
+
+ ITransientAssociative
+ (-assoc! [tcoll key val]
+ (if (number? key)
+ (-assoc-n! tcoll key val)
+ (throw (js/Error. "TransientVector's key for assoc! must be a number."))))
+
+ ITransientVector
+ (-assoc-n! [tcoll n val]
+ (if ^boolean (.-edit root)
+ (cond
+ (and (<= 0 n) (< n cnt))
+ (if (<= (tail-off tcoll) n)
+ (do (aset tail (bit-and n 0x01f) val)
+ tcoll)
+ (let [new-root
+ ((fn go [level node]
+ (let [node (tv-ensure-editable (.-edit root) node)]
+ (if (zero? level)
+ (do (pv-aset node (bit-and n 0x01f) val)
+ node)
+ (let [subidx (bit-and (bit-shift-right-zero-fill n level)
+ 0x01f)]
+ (pv-aset node subidx
+ (go (- level 5) (pv-aget node subidx)))
+ node))))
+ shift root)]
+ (set! root new-root)
+ tcoll))
+ (== n cnt) (-conj! tcoll val)
+ :else
+ (throw
+ (js/Error.
+ (str "Index " n " out of bounds for TransientVector of length" cnt))))
+ (throw (js/Error. "assoc! after persistent!"))))
+
+ (-pop! [tcoll]
+ (if ^boolean (.-edit root)
+ (cond
+ (zero? cnt) (throw (js/Error. "Can't pop empty vector"))
+ (== 1 cnt) (do (set! cnt 0) tcoll)
+ (pos? (bit-and (dec cnt) 0x01f)) (do (set! cnt (dec cnt)) tcoll)
+ :else
+ (let [new-tail (unchecked-editable-array-for tcoll (- cnt 2))
+ new-root (let [nr (tv-pop-tail tcoll shift root)]
+ (if-not (nil? nr)
+ nr
+ (VectorNode. (.-edit root) (make-array 32))))]
+ (if (and (< 5 shift) (nil? (pv-aget new-root 1)))
+ (let [new-root (tv-ensure-editable (.-edit root) (pv-aget new-root 0))]
+ (set! root new-root)
+ (set! shift (- shift 5))
+ (set! cnt (dec cnt))
+ (set! tail new-tail)
+ tcoll)
+ (do (set! root new-root)
+ (set! cnt (dec cnt))
+ (set! tail new-tail)
+ tcoll))))
+ (throw (js/Error. "pop! after persistent!"))))
+
+ ICounted
+ (-count [coll]
+ (if ^boolean (.-edit root)
+ cnt
+ (throw (js/Error. "count after persistent!"))))
+
+ IIndexed
+ (-nth [coll n]
+ (if ^boolean (.-edit root)
+ (aget (array-for coll n) (bit-and n 0x01f))
+ (throw (js/Error. "nth after persistent!"))))
+
+ (-nth [coll n not-found]
+ (if (and (<= 0 n) (< n cnt))
+ (-nth coll n)
+ not-found))
+
+ ILookup
+ (-lookup [coll k] (-lookup coll k nil))
+
+ (-lookup [coll k not-found] (if (number? k)
+ (-nth coll k not-found)
+ not-found))
+
+ IFn
+ (-invoke [coll k]
+ (-lookup coll k))
+
+ (-invoke [coll k not-found]
+ (-lookup coll k not-found)))
+
+;;; PersistentQueue ;;;
+
+(deftype PersistentQueueIter [^:mutable fseq riter]
+ Object
+ (hasNext [_]
+ (or (and (some? fseq) (seq fseq)) (and (some? riter) (.hasNext riter))))
+ (next [_]
+ (cond
+ (some? fseq)
+ (let [ret (first fseq)]
+ (set! fseq (next fseq))
+ ret)
+ (and (some? riter) ^boolean (.hasNext riter))
+ (.next riter)
+ :else (throw (js/Error. "No such element"))))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+(deftype PersistentQueueSeq [meta front rear ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IWithMeta
+ (-with-meta [coll meta] (PersistentQueueSeq. meta front rear __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ISeq
+ (-first [coll] (first front))
+ (-rest [coll]
+ (if-let [f1 (next front)]
+ (PersistentQueueSeq. meta f1 rear nil)
+ (if (nil? rear)
+ (-empty coll)
+ (PersistentQueueSeq. meta rear nil nil))))
+
+ INext
+ (-next [coll]
+ (if-let [f1 (next front)]
+ (PersistentQueueSeq. meta f1 rear nil)
+ (when (some? rear)
+ (PersistentQueueSeq. meta rear nil nil))))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ ISeqable
+ (-seq [coll] coll))
+
+(es6-iterable PersistentQueueSeq)
+
+(deftype PersistentQueue [meta count front rear ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ ICloneable
+ (-clone [coll] (PersistentQueue. meta count front rear __hash))
+
+ IIterable
+ (-iterator [coll]
+ (PersistentQueueIter. front (-iterator rear)))
+
+ IWithMeta
+ (-with-meta [coll meta] (PersistentQueue. meta count front rear __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ISeq
+ (-first [coll] (first front))
+ (-rest [coll] (rest (seq coll)))
+
+ IStack
+ (-peek [coll] (first front))
+ (-pop [coll]
+ (if front
+ (if-let [f1 (next front)]
+ (PersistentQueue. meta (dec count) f1 rear nil)
+ (PersistentQueue. meta (dec count) (seq rear) [] nil))
+ coll))
+
+ ICollection
+ (-conj [coll o]
+ (if front
+ (PersistentQueue. meta (inc count) front (conj (or rear []) o) nil)
+ (PersistentQueue. meta (inc count) (conj front o) [] nil)))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY PersistentQueue) meta))
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ ISeqable
+ (-seq [coll]
+ (let [rear (seq rear)]
+ (if (or front rear)
+ (PersistentQueueSeq. nil front (seq rear) nil))))
+
+ ICounted
+ (-count [coll] count))
+
+(set! (.-EMPTY PersistentQueue) (PersistentQueue. nil 0 nil [] empty-ordered-hash))
+
+(es6-iterable PersistentQueue)
+
+(deftype NeverEquiv []
+ Object
+ (equiv [this other]
+ (-equiv this other))
+ IEquiv
+ (-equiv [o other] false))
+
+(def ^:private never-equiv (NeverEquiv.))
+
+(defn ^boolean equiv-map
+ "Test map equivalence. Returns true if x equals y, otherwise returns false."
+ [x y]
+ (boolean
+ (when (and (map? y) (not (record? y)))
+ ; assume all maps are counted
+ (when (== (count x) (count y))
+ (if (satisfies? IKVReduce x)
+ (reduce-kv
+ (fn [_ k v]
+ (if (= (get y k never-equiv) v)
+ true
+ (reduced false)))
+ true x)
+ (every?
+ (fn [xkv]
+ (= (get y (first xkv) never-equiv) (second xkv)))
+ x))))))
+
+
+(defn- scan-array [incr k array]
+ (let [len (alength array)]
+ (loop [i 0]
+ (when (< i len)
+ (if (identical? k (aget array i))
+ i
+ (recur (+ i incr)))))))
+
+; The keys field is an array of all keys of this map, in no particular
+; order. Any string, keyword, or symbol key is used as a property name
+; to store the value in strobj. If a key is assoc'ed when that same
+; key already exists in strobj, the old value is overwritten. If a
+; non-string key is assoc'ed, return a HashMap object instead.
+
+(defn- obj-map-compare-keys [a b]
+ (let [a (hash a)
+ b (hash b)]
+ (cond
+ (< a b) -1
+ (> a b) 1
+ :else 0)))
+
+(defn- obj-map->hash-map [m k v]
+ (let [ks (.-keys m)
+ len (alength ks)
+ so (.-strobj m)
+ mm (meta m)]
+ (loop [i 0
+ out (transient (.-EMPTY PersistentHashMap))]
+ (if (< i len)
+ (let [k (aget ks i)]
+ (recur (inc i) (assoc! out k (gobject/get so k))))
+ (-with-meta (persistent! (assoc! out k v)) mm)))))
+
+;;; ObjMap - DEPRECATED
+
+(defn- obj-clone [obj ks]
+ (let [new-obj (js-obj)
+ l (alength ks)]
+ (loop [i 0]
+ (when (< i l)
+ (let [k (aget ks i)]
+ (gobject/set new-obj k (gobject/get obj k))
+ (recur (inc i)))))
+ new-obj))
+
+(deftype ObjMap [meta keys strobj update-count ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+
+ IWithMeta
+ (-with-meta [coll meta] (ObjMap. meta keys strobj update-count __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ICollection
+ (-conj [coll entry]
+ (if (vector? entry)
+ (-assoc coll (-nth entry 0) (-nth entry 1))
+ (reduce -conj
+ coll
+ entry)))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY ObjMap) meta))
+
+ IEquiv
+ (-equiv [coll other] (equiv-map coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-unordered-coll __hash))
+
+ ISeqable
+ (-seq [coll]
+ (when (pos? (alength keys))
+ (map #(vector % (unchecked-get strobj %))
+ (.sort keys obj-map-compare-keys))))
+
+ ICounted
+ (-count [coll] (alength keys))
+
+ ILookup
+ (-lookup [coll k] (-lookup coll k nil))
+ (-lookup [coll k not-found]
+ (if (and ^boolean (goog/isString k)
+ (not (nil? (scan-array 1 k keys))))
+ (unchecked-get strobj k)
+ not-found))
+
+ IAssociative
+ (-assoc [coll k v]
+ (if ^boolean (goog/isString k)
+ (if (or (> update-count (.-HASHMAP_THRESHOLD ObjMap))
+ (>= (alength keys) (.-HASHMAP_THRESHOLD ObjMap)))
+ (obj-map->hash-map coll k v)
+ (if-not (nil? (scan-array 1 k keys))
+ (let [new-strobj (obj-clone strobj keys)]
+ (gobject/set new-strobj k v)
+ (ObjMap. meta keys new-strobj (inc update-count) nil)) ; overwrite
+ (let [new-strobj (obj-clone strobj keys) ; append
+ new-keys (aclone keys)]
+ (gobject/set new-strobj k v)
+ (.push new-keys k)
+ (ObjMap. meta new-keys new-strobj (inc update-count) nil))))
+ ;; non-string key. game over.
+ (obj-map->hash-map coll k v)))
+ (-contains-key? [coll k]
+ (if (and ^boolean (goog/isString k)
+ (not (nil? (scan-array 1 k keys))))
+ true
+ false))
+
+ IFind
+ (-find [coll k]
+ (when (and ^boolean (goog/isString k)
+ (not (nil? (scan-array 1 k keys))))
+ (MapEntry. k (unchecked-get strobj k) nil)))
+
+ IKVReduce
+ (-kv-reduce [coll f init]
+ (let [len (alength keys)]
+ (loop [keys (.sort keys obj-map-compare-keys)
+ init init]
+ (if (seq keys)
+ (let [k (first keys)
+ init (f init k (unchecked-get strobj k))]
+ (if (reduced? init)
+ @init
+ (recur (rest keys) init)))
+ init))))
+
+ IMap
+ (-dissoc [coll k]
+ (if (and ^boolean (goog/isString k)
+ (not (nil? (scan-array 1 k keys))))
+ (let [new-keys (aclone keys)
+ new-strobj (obj-clone strobj keys)]
+ (.splice new-keys (scan-array 1 k new-keys) 1)
+ (js-delete new-strobj k)
+ (ObjMap. meta new-keys new-strobj (inc update-count) nil))
+ coll)) ; key not found, return coll unchanged
+
+ IFn
+ (-invoke [coll k]
+ (-lookup coll k))
+ (-invoke [coll k not-found]
+ (-lookup coll k not-found))
+
+ IEditableCollection
+ (-as-transient [coll]
+ (transient (into (hash-map) coll))))
+
+(set! (.-EMPTY ObjMap) (ObjMap. nil (array) (js-obj) 0 empty-unordered-hash))
+
+(set! (.-HASHMAP_THRESHOLD ObjMap) 8)
+
+(set! (.-fromObject ObjMap) (fn [ks obj] (ObjMap. nil ks obj 0 nil)))
+
+;; Record Iterator
+(deftype RecordIter [^:mutable i record base-count fields ext-map-iter]
+ Object
+ (hasNext [_]
+ (or (< i base-count) (.hasNext ext-map-iter)))
+ (next [_]
+ (if (< i base-count)
+ (let [k (nth fields i)]
+ (set! i (inc i))
+ (MapEntry. k (-lookup record k) nil))
+ (.next ext-map-iter)))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+;; EXPERIMENTAL: subject to change
+(deftype ES6EntriesIterator [^:mutable s]
+ Object
+ (next [_]
+ (if-not (nil? s)
+ (let [[k v] (first s)]
+ (set! s (next s))
+ #js {:value #js [k v] :done false})
+ #js {:value nil :done true})))
+
+(defn es6-entries-iterator [coll]
+ (ES6EntriesIterator. (seq coll)))
+
+;; EXPERIMENTAL: subject to change
+(deftype ES6SetEntriesIterator [^:mutable s]
+ Object
+ (next [_]
+ (if-not (nil? s)
+ (let [x (first s)]
+ (set! s (next s))
+ #js {:value #js [x x] :done false})
+ #js {:value nil :done true})))
+
+(defn es6-set-entries-iterator [coll]
+ (ES6SetEntriesIterator. (seq coll)))
+
+;;; PersistentArrayMap
+
+(defn- array-index-of-nil? [arr]
+ (let [len (alength arr)]
+ (loop [i 0]
+ (cond
+ (<= len i) -1
+ (nil? (aget arr i)) i
+ :else (recur (+ i 2))))))
+
+(defn- array-index-of-keyword? [arr k]
+ (let [len (alength arr)
+ kstr (.-fqn k)]
+ (loop [i 0]
+ (cond
+ (<= len i) -1
+ (and (keyword? (aget arr i))
+ (identical? kstr (.-fqn (aget arr i)))) i
+ :else (recur (+ i 2))))))
+
+(defn- array-index-of-symbol? [arr k]
+ (let [len (alength arr)
+ kstr (.-str k)]
+ (loop [i 0]
+ (cond
+ (<= len i) -1
+ (and (symbol? (aget arr i))
+ (identical? kstr (.-str (aget arr i)))) i
+ :else (recur (+ i 2))))))
+
+(defn- array-index-of-identical? [arr k]
+ (let [len (alength arr)]
+ (loop [i 0]
+ (cond
+ (<= len i) -1
+ (identical? k (aget arr i)) i
+ :else (recur (+ i 2))))))
+
+(defn- array-index-of-equiv? [arr k]
+ (let [len (alength arr)]
+ (loop [i 0]
+ (cond
+ (<= len i) -1
+ (= k (aget arr i)) i
+ :else (recur (+ i 2))))))
+
+(defn array-index-of [arr k]
+ (cond
+ (keyword? k) (array-index-of-keyword? arr k)
+
+ (or ^boolean (goog/isString k) (number? k))
+ (array-index-of-identical? arr k)
+
+ (symbol? k) (array-index-of-symbol? arr k)
+
+ (nil? k)
+ (array-index-of-nil? arr)
+
+ :else (array-index-of-equiv? arr k)))
+
+(defn- array-map-index-of [m k]
+ (array-index-of (.-arr m) k))
+
+(defn- array-extend-kv [arr k v]
+ (let [l (alength arr)
+ narr (make-array (+ l 2))]
+ (loop [i 0]
+ (when (< i l)
+ (aset narr i (aget arr i))
+ (recur (inc i))))
+ (aset narr l k)
+ (aset narr (inc l) v)
+ narr))
+
+(defn- array-map-extend-kv [m k v]
+ (array-extend-kv (.-arr m) k v))
+
+(declare TransientArrayMap)
+
+(deftype MapEntry [key val ^:mutable __hash]
+ Object
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IMapEntry
+ (-key [node] key)
+ (-val [node] val)
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IMeta
+ (-meta [node] nil)
+
+ IWithMeta
+ (-with-meta [node meta]
+ (with-meta [key val] meta))
+
+ IStack
+ (-peek [node] val)
+
+ (-pop [node] [key])
+
+ ICollection
+ (-conj [node o] [key val o])
+
+ IEmptyableCollection
+ (-empty [node] nil)
+
+ ISequential
+ ISeqable
+ (-seq [node] (IndexedSeq. #js [key val] 0 nil))
+
+ IReversible
+ (-rseq [node] (IndexedSeq. #js [val key] 0 nil))
+
+ ICounted
+ (-count [node] 2)
+
+ IIndexed
+ (-nth [node n]
+ (cond (== n 0) key
+ (== n 1) val
+ :else (throw (js/Error. "Index out of bounds"))))
+
+ (-nth [node n not-found]
+ (cond (== n 0) key
+ (== n 1) val
+ :else not-found))
+
+ ILookup
+ (-lookup [node k] (-nth node k nil))
+ (-lookup [node k not-found] (-nth node k not-found))
+
+ IAssociative
+ (-assoc [node k v]
+ (assoc [key val] k v))
+ (-contains-key? [node k]
+ (or (== k 0) (== k 1)))
+
+ IFind
+ (-find [node k]
+ (case k
+ 0 (MapEntry. 0 key nil)
+ 1 (MapEntry. 1 val nil)
+ nil))
+
+ IVector
+ (-assoc-n [node n v]
+ (-assoc-n [key val] n v))
+
+ IReduce
+ (-reduce [node f]
+ (ci-reduce node f))
+
+ (-reduce [node f start]
+ (ci-reduce node f start))
+
+ IFn
+ (-invoke [node k]
+ (-nth node k))
+
+ (-invoke [node k not-found]
+ (-nth node k not-found)))
+
+(defn ^boolean map-entry?
+ "Returns true if x satisfies IMapEntry"
+ [x]
+ (implements? IMapEntry x))
+
+(deftype PersistentArrayMapSeq [arr i _meta]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IMeta
+ (-meta [coll] _meta)
+
+ IWithMeta
+ (-with-meta [coll new-meta]
+ (PersistentArrayMapSeq. arr i new-meta))
+
+ ICounted
+ (-count [coll]
+ (/ (- (alength arr) i) 2))
+
+ ISeqable
+ (-seq [coll] coll)
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ ICollection
+ (-conj [coll o]
+ (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) _meta))
+
+ IHash
+ (-hash [coll] (hash-ordered-coll coll))
+
+ ISeq
+ (-first [coll]
+ (MapEntry. (aget arr i) (aget arr (inc i)) nil))
+
+ (-rest [coll]
+ (if (< i (- (alength arr) 2))
+ (PersistentArrayMapSeq. arr (+ i 2) _meta)
+ ()))
+
+ INext
+ (-next [coll]
+ (when (< i (- (alength arr) 2))
+ (PersistentArrayMapSeq. arr (+ i 2) _meta)))
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(es6-iterable PersistentArrayMapSeq)
+
+(defn persistent-array-map-seq [arr i _meta]
+ (when (<= i (- (alength arr) 2))
+ (PersistentArrayMapSeq. arr i _meta)))
+
+(declare keys vals)
+
+(deftype PersistentArrayMapIterator [arr ^:mutable i cnt]
+ Object
+ (hasNext [_]
+ (< i cnt))
+ (next [_]
+ (let [ret (MapEntry. (aget arr i) (aget arr (inc i)) nil)]
+ (set! i (+ i 2))
+ ret)))
+
+(deftype PersistentArrayMap [meta cnt arr ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+
+ ;; EXPERIMENTAL: subject to change
+ (keys [coll]
+ (es6-iterator (keys coll)))
+ (entries [coll]
+ (es6-entries-iterator (seq coll)))
+ (values [coll]
+ (es6-iterator (vals coll)))
+ (has [coll k]
+ (contains? coll k))
+ (get [coll k not-found]
+ (-lookup coll k not-found))
+ (forEach [coll f]
+ (doseq [[k v] coll]
+ (f v k)))
+
+ ICloneable
+ (-clone [_] (PersistentArrayMap. meta cnt arr __hash))
+
+ IWithMeta
+ (-with-meta [coll meta] (PersistentArrayMap. meta cnt arr __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ICollection
+ (-conj [coll entry]
+ (if (vector? entry)
+ (-assoc coll (-nth entry 0) (-nth entry 1))
+ (loop [ret coll es (seq entry)]
+ (if (nil? es)
+ ret
+ (let [e (first es)]
+ (if (vector? e)
+ (recur (-assoc ret (-nth e 0) (-nth e 1))
+ (next es))
+ (throw (js/Error. "conj on a map takes map entries or seqables of map entries"))))))))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY PersistentArrayMap) meta))
+
+ IEquiv
+ (-equiv [coll other]
+ (if (and (map? other) (not (record? other)))
+ (let [alen (alength arr)
+ ^not-native other other]
+ (if (== cnt (-count other))
+ (loop [i 0]
+ (if (< i alen)
+ (let [v (-lookup other (aget arr i) lookup-sentinel)]
+ (if-not (identical? v lookup-sentinel)
+ (if (= (aget arr (inc i)) v)
+ (recur (+ i 2))
+ false)
+ false))
+ true))
+ false))
+ false))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-unordered-coll __hash))
+
+ IIterable
+ (-iterator [this]
+ (PersistentArrayMapIterator. arr 0 (* cnt 2)))
+
+ ISeqable
+ (-seq [coll]
+ (persistent-array-map-seq arr 0 nil))
+
+ ICounted
+ (-count [coll] cnt)
+
+ ILookup
+ (-lookup [coll k]
+ (-lookup coll k nil))
+
+ (-lookup [coll k not-found]
+ (let [idx (array-map-index-of coll k)]
+ (if (== idx -1)
+ not-found
+ (aget arr (inc idx)))))
+
+ IAssociative
+ (-assoc [coll k v]
+ (let [idx (array-map-index-of coll k)]
+ (cond
+ (== idx -1)
+ (if (< cnt (.-HASHMAP-THRESHOLD PersistentArrayMap))
+ (let [arr (array-map-extend-kv coll k v)]
+ (PersistentArrayMap. meta (inc cnt) arr nil))
+ (-> (into (.-EMPTY PersistentHashMap) coll)
+ (-assoc k v)
+ (-with-meta meta)))
+
+ (identical? v (aget arr (inc idx)))
+ coll
+
+ :else
+ (let [arr (doto (aclone arr)
+ (aset (inc idx) v))]
+ (PersistentArrayMap. meta cnt arr nil)))))
+
+ (-contains-key? [coll k]
+ (not (== (array-map-index-of coll k) -1)))
+
+ IFind
+ (-find [coll k]
+ (let [idx (array-map-index-of coll k)]
+ (when-not (== idx -1)
+ (MapEntry. (aget arr idx) (aget arr (inc idx)) nil))))
+
+ IMap
+ (-dissoc [coll k]
+ (let [idx (array-map-index-of coll k)]
+ (if (>= idx 0)
+ (let [len (alength arr)
+ new-len (- len 2)]
+ (if (zero? new-len)
+ (-empty coll)
+ (let [new-arr (make-array new-len)]
+ (loop [s 0 d 0]
+ (cond
+ (>= s len) (PersistentArrayMap. meta (dec cnt) new-arr nil)
+ (= k (aget arr s)) (recur (+ s 2) d)
+ :else (do (aset new-arr d (aget arr s))
+ (aset new-arr (inc d) (aget arr (inc s)))
+ (recur (+ s 2) (+ d 2))))))))
+ coll)))
+
+ IKVReduce
+ (-kv-reduce [coll f init]
+ (let [len (alength arr)]
+ (loop [i 0 init init]
+ (if (< i len)
+ (let [init (f init (aget arr i) (aget arr (inc i)))]
+ (if (reduced? init)
+ @init
+ (recur (+ i 2) init)))
+ init))))
+
+ IReduce
+ (-reduce [coll f]
+ (iter-reduce coll f))
+ (-reduce [coll f start]
+ (iter-reduce coll f start))
+
+ IFn
+ (-invoke [coll k]
+ (-lookup coll k))
+
+ (-invoke [coll k not-found]
+ (-lookup coll k not-found))
+
+ IEditableCollection
+ (-as-transient [coll]
+ (TransientArrayMap. (js-obj) (alength arr) (aclone arr))))
+
+(set! (.-EMPTY PersistentArrayMap) (PersistentArrayMap. nil 0 (array) empty-unordered-hash))
+
+(set! (.-HASHMAP-THRESHOLD PersistentArrayMap) 8)
+
+(set! (.-fromArray PersistentArrayMap)
+ (fn [arr ^boolean no-clone ^boolean no-check]
+ (as-> (if no-clone arr (aclone arr)) arr
+ (if no-check
+ arr
+ (let [ret (array)]
+ (loop [i 0]
+ (when (< i (alength arr))
+ (let [k (aget arr i)
+ v (aget arr (inc i))
+ idx (array-index-of ret k)]
+ (when (== idx -1)
+ (.push ret k)
+ (.push ret v)))
+ (recur (+ i 2))))
+ ret))
+ (let [cnt (/ (alength arr) 2)]
+ (PersistentArrayMap. nil cnt arr nil)))))
+
+(set! (.-createWithCheck PersistentArrayMap)
+ (fn [arr]
+ (let [ret (array)]
+ (loop [i 0]
+ (when (< i (alength arr))
+ (let [k (aget arr i)
+ v (aget arr (inc i))
+ idx (array-index-of ret k)]
+ (if (== idx -1)
+ (doto ret (.push k) (.push v))
+ (throw (js/Error. (str "Duplicate key: " k)))))
+ (recur (+ i 2))))
+ (let [cnt (/ (alength arr) 2)]
+ (PersistentArrayMap. nil cnt arr nil)))))
+
+(set! (.-createAsIfByAssoc PersistentArrayMap)
+ (fn [arr]
+ (let [ret (array)]
+ (loop [i 0]
+ (when (< i (alength arr))
+ (let [k (aget arr i)
+ v (aget arr (inc i))
+ idx (array-index-of ret k)]
+ (if (== idx -1)
+ (doto ret (.push k) (.push v))
+ (aset ret (inc idx) v)))
+ (recur (+ i 2))))
+ (PersistentArrayMap. nil (/ (alength ret) 2) ret nil))))
+
+(es6-iterable PersistentArrayMap)
+
+(declare array->transient-hash-map)
+
+(deftype TransientArrayMap [^:mutable editable?
+ ^:mutable len
+ arr]
+ ICounted
+ (-count [tcoll]
+ (if editable?
+ (quot len 2)
+ (throw (js/Error. "count after persistent!"))))
+
+ ILookup
+ (-lookup [tcoll k]
+ (-lookup tcoll k nil))
+
+ (-lookup [tcoll k not-found]
+ (if editable?
+ (let [idx (array-map-index-of tcoll k)]
+ (if (== idx -1)
+ not-found
+ (aget arr (inc idx))))
+ (throw (js/Error. "lookup after persistent!"))))
+
+ ITransientCollection
+ (-conj! [tcoll o]
+ (if editable?
+ (cond
+ (map-entry? o)
+ (-assoc! tcoll (key o) (val o))
+
+ (vector? o)
+ (-assoc! tcoll (o 0) (o 1))
+
+ :else
+ (loop [es (seq o) tcoll tcoll]
+ (if-let [e (first es)]
+ (recur (next es)
+ (-assoc! tcoll (key e) (val e)))
+ tcoll)))
+ (throw (js/Error. "conj! after persistent!"))))
+
+ (-persistent! [tcoll]
+ (if editable?
+ (do (set! editable? false)
+ (PersistentArrayMap. nil (quot len 2) arr nil))
+ (throw (js/Error. "persistent! called twice"))))
+
+ ITransientAssociative
+ (-assoc! [tcoll key val]
+ (if editable?
+ (let [idx (array-map-index-of tcoll key)]
+ (if (== idx -1)
+ (if (<= (+ len 2) (* 2 (.-HASHMAP-THRESHOLD PersistentArrayMap)))
+ (do (set! len (+ len 2))
+ (.push arr key)
+ (.push arr val)
+ tcoll)
+ (assoc! (array->transient-hash-map len arr) key val))
+ (if (identical? val (aget arr (inc idx)))
+ tcoll
+ (do (aset arr (inc idx) val)
+ tcoll))))
+ (throw (js/Error. "assoc! after persistent!"))))
+
+ ITransientMap
+ (-dissoc! [tcoll key]
+ (if editable?
+ (let [idx (array-map-index-of tcoll key)]
+ (when (>= idx 0)
+ (aset arr idx (aget arr (- len 2)))
+ (aset arr (inc idx) (aget arr (dec len)))
+ (doto arr .pop .pop)
+ (set! len (- len 2)))
+ tcoll)
+ (throw (js/Error. "dissoc! after persistent!"))))
+
+ IFn
+ (-invoke [tcoll key]
+ (-lookup tcoll key nil))
+ (-invoke [tcoll key not-found]
+ (-lookup tcoll key not-found)))
+
+(declare TransientHashMap)
+
+(defn- array->transient-hash-map [len arr]
+ (loop [out (transient (.-EMPTY PersistentHashMap))
+ i 0]
+ (if (< i len)
+ (recur (assoc! out (aget arr i) (aget arr (inc i))) (+ i 2))
+ out)))
+
+;;; PersistentHashMap
+
+(deftype Box [^:mutable val])
+
+(declare create-inode-seq create-array-node-seq reset! create-node atom deref)
+
+(defn ^boolean key-test [key other]
+ (cond
+ (identical? key other) true
+ (keyword-identical? key other) true
+ :else (= key other)))
+
+(defn- mask [hash shift]
+ (bit-and (bit-shift-right-zero-fill hash shift) 0x01f))
+
+(defn- clone-and-set
+ ([arr i a]
+ (doto (aclone arr)
+ (aset i a)))
+ ([arr i a j b]
+ (doto (aclone arr)
+ (aset i a)
+ (aset j b))))
+
+(defn- remove-pair [arr i]
+ (let [new-arr (make-array (- (alength arr) 2))]
+ (array-copy arr 0 new-arr 0 (* 2 i))
+ (array-copy arr (* 2 (inc i)) new-arr (* 2 i) (- (alength new-arr) (* 2 i)))
+ new-arr))
+
+(defn- bitmap-indexed-node-index [bitmap bit]
+ (bit-count (bit-and bitmap (dec bit))))
+
+(defn- bitpos [hash shift]
+ (bit-shift-left 1 (mask hash shift)))
+
+(defn- edit-and-set
+ ([inode edit i a]
+ (let [editable (.ensure-editable inode edit)]
+ (aset (.-arr editable) i a)
+ editable))
+ ([inode edit i a j b]
+ (let [editable (.ensure-editable inode edit)]
+ (aset (.-arr editable) i a)
+ (aset (.-arr editable) j b)
+ editable)))
+
+(defn- inode-kv-reduce [arr f init]
+ (let [len (alength arr)]
+ (loop [i 0 init init]
+ (if (< i len)
+ (let [init (let [k (aget arr i)]
+ (if-not (nil? k)
+ (f init k (aget arr (inc i)))
+ (let [node (aget arr (inc i))]
+ (if-not (nil? node)
+ (.kv-reduce node f init)
+ init))))]
+ (if (reduced? init)
+ init
+ (recur (+ i 2) init)))
+ init))))
+
+(declare ArrayNode)
+
+ (deftype NodeIterator [arr ^:mutable i ^:mutable next-entry ^:mutable next-iter]
+ Object
+ (advance [this]
+ (let [len (alength arr)]
+ (loop []
+ (if (< i len)
+ (let [key (aget arr i)
+ node-or-val (aget arr (inc i))
+ ^boolean found
+ (cond (some? key)
+ (set! next-entry (MapEntry. key node-or-val nil))
+ (some? node-or-val)
+ (let [new-iter (-iterator node-or-val)]
+ (if ^boolean (.hasNext new-iter)
+ (set! next-iter new-iter)
+ false))
+ :else false)]
+ (set! i (+ i 2))
+ (if found true (recur)))
+ false))))
+ (hasNext [this]
+ (or (some? next-entry) (some? next-iter) (.advance this)))
+ (next [this]
+ (cond
+ (some? next-entry)
+ (let [ret next-entry]
+ (set! next-entry nil)
+ ret)
+ (some? next-iter)
+ (let [ret (.next next-iter)]
+ (when-not ^boolean (.hasNext next-iter)
+ (set! next-iter nil))
+ ret)
+ ^boolean (.advance this)
+ (.next this)
+ :else (throw (js/Error. "No such element"))))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+(deftype BitmapIndexedNode [edit ^:mutable bitmap ^:mutable arr]
+ Object
+ (inode-assoc [inode shift hash key val added-leaf?]
+ (let [bit (bitpos hash shift)
+ idx (bitmap-indexed-node-index bitmap bit)]
+ (if (zero? (bit-and bitmap bit))
+ (let [n (bit-count bitmap)]
+ (if (>= n 16)
+ (let [nodes (make-array 32)
+ jdx (mask hash shift)]
+ (aset nodes jdx (.inode-assoc (.-EMPTY BitmapIndexedNode) (+ shift 5) hash key val added-leaf?))
+ (loop [i 0 j 0]
+ (if (< i 32)
+ (if (zero? (bit-and (bit-shift-right-zero-fill bitmap i) 1))
+ (recur (inc i) j)
+ (do (aset nodes i
+ (if-not (nil? (aget arr j))
+ (.inode-assoc (.-EMPTY BitmapIndexedNode)
+ (+ shift 5) (cljs.core/hash (aget arr j)) (aget arr j) (aget arr (inc j)) added-leaf?)
+ (aget arr (inc j))))
+ (recur (inc i) (+ j 2))))))
+ (ArrayNode. nil (inc n) nodes))
+ (let [new-arr (make-array (* 2 (inc n)))]
+ (array-copy arr 0 new-arr 0 (* 2 idx))
+ (aset new-arr (* 2 idx) key)
+ (aset new-arr (inc (* 2 idx)) val)
+ (array-copy arr (* 2 idx) new-arr (* 2 (inc idx)) (* 2 (- n idx)))
+ (set! (.-val added-leaf?) true)
+ (BitmapIndexedNode. nil (bit-or bitmap bit) new-arr))))
+ (let [key-or-nil (aget arr (* 2 idx))
+ val-or-node (aget arr (inc (* 2 idx)))]
+ (cond (nil? key-or-nil)
+ (let [n (.inode-assoc val-or-node (+ shift 5) hash key val added-leaf?)]
+ (if (identical? n val-or-node)
+ inode
+ (BitmapIndexedNode. nil bitmap (clone-and-set arr (inc (* 2 idx)) n))))
+
+ (key-test key key-or-nil)
+ (if (identical? val val-or-node)
+ inode
+ (BitmapIndexedNode. nil bitmap (clone-and-set arr (inc (* 2 idx)) val)))
+
+ :else
+ (do (set! (.-val added-leaf?) true)
+ (BitmapIndexedNode. nil bitmap
+ (clone-and-set arr (* 2 idx) nil (inc (* 2 idx))
+ (create-node (+ shift 5) key-or-nil val-or-node hash key val)))))))))
+
+ (inode-without [inode shift hash key]
+ (let [bit (bitpos hash shift)]
+ (if (zero? (bit-and bitmap bit))
+ inode
+ (let [idx (bitmap-indexed-node-index bitmap bit)
+ key-or-nil (aget arr (* 2 idx))
+ val-or-node (aget arr (inc (* 2 idx)))]
+ (cond (nil? key-or-nil)
+ (let [n (.inode-without val-or-node (+ shift 5) hash key)]
+ (cond (identical? n val-or-node) inode
+ (not (nil? n)) (BitmapIndexedNode. nil bitmap (clone-and-set arr (inc (* 2 idx)) n))
+ (== bitmap bit) nil
+ :else (BitmapIndexedNode. nil (bit-xor bitmap bit) (remove-pair arr idx))))
+ (key-test key key-or-nil)
+ (BitmapIndexedNode. nil (bit-xor bitmap bit) (remove-pair arr idx))
+ :else inode)))))
+
+ (inode-lookup [inode shift hash key not-found]
+ (let [bit (bitpos hash shift)]
+ (if (zero? (bit-and bitmap bit))
+ not-found
+ (let [idx (bitmap-indexed-node-index bitmap bit)
+ key-or-nil (aget arr (* 2 idx))
+ val-or-node (aget arr (inc (* 2 idx)))]
+ (cond (nil? key-or-nil) (.inode-lookup val-or-node (+ shift 5) hash key not-found)
+ (key-test key key-or-nil) val-or-node
+ :else not-found)))))
+
+ (inode-find [inode shift hash key not-found]
+ (let [bit (bitpos hash shift)]
+ (if (zero? (bit-and bitmap bit))
+ not-found
+ (let [idx (bitmap-indexed-node-index bitmap bit)
+ key-or-nil (aget arr (* 2 idx))
+ val-or-node (aget arr (inc (* 2 idx)))]
+ (cond (nil? key-or-nil) (.inode-find val-or-node (+ shift 5) hash key not-found)
+ (key-test key key-or-nil) (MapEntry. key-or-nil val-or-node nil)
+ :else not-found)))))
+
+ (inode-seq [inode]
+ (create-inode-seq arr))
+
+ (ensure-editable [inode e]
+ (if (identical? e edit)
+ inode
+ (let [n (bit-count bitmap)
+ new-arr (make-array (if (neg? n) 4 (* 2 (inc n))))]
+ (array-copy arr 0 new-arr 0 (* 2 n))
+ (BitmapIndexedNode. e bitmap new-arr))))
+
+ (edit-and-remove-pair [inode e bit i]
+ (if (== bitmap bit)
+ nil
+ (let [editable (.ensure-editable inode e)
+ earr (.-arr editable)
+ len (alength earr)]
+ (set! (.-bitmap editable) (bit-xor bit (.-bitmap editable)))
+ (array-copy earr (* 2 (inc i))
+ earr (* 2 i)
+ (- len (* 2 (inc i))))
+ (aset earr (- len 2) nil)
+ (aset earr (dec len) nil)
+ editable)))
+
+ (inode-assoc! [inode edit shift hash key val added-leaf?]
+ (let [bit (bitpos hash shift)
+ idx (bitmap-indexed-node-index bitmap bit)]
+ (if (zero? (bit-and bitmap bit))
+ (let [n (bit-count bitmap)]
+ (cond
+ (< (* 2 n) (alength arr))
+ (let [editable (.ensure-editable inode edit)
+ earr (.-arr editable)]
+ (set! (.-val added-leaf?) true)
+ (array-copy-downward earr (* 2 idx)
+ earr (* 2 (inc idx))
+ (* 2 (- n idx)))
+ (aset earr (* 2 idx) key)
+ (aset earr (inc (* 2 idx)) val)
+ (set! (.-bitmap editable) (bit-or (.-bitmap editable) bit))
+ editable)
+
+ (>= n 16)
+ (let [nodes (make-array 32)
+ jdx (mask hash shift)]
+ (aset nodes jdx (.inode-assoc! (.-EMPTY BitmapIndexedNode) edit (+ shift 5) hash key val added-leaf?))
+ (loop [i 0 j 0]
+ (if (< i 32)
+ (if (zero? (bit-and (bit-shift-right-zero-fill bitmap i) 1))
+ (recur (inc i) j)
+ (do (aset nodes i
+ (if-not (nil? (aget arr j))
+ (.inode-assoc! (.-EMPTY BitmapIndexedNode)
+ edit (+ shift 5) (cljs.core/hash (aget arr j)) (aget arr j) (aget arr (inc j)) added-leaf?)
+ (aget arr (inc j))))
+ (recur (inc i) (+ j 2))))))
+ (ArrayNode. edit (inc n) nodes))
+
+ :else
+ (let [new-arr (make-array (* 2 (+ n 4)))]
+ (array-copy arr 0 new-arr 0 (* 2 idx))
+ (aset new-arr (* 2 idx) key)
+ (aset new-arr (inc (* 2 idx)) val)
+ (array-copy arr (* 2 idx) new-arr (* 2 (inc idx)) (* 2 (- n idx)))
+ (set! (.-val added-leaf?) true)
+ (let [editable (.ensure-editable inode edit)]
+ (set! (.-arr editable) new-arr)
+ (set! (.-bitmap editable) (bit-or (.-bitmap editable) bit))
+ editable))))
+ (let [key-or-nil (aget arr (* 2 idx))
+ val-or-node (aget arr (inc (* 2 idx)))]
+ (cond (nil? key-or-nil)
+ (let [n (.inode-assoc! val-or-node edit (+ shift 5) hash key val added-leaf?)]
+ (if (identical? n val-or-node)
+ inode
+ (edit-and-set inode edit (inc (* 2 idx)) n)))
+
+ (key-test key key-or-nil)
+ (if (identical? val val-or-node)
+ inode
+ (edit-and-set inode edit (inc (* 2 idx)) val))
+
+ :else
+ (do (set! (.-val added-leaf?) true)
+ (edit-and-set inode edit (* 2 idx) nil (inc (* 2 idx))
+ (create-node edit (+ shift 5) key-or-nil val-or-node hash key val))))))))
+
+ (inode-without! [inode edit shift hash key removed-leaf?]
+ (let [bit (bitpos hash shift)]
+ (if (zero? (bit-and bitmap bit))
+ inode
+ (let [idx (bitmap-indexed-node-index bitmap bit)
+ key-or-nil (aget arr (* 2 idx))
+ val-or-node (aget arr (inc (* 2 idx)))]
+ (cond (nil? key-or-nil)
+ (let [n (.inode-without! val-or-node edit (+ shift 5) hash key removed-leaf?)]
+ (cond (identical? n val-or-node) inode
+ (not (nil? n)) (edit-and-set inode edit (inc (* 2 idx)) n)
+ (== bitmap bit) nil
+ :else (.edit-and-remove-pair inode edit bit idx)))
+ (key-test key key-or-nil)
+ (do (set! (.-val removed-leaf?) true)
+ (.edit-and-remove-pair inode edit bit idx))
+ :else inode)))))
+
+ (kv-reduce [inode f init]
+ (inode-kv-reduce arr f init))
+
+ IIterable
+ (-iterator [coll]
+ (NodeIterator. arr 0 nil nil)))
+
+(set! (.-EMPTY BitmapIndexedNode) (BitmapIndexedNode. nil 0 (make-array 0)))
+
+(defn- pack-array-node [array-node edit idx]
+ (let [arr (.-arr array-node)
+ len (alength arr)
+ new-arr (make-array (* 2 (dec (.-cnt array-node))))]
+ (loop [i 0 j 1 bitmap 0]
+ (if (< i len)
+ (if (and (not (== i idx))
+ (not (nil? (aget arr i))))
+ (do (aset new-arr j (aget arr i))
+ (recur (inc i) (+ j 2) (bit-or bitmap (bit-shift-left 1 i))))
+ (recur (inc i) j bitmap))
+ (BitmapIndexedNode. edit bitmap new-arr)))))
+
+(deftype ArrayNodeIterator [arr ^:mutable i ^:mutable next-iter]
+ Object
+ (hasNext [this]
+ (let [len (alength arr)]
+ (loop []
+ (if-not (and (some? next-iter) ^boolean (.hasNext next-iter))
+ (if (< i len)
+ (let [node (aget arr i)]
+ (set! i (inc i))
+ (when (some? node)
+ (set! next-iter (-iterator node)))
+ (recur))
+ false)
+ true))))
+ (next [this]
+ (if ^boolean (.hasNext this)
+ (.next next-iter)
+ (throw (js/Error. "No such element"))))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+(deftype ArrayNode [edit ^:mutable cnt ^:mutable arr]
+ Object
+ (inode-assoc [inode shift hash key val added-leaf?]
+ (let [idx (mask hash shift)
+ node (aget arr idx)]
+ (if (nil? node)
+ (ArrayNode. nil (inc cnt) (clone-and-set arr idx (.inode-assoc (.-EMPTY BitmapIndexedNode) (+ shift 5) hash key val added-leaf?)))
+ (let [n (.inode-assoc node (+ shift 5) hash key val added-leaf?)]
+ (if (identical? n node)
+ inode
+ (ArrayNode. nil cnt (clone-and-set arr idx n)))))))
+
+ (inode-without [inode shift hash key]
+ (let [idx (mask hash shift)
+ node (aget arr idx)]
+ (if-not (nil? node)
+ (let [n (.inode-without node (+ shift 5) hash key)]
+ (cond
+ (identical? n node)
+ inode
+
+ (nil? n)
+ (if (<= cnt 8)
+ (pack-array-node inode nil idx)
+ (ArrayNode. nil (dec cnt) (clone-and-set arr idx n)))
+
+ :else
+ (ArrayNode. nil cnt (clone-and-set arr idx n))))
+ inode)))
+
+ (inode-lookup [inode shift hash key not-found]
+ (let [idx (mask hash shift)
+ node (aget arr idx)]
+ (if-not (nil? node)
+ (.inode-lookup node (+ shift 5) hash key not-found)
+ not-found)))
+
+ (inode-find [inode shift hash key not-found]
+ (let [idx (mask hash shift)
+ node (aget arr idx)]
+ (if-not (nil? node)
+ (.inode-find node (+ shift 5) hash key not-found)
+ not-found)))
+
+ (inode-seq [inode]
+ (create-array-node-seq arr))
+
+ (ensure-editable [inode e]
+ (if (identical? e edit)
+ inode
+ (ArrayNode. e cnt (aclone arr))))
+
+ (inode-assoc! [inode edit shift hash key val added-leaf?]
+ (let [idx (mask hash shift)
+ node (aget arr idx)]
+ (if (nil? node)
+ (let [editable (edit-and-set inode edit idx (.inode-assoc! (.-EMPTY BitmapIndexedNode) edit (+ shift 5) hash key val added-leaf?))]
+ (set! (.-cnt editable) (inc (.-cnt editable)))
+ editable)
+ (let [n (.inode-assoc! node edit (+ shift 5) hash key val added-leaf?)]
+ (if (identical? n node)
+ inode
+ (edit-and-set inode edit idx n))))))
+
+ (inode-without! [inode edit shift hash key removed-leaf?]
+ (let [idx (mask hash shift)
+ node (aget arr idx)]
+ (if (nil? node)
+ inode
+ (let [n (.inode-without! node edit (+ shift 5) hash key removed-leaf?)]
+ (cond
+ (identical? n node)
+ inode
+
+ (nil? n)
+ (if (<= cnt 8)
+ (pack-array-node inode edit idx)
+ (let [editable (edit-and-set inode edit idx n)]
+ (set! (.-cnt editable) (dec (.-cnt editable)))
+ editable))
+
+ :else
+ (edit-and-set inode edit idx n))))))
+
+ (kv-reduce [inode f init]
+ (let [len (alength arr)] ; actually 32
+ (loop [i 0 init init]
+ (if (< i len)
+ (let [node (aget arr i)]
+ (if-not (nil? node)
+ (let [init (.kv-reduce node f init)]
+ (if (reduced? init)
+ init
+ (recur (inc i) init)))
+ (recur (inc i) init)))
+ init))))
+
+ IIterable
+ (-iterator [coll]
+ (ArrayNodeIterator. arr 0 nil)))
+
+(defn- hash-collision-node-find-index [arr cnt key]
+ (let [lim (* 2 cnt)]
+ (loop [i 0]
+ (if (< i lim)
+ (if (key-test key (aget arr i))
+ i
+ (recur (+ i 2)))
+ -1))))
+
+(deftype HashCollisionNode [edit
+ ^:mutable collision-hash
+ ^:mutable cnt
+ ^:mutable arr]
+ Object
+ (inode-assoc [inode shift hash key val added-leaf?]
+ (if (== hash collision-hash)
+ (let [idx (hash-collision-node-find-index arr cnt key)]
+ (if (== idx -1)
+ (let [len (* 2 cnt)
+ new-arr (make-array (+ len 2))]
+ (array-copy arr 0 new-arr 0 len)
+ (aset new-arr len key)
+ (aset new-arr (inc len) val)
+ (set! (.-val added-leaf?) true)
+ (HashCollisionNode. nil collision-hash (inc cnt) new-arr))
+ (if (= (aget arr (inc idx)) val)
+ inode
+ (HashCollisionNode. nil collision-hash cnt (clone-and-set arr (inc idx) val)))))
+ (.inode-assoc (BitmapIndexedNode. nil (bitpos collision-hash shift) (array nil inode))
+ shift hash key val added-leaf?)))
+
+ (inode-without [inode shift hash key]
+ (let [idx (hash-collision-node-find-index arr cnt key)]
+ (cond (== idx -1) inode
+ (== cnt 1) nil
+ :else (HashCollisionNode. nil collision-hash (dec cnt) (remove-pair arr (quot idx 2))))))
+
+ (inode-lookup [inode shift hash key not-found]
+ (let [idx (hash-collision-node-find-index arr cnt key)]
+ (cond (< idx 0) not-found
+ (key-test key (aget arr idx)) (aget arr (inc idx))
+ :else not-found)))
+
+ (inode-find [inode shift hash key not-found]
+ (let [idx (hash-collision-node-find-index arr cnt key)]
+ (cond (< idx 0) not-found
+ (key-test key (aget arr idx)) (MapEntry. (aget arr idx) (aget arr (inc idx)) nil)
+ :else not-found)))
+
+ (inode-seq [inode]
+ (create-inode-seq arr))
+
+ (ensure-editable [inode e]
+ (if (identical? e edit)
+ inode
+ (let [new-arr (make-array (* 2 (inc cnt)))]
+ (array-copy arr 0 new-arr 0 (* 2 cnt))
+ (HashCollisionNode. e collision-hash cnt new-arr))))
+
+ (ensure-editable-array [inode e count array]
+ (if (identical? e edit)
+ (do (set! arr array)
+ (set! cnt count)
+ inode)
+ (HashCollisionNode. edit collision-hash count array)))
+
+ (inode-assoc! [inode edit shift hash key val added-leaf?]
+ (if (== hash collision-hash)
+ (let [idx (hash-collision-node-find-index arr cnt key)]
+ (if (== idx -1)
+ (if (> (alength arr) (* 2 cnt))
+ (let [editable (edit-and-set inode edit (* 2 cnt) key (inc (* 2 cnt)) val)]
+ (set! (.-val added-leaf?) true)
+ (set! (.-cnt editable) (inc (.-cnt editable)))
+ editable)
+ (let [len (alength arr)
+ new-arr (make-array (+ len 2))]
+ (array-copy arr 0 new-arr 0 len)
+ (aset new-arr len key)
+ (aset new-arr (inc len) val)
+ (set! (.-val added-leaf?) true)
+ (.ensure-editable-array inode edit (inc cnt) new-arr)))
+ (if (identical? (aget arr (inc idx)) val)
+ inode
+ (edit-and-set inode edit (inc idx) val))))
+ (.inode-assoc! (BitmapIndexedNode. edit (bitpos collision-hash shift) (array nil inode nil nil))
+ edit shift hash key val added-leaf?)))
+
+ (inode-without! [inode edit shift hash key removed-leaf?]
+ (let [idx (hash-collision-node-find-index arr cnt key)]
+ (if (== idx -1)
+ inode
+ (do (set! (.-val removed-leaf?) true)
+ (if (== cnt 1)
+ nil
+ (let [editable (.ensure-editable inode edit)
+ earr (.-arr editable)]
+ (aset earr idx (aget earr (- (* 2 cnt) 2)))
+ (aset earr (inc idx) (aget earr (dec (* 2 cnt))))
+ (aset earr (dec (* 2 cnt)) nil)
+ (aset earr (- (* 2 cnt) 2) nil)
+ (set! (.-cnt editable) (dec (.-cnt editable)))
+ editable))))))
+
+ (kv-reduce [inode f init]
+ (inode-kv-reduce arr f init))
+
+ IIterable
+ (-iterator [coll]
+ (NodeIterator. arr 0 nil nil)))
+
+(defn- create-node
+ ([shift key1 val1 key2hash key2 val2]
+ (let [key1hash (hash key1)]
+ (if (== key1hash key2hash)
+ (HashCollisionNode. nil key1hash 2 (array key1 val1 key2 val2))
+ (let [added-leaf? (Box. false)]
+ (-> (.-EMPTY BitmapIndexedNode)
+ (.inode-assoc shift key1hash key1 val1 added-leaf?)
+ (.inode-assoc shift key2hash key2 val2 added-leaf?))))))
+ ([edit shift key1 val1 key2hash key2 val2]
+ (let [key1hash (hash key1)]
+ (if (== key1hash key2hash)
+ (HashCollisionNode. nil key1hash 2 (array key1 val1 key2 val2))
+ (let [added-leaf? (Box. false)]
+ (-> (.-EMPTY BitmapIndexedNode)
+ (.inode-assoc! edit shift key1hash key1 val1 added-leaf?)
+ (.inode-assoc! edit shift key2hash key2 val2 added-leaf?)))))))
+
+(deftype NodeSeq [meta nodes i s ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IMeta
+ (-meta [coll] meta)
+
+ IWithMeta
+ (-with-meta [coll meta] (NodeSeq. meta nodes i s __hash))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ ISeq
+ (-first [coll]
+ (if (nil? s)
+ (MapEntry. (aget nodes i) (aget nodes (inc i)) nil)
+ (first s)))
+
+ (-rest [coll]
+ (let [ret (if (nil? s)
+ (create-inode-seq nodes (+ i 2) nil)
+ (create-inode-seq nodes i (next s)))]
+ (if-not (nil? ret) ret ())))
+
+ INext
+ (-next [coll]
+ (if (nil? s)
+ (create-inode-seq nodes (+ i 2) nil)
+ (create-inode-seq nodes i (next s))))
+
+ ISeqable
+ (-seq [this] this)
+
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(es6-iterable NodeSeq)
+
+(defn- create-inode-seq
+ ([nodes]
+ (create-inode-seq nodes 0 nil))
+ ([nodes i s]
+ (if (nil? s)
+ (let [len (alength nodes)]
+ (loop [j i]
+ (if (< j len)
+ (if-not (nil? (aget nodes j))
+ (NodeSeq. nil nodes j nil nil)
+ (if-let [node (aget nodes (inc j))]
+ (if-let [node-seq (.inode-seq node)]
+ (NodeSeq. nil nodes (+ j 2) node-seq nil)
+ (recur (+ j 2)))
+ (recur (+ j 2)))))))
+ (NodeSeq. nil nodes i s nil))))
+
+(deftype ArrayNodeSeq [meta nodes i s ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IMeta
+ (-meta [coll] meta)
+
+ IWithMeta
+ (-with-meta [coll meta] (ArrayNodeSeq. meta nodes i s __hash))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ ISeq
+ (-first [coll] (first s))
+ (-rest [coll]
+ (let [ret (create-array-node-seq nil nodes i (next s))]
+ (if-not (nil? ret) ret ())))
+
+ INext
+ (-next [coll]
+ (create-array-node-seq nil nodes i (next s)))
+
+ ISeqable
+ (-seq [this] this)
+
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(es6-iterable ArrayNodeSeq)
+
+(defn- create-array-node-seq
+ ([nodes] (create-array-node-seq nil nodes 0 nil))
+ ([meta nodes i s]
+ (if (nil? s)
+ (let [len (alength nodes)]
+ (loop [j i]
+ (if (< j len)
+ (if-let [nj (aget nodes j)]
+ (if-let [ns (.inode-seq nj)]
+ (ArrayNodeSeq. meta nodes (inc j) ns nil)
+ (recur (inc j)))
+ (recur (inc j))))))
+ (ArrayNodeSeq. meta nodes i s nil))))
+
+(deftype HashMapIter [nil-val root-iter ^:mutable seen]
+ Object
+ (hasNext [_]
+ (or (not ^boolean seen) ^boolean (.hasNext root-iter)))
+ (next [_]
+ (if-not ^boolean seen
+ (do
+ (set! seen true)
+ (MapEntry. nil nil-val nil))
+ (.next root-iter)))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+(deftype PersistentHashMap [meta cnt root ^boolean has-nil? nil-val ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+
+ ;; EXPERIMENTAL: subject to change
+ (keys [coll]
+ (es6-iterator (keys coll)))
+ (entries [coll]
+ (es6-entries-iterator (seq coll)))
+ (values [coll]
+ (es6-iterator (vals coll)))
+ (has [coll k]
+ (contains? coll k))
+ (get [coll k not-found]
+ (-lookup coll k not-found))
+ (forEach [coll f]
+ (doseq [[k v] coll]
+ (f v k)))
+
+ ICloneable
+ (-clone [_] (PersistentHashMap. meta cnt root has-nil? nil-val __hash))
+
+ IIterable
+ (-iterator [coll]
+ (let [root-iter (if ^boolean root (-iterator root) (nil-iter))]
+ (if has-nil?
+ (HashMapIter. nil-val root-iter false)
+ root-iter)))
+
+ IWithMeta
+ (-with-meta [coll meta] (PersistentHashMap. meta cnt root has-nil? nil-val __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ICollection
+ (-conj [coll entry]
+ (if (vector? entry)
+ (-assoc coll (-nth entry 0) (-nth entry 1))
+ (loop [ret coll es (seq entry)]
+ (if (nil? es)
+ ret
+ (let [e (first es)]
+ (if (vector? e)
+ (recur (-assoc ret (-nth e 0) (-nth e 1))
+ (next es))
+ (throw (js/Error. "conj on a map takes map entries or seqables of map entries"))))))))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY PersistentHashMap) meta))
+
+ IEquiv
+ (-equiv [coll other] (equiv-map coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-unordered-coll __hash))
+
+ ISeqable
+ (-seq [coll]
+ (when (pos? cnt)
+ (let [s (if-not (nil? root) (.inode-seq root))]
+ (if has-nil?
+ (cons (MapEntry. nil nil-val nil) s)
+ s))))
+
+ ICounted
+ (-count [coll] cnt)
+
+ ILookup
+ (-lookup [coll k]
+ (-lookup coll k nil))
+
+ (-lookup [coll k not-found]
+ (cond (nil? k) (if has-nil?
+ nil-val
+ not-found)
+ (nil? root) not-found
+ :else (.inode-lookup root 0 (hash k) k not-found)))
+
+ IAssociative
+ (-assoc [coll k v]
+ (if (nil? k)
+ (if (and has-nil? (identical? v nil-val))
+ coll
+ (PersistentHashMap. meta (if has-nil? cnt (inc cnt)) root true v nil))
+ (let [added-leaf? (Box. false)
+ new-root (-> (if (nil? root)
+ (.-EMPTY BitmapIndexedNode)
+ root)
+ (.inode-assoc 0 (hash k) k v added-leaf?))]
+ (if (identical? new-root root)
+ coll
+ (PersistentHashMap. meta (if ^boolean (.-val added-leaf?) (inc cnt) cnt) new-root has-nil? nil-val nil)))))
+
+ (-contains-key? [coll k]
+ (cond (nil? k) has-nil?
+ (nil? root) false
+ :else (not (identical? (.inode-lookup root 0 (hash k) k lookup-sentinel)
+ lookup-sentinel))))
+
+ IFind
+ (-find [coll k]
+ (cond
+ (nil? k) (when has-nil? (MapEntry. nil nil-val nil))
+ (nil? root) nil
+ :else (.inode-find root 0 (hash k) k nil)))
+
+ IMap
+ (-dissoc [coll k]
+ (cond (nil? k) (if has-nil?
+ (PersistentHashMap. meta (dec cnt) root false nil nil)
+ coll)
+ (nil? root) coll
+ :else
+ (let [new-root (.inode-without root 0 (hash k) k)]
+ (if (identical? new-root root)
+ coll
+ (PersistentHashMap. meta (dec cnt) new-root has-nil? nil-val nil)))))
+
+ IKVReduce
+ (-kv-reduce [coll f init]
+ (let [init (if has-nil? (f init nil nil-val) init)]
+ (cond
+ (reduced? init) @init
+ (not (nil? root)) (unreduced (.kv-reduce root f init))
+ :else init)))
+
+ IFn
+ (-invoke [coll k]
+ (-lookup coll k))
+
+ (-invoke [coll k not-found]
+ (-lookup coll k not-found))
+
+ IEditableCollection
+ (-as-transient [coll]
+ (TransientHashMap. (js-obj) root cnt has-nil? nil-val)))
+
+(set! (.-EMPTY PersistentHashMap) (PersistentHashMap. nil 0 nil false nil empty-unordered-hash))
+
+(set! (.-fromArray PersistentHashMap)
+ (fn [arr ^boolean no-clone]
+ (let [arr (if no-clone arr (aclone arr))
+ len (alength arr)]
+ (loop [i 0 ret (transient (.-EMPTY PersistentHashMap))]
+ (if (< i len)
+ (recur (+ i 2)
+ (-assoc! ret (aget arr i) (aget arr (inc i))))
+ (-persistent! ret))))))
+
+(set! (.-fromArrays PersistentHashMap)
+ (fn [ks vs]
+ (let [len (alength ks)]
+ (loop [i 0 ^not-native out (transient (.-EMPTY PersistentHashMap))]
+ (if (< i len)
+ (recur (inc i) (-assoc! out (aget ks i) (aget vs i)))
+ (persistent! out))))))
+
+(set! (.-createWithCheck PersistentHashMap)
+ (fn [arr]
+ (let [len (alength arr)
+ ret (transient (.-EMPTY PersistentHashMap))]
+ (loop [i 0]
+ (when (< i len)
+ (-assoc! ret (aget arr i) (aget arr (inc i)))
+ (if (not= (-count ret) (inc (/ i 2)))
+ (throw (js/Error. (str "Duplicate key: " (aget arr i))))
+ (recur (+ i 2)))))
+ (-persistent! ret))))
+
+(es6-iterable PersistentHashMap)
+
+(deftype TransientHashMap [^:mutable ^boolean edit
+ ^:mutable root
+ ^:mutable count
+ ^:mutable ^boolean has-nil?
+ ^:mutable nil-val]
+ Object
+ (conj! [tcoll o]
+ (if edit
+ (cond
+ (map-entry? o)
+ (.assoc! tcoll (key o) (val o))
+
+ (vector? o)
+ (.assoc! tcoll (o 0) (o 1))
+
+ :else
+ (loop [es (seq o) tcoll tcoll]
+ (if-let [e (first es)]
+ (recur (next es)
+ (.assoc! tcoll (key e) (val e)))
+ tcoll)))
+ (throw (js/Error. "conj! after persistent"))))
+
+ (assoc! [tcoll k v]
+ (if edit
+ (if (nil? k)
+ (do (if (identical? nil-val v)
+ nil
+ (set! nil-val v))
+ (if has-nil?
+ nil
+ (do (set! count (inc count))
+ (set! has-nil? true)))
+ tcoll)
+ (let [added-leaf? (Box. false)
+ node (-> (if (nil? root)
+ (.-EMPTY BitmapIndexedNode)
+ root)
+ (.inode-assoc! edit 0 (hash k) k v added-leaf?))]
+ (if (identical? node root)
+ nil
+ (set! root node))
+ (if ^boolean (.-val added-leaf?)
+ (set! count (inc count)))
+ tcoll))
+ (throw (js/Error. "assoc! after persistent!"))))
+
+ (without! [tcoll k]
+ (if edit
+ (if (nil? k)
+ (if has-nil?
+ (do (set! has-nil? false)
+ (set! nil-val nil)
+ (set! count (dec count))
+ tcoll)
+ tcoll)
+ (if (nil? root)
+ tcoll
+ (let [removed-leaf? (Box. false)
+ node (.inode-without! root edit 0 (hash k) k removed-leaf?)]
+ (if (identical? node root)
+ nil
+ (set! root node))
+ (if ^boolean (.-val removed-leaf?)
+ (set! count (dec count)))
+ tcoll)))
+ (throw (js/Error. "dissoc! after persistent!"))))
+
+ (persistent! [tcoll]
+ (if edit
+ (do (set! edit nil)
+ (PersistentHashMap. nil count root has-nil? nil-val nil))
+ (throw (js/Error. "persistent! called twice"))))
+
+ ICounted
+ (-count [coll]
+ (if edit
+ count
+ (throw (js/Error. "count after persistent!"))))
+
+ ILookup
+ (-lookup [tcoll k]
+ (if (nil? k)
+ (if has-nil?
+ nil-val)
+ (if (nil? root)
+ nil
+ (.inode-lookup root 0 (hash k) k))))
+
+ (-lookup [tcoll k not-found]
+ (if (nil? k)
+ (if has-nil?
+ nil-val
+ not-found)
+ (if (nil? root)
+ not-found
+ (.inode-lookup root 0 (hash k) k not-found))))
+
+ ITransientCollection
+ (-conj! [tcoll val] (.conj! tcoll val))
+
+ (-persistent! [tcoll] (.persistent! tcoll))
+
+ ITransientAssociative
+ (-assoc! [tcoll key val] (.assoc! tcoll key val))
+
+ ITransientMap
+ (-dissoc! [tcoll key] (.without! tcoll key))
+
+ IFn
+ (-invoke [tcoll key]
+ (-lookup tcoll key))
+ (-invoke [tcoll key not-found]
+ (-lookup tcoll key not-found)))
+
+;;; PersistentTreeMap
+
+(defn- tree-map-seq-push [node stack ^boolean ascending?]
+ (loop [t node stack stack]
+ (if-not (nil? t)
+ (recur (if ascending? (.-left t) (.-right t))
+ (conj stack t))
+ stack)))
+
+(deftype PersistentTreeMapSeq [meta stack ^boolean ascending? cnt ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ ISeqable
+ (-seq [this] this)
+
+ ISequential
+ ISeq
+ (-first [this] (peek stack))
+ (-rest [this]
+ (let [t (first stack)
+ next-stack (tree-map-seq-push (if ascending? (.-right t) (.-left t))
+ (next stack)
+ ascending?)]
+ (if-not (nil? next-stack)
+ (PersistentTreeMapSeq. nil next-stack ascending? (dec cnt) nil)
+ ())))
+ INext
+ (-next [this]
+ (let [t (first stack)
+ next-stack (tree-map-seq-push (if ascending? (.-right t) (.-left t))
+ (next stack)
+ ascending?)]
+ (when-not (nil? next-stack)
+ (PersistentTreeMapSeq. nil next-stack ascending? (dec cnt) nil))))
+
+ ICounted
+ (-count [coll]
+ (if (neg? cnt)
+ (inc (count (next coll)))
+ cnt))
+
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ ICollection
+ (-conj [coll o] (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) meta))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ IWithMeta
+ (-with-meta [coll meta]
+ (PersistentTreeMapSeq. meta stack ascending? cnt __hash))
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(es6-iterable PersistentTreeMapSeq)
+
+(defn- create-tree-map-seq [tree ascending? cnt]
+ (PersistentTreeMapSeq. nil (tree-map-seq-push tree nil ascending?) ascending? cnt nil))
+
+(declare RedNode BlackNode)
+
+(defn- balance-left [key val ins right]
+ (if (instance? RedNode ins)
+ (cond
+ (instance? RedNode (.-left ins))
+ (RedNode. (.-key ins) (.-val ins)
+ (.blacken (.-left ins))
+ (BlackNode. key val (.-right ins) right nil)
+ nil)
+
+ (instance? RedNode (.-right ins))
+ (RedNode. (.. ins -right -key) (.. ins -right -val)
+ (BlackNode. (.-key ins) (.-val ins)
+ (.-left ins)
+ (.. ins -right -left)
+ nil)
+ (BlackNode. key val
+ (.. ins -right -right)
+ right
+ nil)
+ nil)
+
+ :else
+ (BlackNode. key val ins right nil))
+ (BlackNode. key val ins right nil)))
+
+(defn- balance-right [key val left ins]
+ (if (instance? RedNode ins)
+ (cond
+ (instance? RedNode (.-right ins))
+ (RedNode. (.-key ins) (.-val ins)
+ (BlackNode. key val left (.-left ins) nil)
+ (.blacken (.-right ins))
+ nil)
+
+ (instance? RedNode (.-left ins))
+ (RedNode. (.. ins -left -key) (.. ins -left -val)
+ (BlackNode. key val left (.. ins -left -left) nil)
+ (BlackNode. (.-key ins) (.-val ins)
+ (.. ins -left -right)
+ (.-right ins)
+ nil)
+ nil)
+
+ :else
+ (BlackNode. key val left ins nil))
+ (BlackNode. key val left ins nil)))
+
+(defn- balance-left-del [key val del right]
+ (cond
+ (instance? RedNode del)
+ (RedNode. key val (.blacken del) right nil)
+
+ (instance? BlackNode right)
+ (balance-right key val del (.redden right))
+
+ (and (instance? RedNode right) (instance? BlackNode (.-left right)))
+ (RedNode. (.. right -left -key) (.. right -left -val)
+ (BlackNode. key val del (.. right -left -left) nil)
+ (balance-right (.-key right) (.-val right)
+ (.. right -left -right)
+ (.redden (.-right right)))
+ nil)
+
+ :else
+ (throw (js/Error. "red-black tree invariant violation"))))
+
+(defn- balance-right-del [key val left del]
+ (cond
+ (instance? RedNode del)
+ (RedNode. key val left (.blacken del) nil)
+
+ (instance? BlackNode left)
+ (balance-left key val (.redden left) del)
+
+ (and (instance? RedNode left) (instance? BlackNode (.-right left)))
+ (RedNode. (.. left -right -key) (.. left -right -val)
+ (balance-left (.-key left) (.-val left)
+ (.redden (.-left left))
+ (.. left -right -left))
+ (BlackNode. key val (.. left -right -right) del nil)
+ nil)
+
+ :else
+ (throw (js/Error. "red-black tree invariant violation"))))
+
+(defn- tree-map-kv-reduce [node f init]
+ (let [init (if-not (nil? (.-left node))
+ (tree-map-kv-reduce (.-left node) f init)
+ init)]
+ (if (reduced? init)
+ init
+ (let [init (f init (.-key node) (.-val node))]
+ (if (reduced? init)
+ init
+ (if-not (nil? (.-right node))
+ (tree-map-kv-reduce (.-right node) f init)
+ init))))))
+
+(deftype BlackNode [key val left right ^:mutable __hash]
+ Object
+ (add-left [node ins]
+ (.balance-left ins node))
+
+ (add-right [node ins]
+ (.balance-right ins node))
+
+ (remove-left [node del]
+ (balance-left-del key val del right))
+
+ (remove-right [node del]
+ (balance-right-del key val left del))
+
+ (blacken [node] node)
+
+ (redden [node] (RedNode. key val left right nil))
+
+ (balance-left [node parent]
+ (BlackNode. (.-key parent) (.-val parent) node (.-right parent) nil))
+
+ (balance-right [node parent]
+ (BlackNode. (.-key parent) (.-val parent) (.-left parent) node nil))
+
+ (replace [node key val left right]
+ (BlackNode. key val left right nil))
+
+ (kv-reduce [node f init]
+ (tree-map-kv-reduce node f init))
+
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IMapEntry
+ (-key [node] key)
+ (-val [node] val)
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IMeta
+ (-meta [node] nil)
+
+ IWithMeta
+ (-with-meta [node meta]
+ (-with-meta [key val] meta))
+
+ IStack
+ (-peek [node] val)
+
+ (-pop [node] [key])
+
+ ICollection
+ (-conj [node o] [key val o])
+
+ IEmptyableCollection
+ (-empty [node] nil)
+
+ ISequential
+ ISeqable
+ (-seq [node] (IndexedSeq. #js [key val] 0 nil))
+
+ IReversible
+ (-rseq [node] (IndexedSeq. #js [val key] 0 nil))
+
+ ICounted
+ (-count [node] 2)
+
+ IIndexed
+ (-nth [node n]
+ (cond (== n 0) key
+ (== n 1) val
+ :else (throw (js/Error. "Index out of bounds"))))
+
+ (-nth [node n not-found]
+ (cond (== n 0) key
+ (== n 1) val
+ :else not-found))
+
+ ILookup
+ (-lookup [node k] (-nth node k nil))
+ (-lookup [node k not-found] (-nth node k not-found))
+
+ IAssociative
+ (-assoc [node k v]
+ (assoc [key val] k v))
+ (-contains-key? [node k]
+ (or (== k 0) (== k 1)))
+
+ IFind
+ (-find [node k]
+ (case k
+ 0 (MapEntry. 0 key nil)
+ 1 (MapEntry. 1 val nil)
+ nil))
+
+ IVector
+ (-assoc-n [node n v]
+ (-assoc-n [key val] n v))
+
+ IReduce
+ (-reduce [node f]
+ (ci-reduce node f))
+
+ (-reduce [node f start]
+ (ci-reduce node f start))
+
+ IFn
+ (-invoke [node k]
+ (-nth node k))
+
+ (-invoke [node k not-found]
+ (-nth node k not-found)))
+
+(es6-iterable BlackNode)
+
+(deftype RedNode [key val left right ^:mutable __hash]
+ Object
+ (add-left [node ins]
+ (RedNode. key val ins right nil))
+
+ (add-right [node ins]
+ (RedNode. key val left ins nil))
+
+ (remove-left [node del]
+ (RedNode. key val del right nil))
+
+ (remove-right [node del]
+ (RedNode. key val left del nil))
+
+ (blacken [node]
+ (BlackNode. key val left right nil))
+
+ (redden [node]
+ (throw (js/Error. "red-black tree invariant violation")))
+
+ (balance-left [node parent]
+ (cond
+ (instance? RedNode left)
+ (RedNode. key val
+ (.blacken left)
+ (BlackNode. (.-key parent) (.-val parent) right (.-right parent) nil)
+ nil)
+
+ (instance? RedNode right)
+ (RedNode. (.-key right) (.-val right)
+ (BlackNode. key val left (.-left right) nil)
+ (BlackNode. (.-key parent) (.-val parent)
+ (.-right right)
+ (.-right parent)
+ nil)
+ nil)
+
+ :else
+ (BlackNode. (.-key parent) (.-val parent) node (.-right parent) nil)))
+
+ (balance-right [node parent]
+ (cond
+ (instance? RedNode right)
+ (RedNode. key val
+ (BlackNode. (.-key parent) (.-val parent)
+ (.-left parent)
+ left
+ nil)
+ (.blacken right)
+ nil)
+
+ (instance? RedNode left)
+ (RedNode. (.-key left) (.-val left)
+ (BlackNode. (.-key parent) (.-val parent)
+ (.-left parent)
+ (.-left left)
+ nil)
+ (BlackNode. key val (.-right left) right nil)
+ nil)
+
+ :else
+ (BlackNode. (.-key parent) (.-val parent) (.-left parent) node nil)))
+
+ (replace [node key val left right]
+ (RedNode. key val left right nil))
+
+ (kv-reduce [node f init]
+ (tree-map-kv-reduce node f init))
+
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IMapEntry
+ (-key [node] key)
+ (-val [node] val)
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-ordered-coll __hash))
+
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ IMeta
+ (-meta [node] nil)
+
+ IWithMeta
+ (-with-meta [node meta]
+ (-with-meta [key val] meta))
+
+ IStack
+ (-peek [node] val)
+
+ (-pop [node] [key])
+
+ ICollection
+ (-conj [node o] [key val o])
+
+ IEmptyableCollection
+ (-empty [node] nil)
+
+ ISequential
+ ISeqable
+ (-seq [node] (IndexedSeq. #js [key val] 0 nil))
+
+ IReversible
+ (-rseq [node] (IndexedSeq. #js [val key] 0 nil))
+
+ ICounted
+ (-count [node] 2)
+
+ IIndexed
+ (-nth [node n]
+ (cond (== n 0) key
+ (== n 1) val
+ :else (throw (js/Error. "Index out of bounds"))))
+
+ (-nth [node n not-found]
+ (cond (== n 0) key
+ (== n 1) val
+ :else not-found))
+
+ ILookup
+ (-lookup [node k] (-nth node k nil))
+ (-lookup [node k not-found] (-nth node k not-found))
+
+ IAssociative
+ (-assoc [node k v]
+ (assoc [key val] k v))
+ (-contains-key? [node k]
+ (or (== k 0) (== k 1)))
+
+ IFind
+ (-find [node k]
+ (case k
+ 0 (MapEntry. 0 key nil)
+ 1 (MapEntry. 1 val nil)
+ nil))
+
+ IVector
+ (-assoc-n [node n v]
+ (-assoc-n [key val] n v))
+
+ IReduce
+ (-reduce [node f]
+ (ci-reduce node f))
+
+ (-reduce [node f start]
+ (ci-reduce node f start))
+
+ IFn
+ (-invoke [node k]
+ (-nth node k))
+
+ (-invoke [node k not-found]
+ (-nth node k not-found)))
+
+(es6-iterable RedNode)
+
+(defn- tree-map-add [comp tree k v found]
+ (if (nil? tree)
+ (RedNode. k v nil nil nil)
+ (let [c (comp k (.-key tree))]
+ (cond
+ (zero? c)
+ (do (aset found 0 tree)
+ nil)
+
+ (neg? c)
+ (let [ins (tree-map-add comp (.-left tree) k v found)]
+ (if-not (nil? ins)
+ (.add-left tree ins)))
+
+ :else
+ (let [ins (tree-map-add comp (.-right tree) k v found)]
+ (if-not (nil? ins)
+ (.add-right tree ins)))))))
+
+(defn- tree-map-append [left right]
+ (cond
+ (nil? left)
+ right
+
+ (nil? right)
+ left
+
+ (instance? RedNode left)
+ (if (instance? RedNode right)
+ (let [app (tree-map-append (.-right left) (.-left right))]
+ (if (instance? RedNode app)
+ (RedNode. (.-key app) (.-val app)
+ (RedNode. (.-key left) (.-val left)
+ (.-left left)
+ (.-left app)
+ nil)
+ (RedNode. (.-key right) (.-val right)
+ (.-right app)
+ (.-right right)
+ nil)
+ nil)
+ (RedNode. (.-key left) (.-val left)
+ (.-left left)
+ (RedNode. (.-key right) (.-val right) app (.-right right) nil)
+ nil)))
+ (RedNode. (.-key left) (.-val left)
+ (.-left left)
+ (tree-map-append (.-right left) right)
+ nil))
+
+ (instance? RedNode right)
+ (RedNode. (.-key right) (.-val right)
+ (tree-map-append left (.-left right))
+ (.-right right)
+ nil)
+
+ :else
+ (let [app (tree-map-append (.-right left) (.-left right))]
+ (if (instance? RedNode app)
+ (RedNode. (.-key app) (.-val app)
+ (BlackNode. (.-key left) (.-val left)
+ (.-left left)
+ (.-left app)
+ nil)
+ (BlackNode. (.-key right) (.-val right)
+ (.-right app)
+ (.-right right)
+ nil)
+ nil)
+ (balance-left-del (.-key left) (.-val left)
+ (.-left left)
+ (BlackNode. (.-key right) (.-val right)
+ app
+ (.-right right)
+ nil))))))
+
+(defn- tree-map-remove [comp tree k found]
+ (if-not (nil? tree)
+ (let [c (comp k (.-key tree))]
+ (cond
+ (zero? c)
+ (do (aset found 0 tree)
+ (tree-map-append (.-left tree) (.-right tree)))
+
+ (neg? c)
+ (let [del (tree-map-remove comp (.-left tree) k found)]
+ (if (or (not (nil? del)) (not (nil? (aget found 0))))
+ (if (instance? BlackNode (.-left tree))
+ (balance-left-del (.-key tree) (.-val tree) del (.-right tree))
+ (RedNode. (.-key tree) (.-val tree) del (.-right tree) nil))))
+
+ :else
+ (let [del (tree-map-remove comp (.-right tree) k found)]
+ (if (or (not (nil? del)) (not (nil? (aget found 0))))
+ (if (instance? BlackNode (.-right tree))
+ (balance-right-del (.-key tree) (.-val tree) (.-left tree) del)
+ (RedNode. (.-key tree) (.-val tree) (.-left tree) del nil))))))))
+
+(defn- tree-map-replace [comp tree k v]
+ (let [tk (.-key tree)
+ c (comp k tk)]
+ (cond (zero? c) (.replace tree tk v (.-left tree) (.-right tree))
+ (neg? c) (.replace tree tk (.-val tree) (tree-map-replace comp (.-left tree) k v) (.-right tree))
+ :else (.replace tree tk (.-val tree) (.-left tree) (tree-map-replace comp (.-right tree) k v)))))
+
+(declare key)
+
+(deftype PersistentTreeMap [comp tree cnt meta ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+
+ ;; EXPERIMENTAL: subject to change
+ (keys [coll]
+ (es6-iterator (keys coll)))
+ (entries [coll]
+ (es6-entries-iterator (seq coll)))
+ (values [coll]
+ (es6-iterator (vals coll)))
+ (has [coll k]
+ (contains? coll k))
+ (get [coll k not-found]
+ (-lookup coll k not-found))
+ (forEach [coll f]
+ (doseq [[k v] coll]
+ (f v k)))
+
+ (entry-at [coll k]
+ (loop [t tree]
+ (if-not (nil? t)
+ (let [c (comp k (.-key t))]
+ (cond (zero? c) t
+ (neg? c) (recur (.-left t))
+ :else (recur (.-right t)))))))
+
+ ICloneable
+ (-clone [_] (PersistentTreeMap. comp tree cnt meta __hash))
+
+ IWithMeta
+ (-with-meta [coll meta] (PersistentTreeMap. comp tree cnt meta __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ICollection
+ (-conj [coll entry]
+ (if (vector? entry)
+ (-assoc coll (-nth entry 0) (-nth entry 1))
+ (loop [ret coll es (seq entry)]
+ (if (nil? es)
+ ret
+ (let [e (first es)]
+ (if (vector? e)
+ (recur (-assoc ret (-nth e 0) (-nth e 1))
+ (next es))
+ (throw (js/Error. "conj on a map takes map entries or seqables of map entries"))))))))
+
+ IEmptyableCollection
+ (-empty [coll] (PersistentTreeMap. comp nil 0 meta 0))
+
+ IEquiv
+ (-equiv [coll other] (equiv-map coll other))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-unordered-coll __hash))
+
+ ICounted
+ (-count [coll] cnt)
+
+ IKVReduce
+ (-kv-reduce [coll f init]
+ (if-not (nil? tree)
+ (unreduced (tree-map-kv-reduce tree f init))
+ init))
+
+ IFn
+ (-invoke [coll k]
+ (-lookup coll k))
+
+ (-invoke [coll k not-found]
+ (-lookup coll k not-found))
+
+ ISeqable
+ (-seq [coll]
+ (if (pos? cnt)
+ (create-tree-map-seq tree true cnt)))
+
+ IReversible
+ (-rseq [coll]
+ (if (pos? cnt)
+ (create-tree-map-seq tree false cnt)))
+
+ ILookup
+ (-lookup [coll k]
+ (-lookup coll k nil))
+
+ (-lookup [coll k not-found]
+ (let [n (.entry-at coll k)]
+ (if-not (nil? n)
+ (.-val n)
+ not-found)))
+
+ IAssociative
+ (-assoc [coll k v]
+ (let [found (array nil)
+ t (tree-map-add comp tree k v found)]
+ (if (nil? t)
+ (let [found-node (nth found 0)]
+ (if (= v (.-val found-node))
+ coll
+ (PersistentTreeMap. comp (tree-map-replace comp tree k v) cnt meta nil)))
+ (PersistentTreeMap. comp (.blacken t) (inc cnt) meta nil))))
+
+ (-contains-key? [coll k]
+ (not (nil? (.entry-at coll k))))
+
+ IFind
+ (-find [coll k]
+ (.entry-at coll k))
+
+ IMap
+ (-dissoc [coll k]
+ (let [found (array nil)
+ t (tree-map-remove comp tree k found)]
+ (if (nil? t)
+ (if (nil? (nth found 0))
+ coll
+ (PersistentTreeMap. comp nil 0 meta nil))
+ (PersistentTreeMap. comp (.blacken t) (dec cnt) meta nil))))
+
+ ISorted
+ (-sorted-seq [coll ascending?]
+ (if (pos? cnt)
+ (create-tree-map-seq tree ascending? cnt)))
+
+ (-sorted-seq-from [coll k ascending?]
+ (if (pos? cnt)
+ (loop [stack nil t tree]
+ (if-not (nil? t)
+ (let [c (comp k (.-key t))]
+ (cond
+ (zero? c) (PersistentTreeMapSeq. nil (conj stack t) ascending? -1 nil)
+ ascending? (if (neg? c)
+ (recur (conj stack t) (.-left t))
+ (recur stack (.-right t)))
+ :else (if (pos? c)
+ (recur (conj stack t) (.-right t))
+ (recur stack (.-left t)))))
+ (when-not (nil? stack)
+ (PersistentTreeMapSeq. nil stack ascending? -1 nil))))))
+
+ (-entry-key [coll entry] (key entry))
+
+ (-comparator [coll] comp))
+
+(set! (.-EMPTY PersistentTreeMap) (PersistentTreeMap. compare nil 0 nil empty-unordered-hash))
+
+(es6-iterable PersistentTreeMap)
+
+(defn hash-map
+ "keyval => key val
+ Returns a new hash map with supplied mappings."
+ [& keyvals]
+ (loop [in (seq keyvals), out (transient (.-EMPTY PersistentHashMap))]
+ (if in
+ (recur (nnext in) (assoc! out (first in) (second in)))
+ (persistent! out))))
+
+(defn array-map
+ "keyval => key val
+ Returns a new array map with supplied mappings."
+ [& keyvals]
+ (let [arr (if (and (instance? IndexedSeq keyvals) (zero? (.-i keyvals)))
+ (.-arr keyvals)
+ (into-array keyvals))]
+ (.createAsIfByAssoc PersistentArrayMap arr)))
+
+(defn obj-map
+ "keyval => key val
+ Returns a new object map with supplied mappings."
+ [& keyvals]
+ (let [ks (array)
+ obj (js-obj)]
+ (loop [kvs (seq keyvals)]
+ (if kvs
+ (do (.push ks (first kvs))
+ (gobject/set obj (first kvs) (second kvs))
+ (recur (nnext kvs)))
+ (.fromObject ObjMap ks obj)))))
+
+(defn sorted-map
+ "keyval => key val
+ Returns a new sorted map with supplied mappings."
+ ([& keyvals]
+ (loop [in (seq keyvals) out (.-EMPTY PersistentTreeMap)]
+ (if in
+ (recur (nnext in) (assoc out (first in) (second in)))
+ out))))
+
+(defn sorted-map-by
+ "keyval => key val
+ Returns a new sorted map with supplied mappings, using the supplied comparator."
+ ([comparator & keyvals]
+ (loop [in (seq keyvals)
+ out (PersistentTreeMap. (fn->comparator comparator) nil 0 nil 0)]
+ (if in
+ (recur (nnext in) (assoc out (first in) (second in)))
+ out))))
+
+(deftype KeySeq [^not-native mseq _meta]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IMeta
+ (-meta [coll] _meta)
+
+ IWithMeta
+ (-with-meta [coll new-meta] (KeySeq. mseq new-meta))
+
+ ISeqable
+ (-seq [coll] coll)
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ ICollection
+ (-conj [coll o]
+ (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) _meta))
+
+ IHash
+ (-hash [coll] (hash-ordered-coll coll))
+
+ ISeq
+ (-first [coll]
+ (let [^not-native me (-first mseq)]
+ (-key me)))
+
+ (-rest [coll]
+ (let [nseq (if (satisfies? INext mseq)
+ (-next mseq)
+ (next mseq))]
+ (if-not (nil? nseq)
+ (KeySeq. nseq _meta)
+ ())))
+
+ INext
+ (-next [coll]
+ (let [nseq (if (satisfies? INext mseq)
+ (-next mseq)
+ (next mseq))]
+ (when-not (nil? nseq)
+ (KeySeq. nseq _meta))))
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(es6-iterable KeySeq)
+
+(defn keys
+ "Returns a sequence of the map's keys."
+ [hash-map]
+ (when-let [mseq (seq hash-map)]
+ (KeySeq. mseq nil)))
+
+(defn key
+ "Returns the key of the map entry."
+ [map-entry]
+ (-key map-entry))
+
+(deftype ValSeq [^not-native mseq _meta]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ IMeta
+ (-meta [coll] _meta)
+
+ IWithMeta
+ (-with-meta [coll new-meta] (ValSeq. mseq new-meta))
+
+ ISeqable
+ (-seq [coll] coll)
+
+ ISequential
+ IEquiv
+ (-equiv [coll other] (equiv-sequential coll other))
+
+ ICollection
+ (-conj [coll o]
+ (cons o coll))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY List) _meta))
+
+ IHash
+ (-hash [coll] (hash-ordered-coll coll))
+
+ ISeq
+ (-first [coll]
+ (let [^not-native me (-first mseq)]
+ (-val me)))
+
+ (-rest [coll]
+ (let [nseq (if (satisfies? INext mseq)
+ (-next mseq)
+ (next mseq))]
+ (if-not (nil? nseq)
+ (ValSeq. nseq _meta)
+ ())))
+
+ INext
+ (-next [coll]
+ (let [nseq (if (satisfies? INext mseq)
+ (-next mseq)
+ (next mseq))]
+ (when-not (nil? nseq)
+ (ValSeq. nseq _meta))))
+
+ IReduce
+ (-reduce [coll f] (seq-reduce f coll))
+ (-reduce [coll f start] (seq-reduce f start coll)))
+
+(es6-iterable ValSeq)
+
+(defn vals
+ "Returns a sequence of the map's values."
+ [hash-map]
+ (when-let [mseq (seq hash-map)]
+ (ValSeq. mseq nil)))
+
+(defn val
+ "Returns the value in the map entry."
+ [map-entry]
+ (-val map-entry))
+
+(defn merge
+ "Returns a map that consists of the rest of the maps conj-ed onto
+ the first. If a key occurs in more than one map, the mapping from
+ the latter (left-to-right) will be the mapping in the result."
+ [& maps]
+ (when (some identity maps)
+ (reduce #(conj (or %1 {}) %2) maps)))
+
+(defn merge-with
+ "Returns a map that consists of the rest of the maps conj-ed onto
+ the first. If a key occurs in more than one map, the mapping(s)
+ from the latter (left-to-right) will be combined with the mapping in
+ the result by calling (f val-in-result val-in-latter)."
+ [f & maps]
+ (when (some identity maps)
+ (let [merge-entry (fn [m e]
+ (let [k (key e) v (val e)]
+ (if (contains? m k)
+ (assoc m k (f (get m k) v))
+ (assoc m k v))))
+ merge2 (fn [m1 m2]
+ (reduce merge-entry (or m1 {}) (seq m2)))]
+ (reduce merge2 maps))))
+
+(defn select-keys
+ "Returns a map containing only those entries in map whose key is in keys"
+ [map keyseq]
+ (loop [ret {} keys (seq keyseq)]
+ (if keys
+ (let [key (first keys)
+ entry (get map key ::not-found)]
+ (recur
+ (if (not= entry ::not-found)
+ (assoc ret key entry)
+ ret)
+ (next keys)))
+ (-with-meta ret (meta map)))))
+
+;;; PersistentHashSet
+
+(declare TransientHashSet)
+
+(deftype HashSetIter [iter]
+ Object
+ (hasNext [_]
+ (.hasNext iter))
+ (next [_]
+ (if ^boolean (.hasNext iter)
+ (.-key (.next iter))
+ (throw (js/Error. "No such element"))))
+ (remove [_] (js/Error. "Unsupported operation")))
+
+(deftype PersistentHashSet [meta hash-map ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+
+ ;; EXPERIMENTAL: subject to change
+ (keys [coll]
+ (es6-iterator (seq coll)))
+ (entries [coll]
+ (es6-set-entries-iterator (seq coll)))
+ (values [coll]
+ (es6-iterator (seq coll)))
+ (has [coll k]
+ (contains? coll k))
+ (forEach [coll f]
+ (doseq [[k v] coll]
+ (f v k)))
+
+ ICloneable
+ (-clone [_] (PersistentHashSet. meta hash-map __hash))
+
+ IIterable
+ (-iterator [coll]
+ (HashSetIter. (-iterator hash-map)))
+
+ IWithMeta
+ (-with-meta [coll meta] (PersistentHashSet. meta hash-map __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ICollection
+ (-conj [coll o]
+ (PersistentHashSet. meta (assoc hash-map o nil) nil))
+
+ IEmptyableCollection
+ (-empty [coll] (-with-meta (.-EMPTY PersistentHashSet) meta))
+
+ IEquiv
+ (-equiv [coll other]
+ (and
+ (set? other)
+ (== (count coll) (count other))
+ ^boolean
+ (try
+ (reduce-kv
+ #(or (contains? other %2) (reduced false))
+ true hash-map)
+ (catch js/Error ex
+ false))))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-unordered-coll __hash))
+
+ ISeqable
+ (-seq [coll] (keys hash-map))
+
+ ICounted
+ (-count [coll] (-count hash-map))
+
+ ILookup
+ (-lookup [coll v]
+ (-lookup coll v nil))
+ (-lookup [coll v not-found]
+ (if-let [entry (-find hash-map v)]
+ (key entry)
+ not-found))
+
+ ISet
+ (-disjoin [coll v]
+ (PersistentHashSet. meta (-dissoc hash-map v) nil))
+
+ IFn
+ (-invoke [coll k]
+ (-lookup coll k))
+ (-invoke [coll k not-found]
+ (-lookup coll k not-found))
+
+ IEditableCollection
+ (-as-transient [coll] (TransientHashSet. (-as-transient hash-map))))
+
+(set! (.-EMPTY PersistentHashSet)
+ (PersistentHashSet. nil (.-EMPTY PersistentArrayMap) empty-unordered-hash))
+
+(set! (.-fromArray PersistentHashSet)
+ (fn [items ^boolean no-clone]
+ (let [len (alength items)]
+ (if (<= len (.-HASHMAP-THRESHOLD PersistentArrayMap))
+ (let [arr (if no-clone items (aclone items))]
+ (loop [i 0
+ out (transient (.-EMPTY PersistentArrayMap))]
+ (if (< i len)
+ (recur (inc i) (-assoc! out (aget items i) nil))
+ (PersistentHashSet. nil (-persistent! out) nil))))
+ (loop [i 0
+ out (transient (.-EMPTY PersistentHashSet))]
+ (if (< i len)
+ (recur (inc i) (-conj! out (aget items i)))
+ (-persistent! out)))))))
+
+(set! (.-createWithCheck PersistentHashSet)
+ (fn [items]
+ (let [len (alength items)
+ t (-as-transient (.-EMPTY PersistentHashSet))]
+ (dotimes [i len]
+ (-conj! t (aget items i))
+ (when-not (= (count t) (inc i))
+ (throw (js/Error. (str "Duplicate key: " (aget items i))))))
+ (-persistent! t))))
+
+(set! (.-createAsIfByAssoc PersistentHashSet)
+ (fn [items]
+ (let [len (alength items)
+ t (-as-transient (.-EMPTY PersistentHashSet))]
+ (dotimes [i len] (-conj! t (aget items i)))
+ (-persistent! t))))
+
+(es6-iterable PersistentHashSet)
+
+(deftype TransientHashSet [^:mutable transient-map]
+ ITransientCollection
+ (-conj! [tcoll o]
+ (set! transient-map (assoc! transient-map o nil))
+ tcoll)
+
+ (-persistent! [tcoll]
+ (PersistentHashSet. nil (persistent! transient-map) nil))
+
+ ITransientSet
+ (-disjoin! [tcoll v]
+ (set! transient-map (dissoc! transient-map v))
+ tcoll)
+
+ ICounted
+ (-count [tcoll] (count transient-map))
+
+ ILookup
+ (-lookup [tcoll v]
+ (-lookup tcoll v nil))
+
+ (-lookup [tcoll v not-found]
+ (if (identical? (-lookup transient-map v lookup-sentinel) lookup-sentinel)
+ not-found
+ v))
+
+ IFn
+ (-invoke [tcoll k]
+ (if (identical? (-lookup transient-map k lookup-sentinel) lookup-sentinel)
+ nil
+ k))
+
+ (-invoke [tcoll k not-found]
+ (if (identical? (-lookup transient-map k lookup-sentinel) lookup-sentinel)
+ not-found
+ k)))
+
+(deftype PersistentTreeSet [meta tree-map ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+
+ ;; EXPERIMENTAL: subject to change
+ (keys [coll]
+ (es6-iterator (seq coll)))
+ (entries [coll]
+ (es6-set-entries-iterator (seq coll)))
+ (values [coll]
+ (es6-iterator (seq coll)))
+ (has [coll k]
+ (contains? coll k))
+ (forEach [coll f]
+ (doseq [[k v] coll]
+ (f v k)))
+
+ ICloneable
+ (-clone [_] (PersistentTreeSet. meta tree-map __hash))
+
+ IWithMeta
+ (-with-meta [coll meta] (PersistentTreeSet. meta tree-map __hash))
+
+ IMeta
+ (-meta [coll] meta)
+
+ ICollection
+ (-conj [coll o]
+ (PersistentTreeSet. meta (assoc tree-map o nil) nil))
+
+ IEmptyableCollection
+ (-empty [coll] (PersistentTreeSet. meta (-empty tree-map) 0))
+
+ IEquiv
+ (-equiv [coll other]
+ (and
+ (set? other)
+ (== (count coll) (count other))
+ ^boolean
+ (try
+ (reduce-kv
+ #(or (contains? other %2) (reduced false))
+ true tree-map)
+ (catch js/Error ex
+ false))))
+
+ IHash
+ (-hash [coll] (caching-hash coll hash-unordered-coll __hash))
+
+ ISeqable
+ (-seq [coll] (keys tree-map))
+
+ ISorted
+ (-sorted-seq [coll ascending?]
+ (map key (-sorted-seq tree-map ascending?)))
+
+ (-sorted-seq-from [coll k ascending?]
+ (map key (-sorted-seq-from tree-map k ascending?)))
+
+ (-entry-key [coll entry] entry)
+
+ (-comparator [coll] (-comparator tree-map))
+
+ IReversible
+ (-rseq [coll]
+ (if (pos? (count tree-map))
+ (map key (rseq tree-map))))
+
+ ICounted
+ (-count [coll] (count tree-map))
+
+ ILookup
+ (-lookup [coll v]
+ (-lookup coll v nil))
+ (-lookup [coll v not-found]
+ (let [n (.entry-at tree-map v)]
+ (if-not (nil? n)
+ (.-key n)
+ not-found)))
+
+ ISet
+ (-disjoin [coll v]
+ (PersistentTreeSet. meta (dissoc tree-map v) nil))
+
+ IFn
+ (-invoke [coll k]
+ (-lookup coll k))
+ (-invoke [coll k not-found]
+ (-lookup coll k not-found)))
+
+(set! (.-EMPTY PersistentTreeSet)
+ (PersistentTreeSet. nil (.-EMPTY PersistentTreeMap) empty-unordered-hash))
+
+(es6-iterable PersistentTreeSet)
+
+(defn set-from-indexed-seq [iseq]
+ (let [arr (.-arr iseq)
+ ret (areduce arr i ^not-native res (-as-transient #{})
+ (-conj! res (aget arr i)))]
+ (-persistent! ^not-native ret)))
+
+(defn set
+ "Returns a set of the distinct elements of coll."
+ [coll]
+ (if (set? coll)
+ (with-meta coll nil)
+ (let [in (seq coll)]
+ (cond
+ (nil? in) #{}
+
+ (and (instance? IndexedSeq in) (zero? (.-i in)))
+ (.createAsIfByAssoc PersistentHashSet (.-arr in))
+
+ :else
+ (loop [^not-native in in
+ ^not-native out (-as-transient #{})]
+ (if-not (nil? in)
+ (recur (next in) (-conj! out (-first in)))
+ (persistent! out)))))))
+
+(defn hash-set
+ "Returns a new hash set with supplied keys. Any equal keys are
+ handled as if by repeated uses of conj."
+ ([] #{})
+ ([& keys] (set keys)))
+
+(defn sorted-set
+ "Returns a new sorted set with supplied keys."
+ ([& keys]
+ (reduce -conj (.-EMPTY PersistentTreeSet) keys)))
+
+(defn sorted-set-by
+ "Returns a new sorted set with supplied keys, using the supplied comparator."
+ ([comparator & keys]
+ (reduce -conj
+ (PersistentTreeSet. nil (sorted-map-by comparator) 0)
+ keys)))
+
+(defn replace
+ "Given a map of replacement pairs and a vector/collection, returns a
+ vector/seq with any elements = a key in smap replaced with the
+ corresponding val in smap. Returns a transducer when no collection
+ is provided."
+ ([smap]
+ (map #(if-let [e (find smap %)] (val e) %)))
+ ([smap coll]
+ (if (vector? coll)
+ (let [n (count coll)]
+ (reduce (fn [v i]
+ (if-let [e (find smap (nth v i))]
+ (assoc v i (second e))
+ v))
+ coll (take n (iterate inc 0))))
+ (map #(if-let [e (find smap %)] (second e) %) coll))))
+
+(defn distinct
+ "Returns a lazy sequence of the elements of coll with duplicates removed.
+ Returns a stateful transducer when no collection is provided."
+ ([]
+ (fn [rf]
+ (let [seen (volatile! #{})]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (if (contains? @seen input)
+ result
+ (do (vswap! seen conj input)
+ (rf result input))))))))
+ ([coll]
+ (let [step (fn step [xs seen]
+ (lazy-seq
+ ((fn [[f :as xs] seen]
+ (when-let [s (seq xs)]
+ (if (contains? seen f)
+ (recur (rest s) seen)
+ (cons f (step (rest s) (conj seen f))))))
+ xs seen)))]
+ (step coll #{}))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defn butlast
+ "Return a seq of all but the last item in coll, in linear time"
+ [s]
+ (loop [ret [] s s]
+ (if (next s)
+ (recur (conj ret (first s)) (next s))
+ (seq ret))))
+
+(defn name
+ "Returns the name String of a string, symbol or keyword."
+ [x]
+ (if (implements? INamed x)
+ (-name ^not-native x)
+ (if (string? x)
+ x
+ (throw (js/Error. (str "Doesn't support name: " x))))))
+
+(defn zipmap
+ "Returns a map with the keys mapped to the corresponding vals."
+ [keys vals]
+ (loop [map (transient {})
+ ks (seq keys)
+ vs (seq vals)]
+ (if (and ks vs)
+ (recur (assoc! map (first ks) (first vs))
+ (next ks)
+ (next vs))
+ (persistent! map))))
+
+(defn max-key
+ "Returns the x for which (k x), a number, is greatest.
+
+ If there are multiple such xs, the last one is returned."
+ ([k x] x)
+ ([k x y] (if (> (k x) (k y)) x y))
+ ([k x y & more]
+ (reduce #(max-key k %1 %2) (max-key k x y) more)))
+
+(defn min-key
+ "Returns the x for which (k x), a number, is least.
+
+ If there are multiple such xs, the last one is returned."
+ ([k x] x)
+ ([k x y] (if (< (k x) (k y)) x y))
+ ([k x y & more]
+ (reduce #(min-key k %1 %2) (min-key k x y) more)))
+
+(deftype ArrayList [^:mutable arr]
+ Object
+ (add [_ x] (.push arr x))
+ (size [_] (alength arr))
+ (clear [_] (set! arr (array)))
+ (isEmpty [_] (zero? (alength arr)))
+ (toArray [_] arr))
+
+(defn array-list []
+ (ArrayList. (array)))
+
+(defn partition-all
+ "Returns a lazy sequence of lists like partition, but may include
+ partitions with fewer than n items at the end. Returns a stateful
+ transducer when no collection is provided."
+ ([n]
+ (fn [rf]
+ (let [a (array-list)]
+ (fn
+ ([] (rf))
+ ([result]
+ (let [result (if (.isEmpty a)
+ result
+ (let [v (vec (.toArray a))]
+ ;;clear first!
+ (.clear a)
+ (unreduced (rf result v))))]
+ (rf result)))
+ ([result input]
+ (.add a input)
+ (if (== n (.size a))
+ (let [v (vec (.toArray a))]
+ (.clear a)
+ (rf result v))
+ result))))))
+ ([n coll]
+ (partition-all n n coll))
+ ([n step coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (cons (take n s) (partition-all n step (drop step s)))))))
+
+(defn take-while
+ "Returns a lazy sequence of successive items from coll while
+ (pred item) returns logical true. pred must be free of side-effects.
+ Returns a transducer when no collection is provided."
+ ([pred]
+ (fn [rf]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (if (pred input)
+ (rf result input)
+ (reduced result))))))
+ ([pred coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (when (pred (first s))
+ (cons (first s) (take-while pred (rest s))))))))
+
+(defn mk-bound-fn
+ [sc test key]
+ (fn [e]
+ (let [comp (-comparator sc)]
+ (test (comp (-entry-key sc e) key) 0))))
+
+(defn subseq
+ "sc must be a sorted collection, test(s) one of <, <=, > or
+ >=. Returns a seq of those entries with keys ek for
+ which (test (.. sc comparator (compare ek key)) 0) is true"
+ ([sc test key]
+ (let [include (mk-bound-fn sc test key)]
+ (if (#{> >=} test)
+ (when-let [[e :as s] (-sorted-seq-from sc key true)]
+ (if (include e) s (next s)))
+ (take-while include (-sorted-seq sc true)))))
+ ([sc start-test start-key end-test end-key]
+ (when-let [[e :as s] (-sorted-seq-from sc start-key true)]
+ (take-while (mk-bound-fn sc end-test end-key)
+ (if ((mk-bound-fn sc start-test start-key) e) s (next s))))))
+
+(defn rsubseq
+ "sc must be a sorted collection, test(s) one of <, <=, > or
+ >=. Returns a reverse seq of those entries with keys ek for
+ which (test (.. sc comparator (compare ek key)) 0) is true"
+ ([sc test key]
+ (let [include (mk-bound-fn sc test key)]
+ (if (#{< <=} test)
+ (when-let [[e :as s] (-sorted-seq-from sc key false)]
+ (if (include e) s (next s)))
+ (take-while include (-sorted-seq sc false)))))
+ ([sc start-test start-key end-test end-key]
+ (when-let [[e :as s] (-sorted-seq-from sc end-key false)]
+ (take-while (mk-bound-fn sc start-test start-key)
+ (if ((mk-bound-fn sc end-test end-key) e) s (next s))))))
+
+(deftype RangeIterator [^:mutable i end step]
+ Object
+ (hasNext [_]
+ (if (pos? step)
+ (< i end)
+ (> i end)))
+ (next [_]
+ (let [ret i]
+ (set! i (+ i step))
+ ret)))
+
+(deftype Range [meta start end step ^:mutable __hash]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+ (equiv [this other]
+ (-equiv this other))
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ ICloneable
+ (-clone [_] (Range. meta start end step __hash))
+
+ IWithMeta
+ (-with-meta [rng meta] (Range. meta start end step __hash))
+
+ IMeta
+ (-meta [rng] meta)
+
+ ISeqable
+ (-seq [rng]
+ (cond
+ (pos? step) (when (< start end) rng)
+ (neg? step) (when (> start end) rng)
+ :else (when-not (== start end) rng)))
+
+ ISeq
+ (-first [rng]
+ (when-not (nil? (-seq rng)) start))
+ (-rest [rng]
+ (if-not (nil? (-seq rng))
+ (Range. meta (+ start step) end step nil)
+ ()))
+
+ IIterable
+ (-iterator [_]
+ (RangeIterator. start end step))
+
+ INext
+ (-next [rng]
+ (if (pos? step)
+ (when (< (+ start step) end)
+ (Range. meta (+ start step) end step nil))
+ (when (> (+ start step) end)
+ (Range. meta (+ start step) end step nil))))
+
+ ICollection
+ (-conj [rng o] (cons o rng))
+
+ IEmptyableCollection
+ (-empty [rng] (-with-meta (.-EMPTY List) meta))
+
+ ISequential
+ IEquiv
+ (-equiv [rng other] (equiv-sequential rng other))
+
+ IHash
+ (-hash [rng] (caching-hash rng hash-ordered-coll __hash))
+
+ ICounted
+ (-count [rng]
+ (if-not (-seq rng)
+ 0
+ (Math/ceil (/ (- end start) step))))
+
+ IIndexed
+ (-nth [rng n]
+ (if (and (<= 0 n) (< n (-count rng)))
+ (+ start (* n step))
+ (if (and (<= 0 n) (> start end) (zero? step))
+ start
+ (throw (js/Error. "Index out of bounds")))))
+ (-nth [rng n not-found]
+ (if (and (<= 0 n) (< n (-count rng)))
+ (+ start (* n step))
+ (if (and (<= 0 n) (> start end) (zero? step))
+ start
+ not-found)))
+
+ IReduce
+ (-reduce [rng f] (ci-reduce rng f))
+ (-reduce [rng f init]
+ (loop [i start ret init]
+ (if (if (pos? step) (< i end) (> i end))
+ (let [ret (f ret i)]
+ (if (reduced? ret)
+ @ret
+ (recur (+ i step) ret)))
+ ret))))
+
+(es6-iterable Range)
+
+(defn range
+ "Returns a lazy seq of nums from start (inclusive) to end
+ (exclusive), by step, where start defaults to 0, step to 1,
+ and end to infinity."
+ ([] (range 0 (.-MAX_VALUE js/Number) 1))
+ ([end] (range 0 end 1))
+ ([start end] (range start end 1))
+ ([start end step] (Range. nil start end step nil)))
+
+(defn take-nth
+ "Returns a lazy seq of every nth item in coll. Returns a stateful
+ transducer when no collection is provided."
+ ([n]
+ {:pre [(number? n)]}
+ (fn [rf]
+ (let [ia (volatile! -1)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (let [i (vswap! ia inc)]
+ (if (zero? (rem i n))
+ (rf result input)
+ result)))))))
+ ([n coll]
+ {:pre [(number? n)]}
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (cons (first s) (take-nth n (drop n s)))))))
+
+(defn split-with
+ "Returns a vector of [(take-while pred coll) (drop-while pred coll)]"
+ [pred coll]
+ [(take-while pred coll) (drop-while pred coll)])
+
+(defn partition-by
+ "Applies f to each value in coll, splitting it each time f returns a
+ new value. Returns a lazy seq of partitions. Returns a stateful
+ transducer when no collection is provided."
+ ([f]
+ (fn [rf]
+ (let [a (array-list)
+ pa (volatile! ::none)]
+ (fn
+ ([] (rf))
+ ([result]
+ (let [result (if (.isEmpty a)
+ result
+ (let [v (vec (.toArray a))]
+ ;;clear first!
+ (.clear a)
+ (unreduced (rf result v))))]
+ (rf result)))
+ ([result input]
+ (let [pval @pa
+ val (f input)]
+ (vreset! pa val)
+ (if (or (keyword-identical? pval ::none)
+ (= val pval))
+ (do
+ (.add a input)
+ result)
+ (let [v (vec (.toArray a))]
+ (.clear a)
+ (let [ret (rf result v)]
+ (when-not (reduced? ret)
+ (.add a input))
+ ret)))))))))
+ ([f coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (let [fst (first s)
+ fv (f fst)
+ run (cons fst (take-while #(= fv (f %)) (next s)))]
+ (cons run (partition-by f (lazy-seq (drop (count run) s)))))))))
+
+(defn frequencies
+ "Returns a map from distinct items in coll to the number of times
+ they appear."
+ [coll]
+ (persistent!
+ (reduce (fn [counts x]
+ (assoc! counts x (inc (get counts x 0))))
+ (transient {}) coll)))
+
+(defn reductions
+ "Returns a lazy seq of the intermediate values of the reduction (as
+ per reduce) of coll by f, starting with init."
+ ([f coll]
+ (lazy-seq
+ (if-let [s (seq coll)]
+ (reductions f (first s) (rest s))
+ (list (f)))))
+ ([f init coll]
+ (if (reduced? init)
+ (list @init)
+ (cons init
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (reductions f (f init (first s)) (rest s))))))))
+
+(defn juxt
+ "Takes a set of functions and returns a fn that is the juxtaposition
+ of those fns. The returned fn takes a variable number of args, and
+ returns a vector containing the result of applying each fn to the
+ args (left-to-right).
+ ((juxt a b c) x) => [(a x) (b x) (c x)]"
+ ([f]
+ (fn
+ ([] (vector (f)))
+ ([x] (vector (f x)))
+ ([x y] (vector (f x y)))
+ ([x y z] (vector (f x y z)))
+ ([x y z & args] (vector (apply f x y z args)))))
+ ([f g]
+ (fn
+ ([] (vector (f) (g)))
+ ([x] (vector (f x) (g x)))
+ ([x y] (vector (f x y) (g x y)))
+ ([x y z] (vector (f x y z) (g x y z)))
+ ([x y z & args] (vector (apply f x y z args) (apply g x y z args)))))
+ ([f g h]
+ (fn
+ ([] (vector (f) (g) (h)))
+ ([x] (vector (f x) (g x) (h x)))
+ ([x y] (vector (f x y) (g x y) (h x y)))
+ ([x y z] (vector (f x y z) (g x y z) (h x y z)))
+ ([x y z & args] (vector (apply f x y z args) (apply g x y z args) (apply h x y z args)))))
+ ([f g h & fs]
+ (let [fs (list* f g h fs)]
+ (fn
+ ([] (reduce #(conj %1 (%2)) [] fs))
+ ([x] (reduce #(conj %1 (%2 x)) [] fs))
+ ([x y] (reduce #(conj %1 (%2 x y)) [] fs))
+ ([x y z] (reduce #(conj %1 (%2 x y z)) [] fs))
+ ([x y z & args] (reduce #(conj %1 (apply %2 x y z args)) [] fs))))))
+
+(defn dorun
+ "When lazy sequences are produced via functions that have side
+ effects, any effects other than those needed to produce the first
+ element in the seq do not occur until the seq is consumed. dorun can
+ be used to force any effects. Walks through the successive nexts of
+ the seq, does not retain the head and returns nil."
+ ([coll]
+ (when-let [s (seq coll)]
+ (recur (next s))))
+ ([n coll]
+ (when (and (seq coll) (pos? n))
+ (recur (dec n) (next coll)))))
+
+(defn doall
+ "When lazy sequences are produced via functions that have side
+ effects, any effects other than those needed to produce the first
+ element in the seq do not occur until the seq is consumed. doall can
+ be used to force any effects. Walks through the successive nexts of
+ the seq, retains the head and returns it, thus causing the entire
+ seq to reside in memory at one time."
+ ([coll]
+ (dorun coll)
+ coll)
+ ([n coll]
+ (dorun n coll)
+ coll))
+
+;;;;;;;;;;;;;;;;;;;;;;;;; Regular Expressions ;;;;;;;;;;
+
+(defn ^boolean regexp?
+ "Returns true if x is a JavaScript RegExp instance."
+ [x]
+ (instance? js/RegExp x))
+
+(defn re-matches
+ "Returns the result of (re-find re s) if re fully matches s."
+ [re s]
+ (if (string? s)
+ (let [matches (.exec re s)]
+ (when (= (first matches) s)
+ (if (== (count matches) 1)
+ (first matches)
+ (vec matches))))
+ (throw (js/TypeError. "re-matches must match against a string."))))
+
+
+(defn re-find
+ "Returns the first regex match, if any, of s to re, using
+ re.exec(s). Returns a vector, containing first the matching
+ substring, then any capturing groups if the regular expression contains
+ capturing groups."
+ [re s]
+ (if (string? s)
+ (let [matches (.exec re s)]
+ (when-not (nil? matches)
+ (if (== (count matches) 1)
+ (first matches)
+ (vec matches))))
+ (throw (js/TypeError. "re-find must match against a string."))))
+
+(defn re-seq
+ "Returns a lazy sequence of successive matches of re in s."
+ [re s]
+ (let [match-data (re-find re s)
+ match-idx (.search s re)
+ match-str (if (coll? match-data) (first match-data) match-data)
+ post-idx (+ match-idx (max 1 (count match-str)))
+ post-match (subs s post-idx)]
+ (when match-data (lazy-seq (cons match-data (when (<= post-idx (count s)) (re-seq re post-match)))))))
+
+(defn re-pattern
+ "Returns an instance of RegExp which has compiled the provided string."
+ [s]
+ (if (instance? js/RegExp s)
+ s
+ (let [[prefix flags] (re-find #"^\(\?([idmsux]*)\)" s)
+ pattern (subs s (count prefix))]
+ (js/RegExp. pattern (or flags "")))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Printing ;;;;;;;;;;;;;;;;
+
+(defn pr-sequential-writer [writer print-one begin sep end opts coll]
+ (binding [*print-level* (when-not (nil? *print-level*) (dec *print-level*))]
+ (if (and (not (nil? *print-level*)) (neg? *print-level*))
+ (-write writer "#")
+ (do
+ (-write writer begin)
+ (if (zero? (:print-length opts))
+ (when (seq coll)
+ (-write writer (or (:more-marker opts) "...")))
+ (do
+ (when (seq coll)
+ (print-one (first coll) writer opts))
+ (loop [coll (next coll) n (dec (:print-length opts))]
+ (if (and coll (or (nil? n) (not (zero? n))))
+ (do
+ (-write writer sep)
+ (print-one (first coll) writer opts)
+ (recur (next coll) (dec n)))
+ (when (and (seq coll) (zero? n))
+ (-write writer sep)
+ (-write writer (or (:more-marker opts) "...")))))))
+ (-write writer end)))))
+
+(defn write-all [writer & ss]
+ (doseq [s ss]
+ (-write writer s)))
+
+(defn string-print [x]
+ (when (nil? *print-fn*)
+ (throw (js/Error. "No *print-fn* fn set for evaluation environment")))
+ (*print-fn* x)
+ nil)
+
+(defn flush [] ;stub
+ nil)
+
+(def ^:private char-escapes
+ (js-obj
+ "\"" "\\\""
+ "\\" "\\\\"
+ "\b" "\\b"
+ "\f" "\\f"
+ "\n" "\\n"
+ "\r" "\\r"
+ "\t" "\\t"))
+
+(defn ^:private quote-string
+ [s]
+ (str \"
+ (.replace s (js/RegExp "[\\\\\"\b\f\n\r\t]" "g")
+ (fn [match] (unchecked-get char-escapes match)))
+ \"))
+
+(declare print-map)
+
+(defn ^boolean print-meta? [opts obj]
+ (and (boolean (get opts :meta))
+ (implements? IMeta obj)
+ (not (nil? (meta obj)))))
+
+(defn- pr-writer-impl
+ [obj writer opts]
+ (cond
+ (nil? obj) (-write writer "nil")
+ :else
+ (do
+ (when (print-meta? opts obj)
+ (-write writer "^")
+ (pr-writer (meta obj) writer opts)
+ (-write writer " "))
+ (cond
+ ;; handle CLJS ctors
+ ^boolean (.-cljs$lang$type obj)
+ (.cljs$lang$ctorPrWriter obj obj writer opts)
+
+ ; Use the new, more efficient, IPrintWithWriter interface when possible.
+ (satisfies? IPrintWithWriter obj)
+ (-pr-writer obj writer opts)
+
+ (or (true? obj) (false? obj))
+ (-write writer (str obj))
+
+ (number? obj)
+ (-write writer
+ (cond
+ ^boolean (js/isNaN obj) "##NaN"
+ (identical? obj js/Number.POSITIVE_INFINITY) "##Inf"
+ (identical? obj js/Number.NEGATIVE_INFINITY) "##-Inf"
+ :else (str obj)))
+
+ (object? obj)
+ (do
+ (-write writer "#js ")
+ (print-map
+ (map (fn [k]
+ (MapEntry. (cond-> k (some? (re-matches #"[A-Za-z_\*\+\?!\-'][\w\*\+\?!\-']*" k)) keyword) (unchecked-get obj k) nil))
+ (js-keys obj))
+ pr-writer writer opts))
+
+ (array? obj)
+ (pr-sequential-writer writer pr-writer "#js [" " " "]" opts obj)
+
+ ^boolean (goog/isString obj)
+ (if (:readably opts)
+ (-write writer (quote-string obj))
+ (-write writer obj))
+
+ ^boolean (goog/isFunction obj)
+ (let [name (.-name obj)
+ name (if (or (nil? name) (gstring/isEmpty name))
+ "Function"
+ name)]
+ (write-all writer "#object[" name
+ (if *print-fn-bodies*
+ (str " \"" (str obj) "\"")
+ "")
+ "]"))
+
+ (instance? js/Date obj)
+ (let [normalize (fn [n len]
+ (loop [ns (str n)]
+ (if (< (count ns) len)
+ (recur (str "0" ns))
+ ns)))]
+ (write-all writer
+ "#inst \""
+ (str (.getUTCFullYear obj)) "-"
+ (normalize (inc (.getUTCMonth obj)) 2) "-"
+ (normalize (.getUTCDate obj) 2) "T"
+ (normalize (.getUTCHours obj) 2) ":"
+ (normalize (.getUTCMinutes obj) 2) ":"
+ (normalize (.getUTCSeconds obj) 2) "."
+ (normalize (.getUTCMilliseconds obj) 3) "-"
+ "00:00\""))
+
+ (regexp? obj) (write-all writer "#\"" (.-source obj) "\"")
+
+ :else
+ (if (some-> obj .-constructor .-cljs$lang$ctorStr)
+ (write-all writer
+ "#object[" (.replace (.. obj -constructor -cljs$lang$ctorStr)
+ (js/RegExp. "/" "g") ".") "]")
+ (let [name (some-> obj .-constructor .-name)
+ name (if (or (nil? name) (gstring/isEmpty name))
+ "Object"
+ name)]
+ (if (nil? (. obj -constructor))
+ (write-all writer "#object[" name "]")
+ (write-all writer "#object[" name " " (str obj) "]"))))))))
+
+(defn- pr-writer
+ "Prefer this to pr-seq, because it makes the printing function
+ configurable, allowing efficient implementations such as appending
+ to a StringBuffer."
+ [obj writer opts]
+ (if-let [alt-impl (:alt-impl opts)]
+ (alt-impl obj writer (assoc opts :fallback-impl pr-writer-impl))
+ (pr-writer-impl obj writer opts)))
+
+(defn pr-seq-writer [objs writer opts]
+ (pr-writer (first objs) writer opts)
+ (doseq [obj (next objs)]
+ (-write writer " ")
+ (pr-writer obj writer opts)))
+
+(defn- pr-sb-with-opts [objs opts]
+ (let [sb (StringBuffer.)
+ writer (StringBufferWriter. sb)]
+ (pr-seq-writer objs writer opts)
+ (-flush writer)
+ sb))
+
+(defn pr-str-with-opts
+ "Prints a sequence of objects to a string, observing all the
+ options given in opts"
+ [objs opts]
+ (if (empty? objs)
+ ""
+ (str (pr-sb-with-opts objs opts))))
+
+(defn prn-str-with-opts
+ "Same as pr-str-with-opts followed by (newline)"
+ [objs opts]
+ (if (empty? objs)
+ "\n"
+ (let [sb (pr-sb-with-opts objs opts)]
+ (.append sb \newline)
+ (str sb))))
+
+(defn- pr-with-opts
+ "Prints a sequence of objects using string-print, observing all
+ the options given in opts"
+ [objs opts]
+ (string-print (pr-str-with-opts objs opts)))
+
+(defn newline
+ "Prints a newline using *print-fn*"
+ ([] (newline nil))
+ ([opts]
+ (string-print "\n")
+ (when (get opts :flush-on-newline)
+ (flush))))
+
+(defn pr-str
+ "pr to a string, returning it. Fundamental entrypoint to IPrintWithWriter."
+ [& objs]
+ (pr-str-with-opts objs (pr-opts)))
+
+(defn prn-str
+ "Same as pr-str followed by (newline)"
+ [& objs]
+ (prn-str-with-opts objs (pr-opts)))
+
+(defn pr
+ "Prints the object(s) using string-print. Prints the
+ object(s), separated by spaces if there is more than one.
+ By default, pr and prn print in a way that objects can be
+ read by the reader"
+ [& objs]
+ (pr-with-opts objs (pr-opts)))
+
+(def ^{:doc
+ "Prints the object(s) using string-print.
+ print and println produce output for human consumption."}
+ print
+ (fn cljs-core-print [& objs]
+ (pr-with-opts objs (assoc (pr-opts) :readably false))))
+
+(defn print-str
+ "print to a string, returning it"
+ [& objs]
+ (pr-str-with-opts objs (assoc (pr-opts) :readably false)))
+
+(defn println
+ "Same as print followed by (newline)"
+ [& objs]
+ (pr-with-opts objs (assoc (pr-opts) :readably false))
+ (when *print-newline*
+ (newline (pr-opts))))
+
+(defn println-str
+ "println to a string, returning it"
+ [& objs]
+ (prn-str-with-opts objs (assoc (pr-opts) :readably false)))
+
+(defn prn
+ "Same as pr followed by (newline)."
+ [& objs]
+ (pr-with-opts objs (pr-opts))
+ (when *print-newline*
+ (newline (pr-opts))))
+
+(defn- strip-ns
+ [named]
+ (if (symbol? named)
+ (symbol nil (name named))
+ (keyword nil (name named))))
+
+(defn- lift-ns
+ "Returns [lifted-ns lifted-map] or nil if m can't be lifted."
+ [m]
+ (when *print-namespace-maps*
+ (loop [ns nil
+ [[k v :as entry] & entries] (seq m)
+ lm (empty m)]
+ (if entry
+ (when (or (keyword? k) (symbol? k))
+ (if ns
+ (when (= ns (namespace k))
+ (recur ns entries (assoc lm (strip-ns k) v)))
+ (when-let [new-ns (namespace k)]
+ (recur new-ns entries (assoc lm (strip-ns k) v)))))
+ [ns lm]))))
+
+(defn print-prefix-map [prefix m print-one writer opts]
+ (pr-sequential-writer
+ writer
+ (fn [e w opts]
+ (do (print-one (key e) w opts)
+ (-write w \space)
+ (print-one (val e) w opts)))
+ (str prefix "{") ", " "}"
+ opts (seq m)))
+
+(defn print-map [m print-one writer opts]
+ (let [[ns lift-map] (when (map? m)
+ (lift-ns m))]
+ (if ns
+ (print-prefix-map (str "#:" ns) lift-map print-one writer opts)
+ (print-prefix-map nil m print-one writer opts))))
+
+(extend-protocol IPrintWithWriter
+ LazySeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ TransformerIterator
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ IndexedSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ RSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ PersistentQueue
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "#queue [" " " "]" opts (seq coll)))
+
+ PersistentQueueSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ PersistentTreeMapSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ NodeSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ ArrayNodeSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ List
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ Cons
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ EmptyList
+ (-pr-writer [coll writer opts] (-write writer "()"))
+
+ PersistentVector
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll))
+
+ ChunkedCons
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ ChunkedSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ Subvec
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll))
+
+ BlackNode
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll))
+
+ RedNode
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll))
+
+ MapEntry
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "[" " " "]" opts coll))
+
+ ObjMap
+ (-pr-writer [coll writer opts]
+ (print-map coll pr-writer writer opts))
+
+ KeySeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ ValSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ PersistentArrayMapSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ PersistentArrayMap
+ (-pr-writer [coll writer opts]
+ (print-map coll pr-writer writer opts))
+
+ PersistentHashMap
+ (-pr-writer [coll writer opts]
+ (print-map coll pr-writer writer opts))
+
+ PersistentTreeMap
+ (-pr-writer [coll writer opts]
+ (print-map coll pr-writer writer opts))
+
+ PersistentHashSet
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "#{" " " "}" opts coll))
+
+ PersistentTreeSet
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "#{" " " "}" opts coll))
+
+ Range
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ Cycle
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ Repeat
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ Iterate
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ ES6IteratorSeq
+ (-pr-writer [coll writer opts] (pr-sequential-writer writer pr-writer "(" " " ")" opts coll))
+
+ Atom
+ (-pr-writer [a writer opts]
+ (-write writer "#object [cljs.core.Atom ")
+ (pr-writer {:val (.-state a)} writer opts)
+ (-write writer "]"))
+
+ Volatile
+ (-pr-writer [a writer opts]
+ (-write writer "#object [cljs.core.Volatile ")
+ (pr-writer {:val (.-state a)} writer opts)
+ (-write writer "]"))
+
+ Var
+ (-pr-writer [a writer opts]
+ (-write writer "#'")
+ (pr-writer (.-sym a) writer opts)))
+
+;; IComparable
+(extend-protocol IComparable
+ Symbol
+ (-compare [x y]
+ (if (symbol? y)
+ (compare-symbols x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y)))))
+
+ Keyword
+ (-compare [x y]
+ (if (keyword? y)
+ (compare-keywords x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y)))))
+
+ Subvec
+ (-compare [x y]
+ (if (vector? y)
+ (compare-indexed x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y)))))
+
+ PersistentVector
+ (-compare [x y]
+ (if (vector? y)
+ (compare-indexed x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y)))))
+
+ MapEntry
+ (-compare [x y]
+ (if (vector? y)
+ (compare-indexed x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y)))))
+
+ BlackNode
+ (-compare [x y]
+ (if (vector? y)
+ (compare-indexed x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y)))))
+
+ RedNode
+ (-compare [x y]
+ (if (vector? y)
+ (compare-indexed x y)
+ (throw (js/Error. (str "Cannot compare " x " to " y))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Reference Types ;;;;;;;;;;;;;;;;
+
+(defn alter-meta!
+ "Atomically sets the metadata for a namespace/var/ref/agent/atom to be:
+
+ (apply f its-current-meta args)
+
+ f must be free of side-effects"
+ [iref f & args]
+ (set! (.-meta iref) (apply f (.-meta iref) args)))
+
+(defn reset-meta!
+ "Atomically resets the metadata for an atom"
+ [iref m]
+ (set! (.-meta iref) m))
+
+(defn add-watch
+ "Adds a watch function to an atom reference. The watch fn must be a
+ fn of 4 args: a key, the reference, its old-state, its
+ new-state. Whenever the reference's state might have been changed,
+ any registered watches will have their functions called. The watch
+ fn will be called synchronously. Note that an atom's state
+ may have changed again prior to the fn call, so use old/new-state
+ rather than derefing the reference. Keys must be unique per
+ reference, and can be used to remove the watch with remove-watch,
+ but are otherwise considered opaque by the watch mechanism. Bear in
+ mind that regardless of the result or action of the watch fns the
+ atom's value will change. Example:
+
+ (def a (atom 0))
+ (add-watch a :inc (fn [k r o n] (assert (== 0 n))))
+ (swap! a inc)
+ ;; Assertion Error
+ (deref a)
+ ;=> 1"
+ [iref key f]
+ (-add-watch iref key f)
+ iref)
+
+(defn remove-watch
+ "Removes a watch (set by add-watch) from a reference"
+ [iref key]
+ (-remove-watch iref key)
+ iref)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; gensym ;;;;;;;;;;;;;;;;
+;; Internal - do not use!
+(def
+ ^{:jsdoc ["@type {*}"]}
+ gensym_counter nil)
+
+(defn gensym
+ "Returns a new symbol with a unique name. If a prefix string is
+ supplied, the name is prefix# where # is some unique number. If
+ prefix is not supplied, the prefix is 'G__'."
+ ([] (gensym "G__"))
+ ([prefix-string]
+ (when (nil? gensym_counter)
+ (set! gensym_counter (atom 0)))
+ (symbol (str prefix-string (swap! gensym_counter inc)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Delay ;;;;;;;;;;;;;;;;;;;;
+
+(deftype Delay [^:mutable f ^:mutable value]
+ IDeref
+ (-deref [_]
+ (when f
+ (set! value (f))
+ (set! f nil))
+ value)
+
+ IPending
+ (-realized? [x]
+ (not f))
+
+ IPrintWithWriter
+ (-pr-writer [x writer opts]
+ (-write writer "#object[cljs.core.Delay ")
+ (pr-writer {:status (if (nil? f) :ready :pending), :val value} writer opts)
+ (-write writer "]")))
+
+(defn ^boolean delay?
+ "returns true if x is a Delay created with delay"
+ [x] (instance? Delay x))
+
+(defn force
+ "If x is a Delay, returns the (possibly cached) value of its expression, else returns x"
+ [x]
+ (if (delay? x)
+ (deref x)
+ x))
+
+(defn ^boolean realized?
+ "Returns true if a value has been produced for a delay or lazy sequence."
+ [x]
+ (-realized? x))
+
+(defn- preserving-reduced
+ [rf]
+ #(let [ret (rf %1 %2)]
+ (if (reduced? ret)
+ (reduced ret)
+ ret)))
+
+(defn cat
+ "A transducer which concatenates the contents of each input, which must be a
+ collection, into the reduction."
+ {:added "1.7"}
+ [rf]
+ (let [rf1 (preserving-reduced rf)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (reduce rf1 result input)))))
+
+(defn halt-when
+ "Returns a transducer that ends transduction when pred returns true
+ for an input. When retf is supplied it must be a fn of 2 arguments -
+ it will be passed the (completed) result so far and the input that
+ triggered the predicate, and its return value (if it does not throw
+ an exception) will be the return value of the transducer. If retf
+ is not supplied, the input that triggered the predicate will be
+ returned. If the predicate never returns true the transduction is
+ unaffected."
+ {:added "1.9"}
+ ([pred] (halt-when pred nil))
+ ([pred retf]
+ (fn [rf]
+ (fn
+ ([] (rf))
+ ([result]
+ (if (and (map? result) (contains? result ::halt))
+ (::halt result)
+ (rf result)))
+ ([result input]
+ (if (pred input)
+ (reduced {::halt (if retf (retf (rf result) input) input)})
+ (rf result input)))))))
+
+(defn dedupe
+ "Returns a lazy sequence removing consecutive duplicates in coll.
+ Returns a transducer when no collection is provided."
+ ([]
+ (fn [rf]
+ (let [pa (volatile! ::none)]
+ (fn
+ ([] (rf))
+ ([result] (rf result))
+ ([result input]
+ (let [prior @pa]
+ (vreset! pa input)
+ (if (= prior input)
+ result
+ (rf result input))))))))
+ ([coll] (sequence (dedupe) coll)))
+
+(declare rand)
+
+(defn random-sample
+ "Returns items from coll with random probability of prob (0.0 -
+ 1.0). Returns a transducer when no collection is provided."
+ ([prob]
+ (filter (fn [_] (< (rand) prob))))
+ ([prob coll]
+ (filter (fn [_] (< (rand) prob)) coll)))
+
+(deftype Eduction [xform coll]
+ Object
+ (indexOf [coll x]
+ (-indexOf coll x 0))
+ (indexOf [coll x start]
+ (-indexOf coll x start))
+ (lastIndexOf [coll x]
+ (-lastIndexOf coll x (count coll)))
+ (lastIndexOf [coll x start]
+ (-lastIndexOf coll x start))
+
+ ISequential
+
+ IIterable
+ (-iterator [_]
+ (.create TransformerIterator xform (iter coll)))
+
+ ISeqable
+ (-seq [_] (seq (sequence xform coll)))
+
+ IReduce
+ (-reduce [_ f] (transduce xform (completing f) coll))
+ (-reduce [_ f init] (transduce xform (completing f) init coll))
+
+ IPrintWithWriter
+ (-pr-writer [coll writer opts]
+ (pr-sequential-writer writer pr-writer "(" " " ")" opts coll)))
+
+(es6-iterable Eduction)
+
+(defn eduction
+ "Returns a reducible/iterable application of the transducers
+ to the items in coll. Transducers are applied in order as if
+ combined with comp. Note that these applications will be
+ performed every time reduce/iterator is called."
+ {:arglists '([xform* coll])}
+ [& xforms]
+ (Eduction. (apply comp (butlast xforms)) (last xforms)))
+
+(defn run!
+ "Runs the supplied procedure (via reduce), for purposes of side
+ effects, on successive items in the collection. Returns nil"
+ [proc coll]
+ (reduce #(proc %2) nil coll)
+ nil)
+
+(defprotocol IEncodeJS
+ (-clj->js [x] "Recursively transforms clj values to JavaScript")
+ (-key->js [x] "Transforms map keys to valid JavaScript keys. Arbitrary keys are
+ encoded to their string representation via (pr-str x)"))
+
+(declare clj->js)
+
+(defn key->js
+ ([k] (key->js k clj->js))
+ ([k primitive-fn]
+ (cond
+ (satisfies? IEncodeJS k) (-clj->js k)
+ (or (string? k)
+ (number? k)
+ (keyword? k)
+ (symbol? k)) (primitive-fn k)
+ :default (pr-str k))))
+
+(defn clj->js
+ "Recursively transforms ClojureScript values to JavaScript.
+ sets/vectors/lists become Arrays, Keywords and Symbol become Strings,
+ Maps become Objects. Arbitrary keys are encoded to by `key->js`.
+ Options is a key-value pair, where the only valid key is
+ :keyword-fn, which should point to a single-argument function to be
+ called on keyword keys. Default to `name`."
+ [x & {:keys [keyword-fn]
+ :or {keyword-fn name}
+ :as options}]
+ (letfn [(keyfn [k] (key->js k thisfn))
+ (thisfn [x] (cond
+ (nil? x) nil
+ (satisfies? IEncodeJS x) (-clj->js x)
+ (keyword? x) (keyword-fn x)
+ (symbol? x) (str x)
+ (map? x) (let [m (js-obj)]
+ (doseq [[k v] x]
+ (gobject/set m (keyfn k) (thisfn v)))
+ m)
+ (coll? x) (let [arr (array)]
+ (doseq [x (map thisfn x)]
+ (.push arr x))
+ arr)
+ :else x))]
+ (thisfn x)))
+
+
+(defprotocol IEncodeClojure
+ (-js->clj [x options] "Transforms JavaScript values to Clojure"))
+
+(defn js->clj
+ "Recursively transforms JavaScript arrays into ClojureScript
+ vectors, and JavaScript objects into ClojureScript maps. With
+ option ':keywordize-keys true' will convert object fields from
+ strings to keywords."
+ ([x] (js->clj x :keywordize-keys false))
+ ([x & opts]
+ (let [{:keys [keywordize-keys]} opts
+ keyfn (if keywordize-keys keyword str)
+ f (fn thisfn [x]
+ (cond
+ (satisfies? IEncodeClojure x)
+ (-js->clj x (apply array-map opts))
+
+ (seq? x)
+ (doall (map thisfn x))
+
+ (map-entry? x)
+ (MapEntry. (thisfn (key x)) (thisfn (val x)) nil)
+
+ (coll? x)
+ (into (empty x) (map thisfn) x)
+
+ (array? x)
+ (persistent!
+ (reduce #(conj! %1 (thisfn %2))
+ (transient []) x))
+
+ (identical? (type x) js/Object)
+ (persistent!
+ (reduce (fn [r k] (assoc! r (keyfn k) (thisfn (gobject/get x k))))
+ (transient {}) (js-keys x)))
+ :else x))]
+ (f x))))
+
+(defn memoize
+ "Returns a memoized version of a referentially transparent function. The
+ memoized version of the function keeps a cache of the mapping from arguments
+ to results and, when calls with the same arguments are repeated often, has
+ higher performance at the expense of higher memory use."
+ [f]
+ (let [mem (atom {})]
+ (fn [& args]
+ (let [v (get @mem args lookup-sentinel)]
+ (if (identical? v lookup-sentinel)
+ (let [ret (apply f args)]
+ (swap! mem assoc args ret)
+ ret)
+ v)))))
+
+(defn trampoline
+ "trampoline can be used to convert algorithms requiring mutual
+ recursion without stack consumption. Calls f with supplied args, if
+ any. If f returns a fn, calls that fn with no arguments, and
+ continues to repeat, until the return value is not a fn, then
+ returns that non-fn value. Note that if you want to return a fn as a
+ final value, you must wrap it in some data structure and unpack it
+ after trampoline returns."
+ ([f]
+ (let [ret (f)]
+ (if (fn? ret)
+ (recur ret)
+ ret)))
+ ([f & args]
+ (trampoline #(apply f args))))
+
+(defn rand
+ "Returns a random floating point number between 0 (inclusive) and
+ n (default 1) (exclusive)."
+ ([] (rand 1))
+ ([n] (* (Math/random) n)))
+
+(defn rand-int
+ "Returns a random integer between 0 (inclusive) and n (exclusive)."
+ [n] (Math/floor (* (Math/random) n)))
+
+(defn rand-nth
+ "Return a random element of the (sequential) collection. Will have
+ the same performance characteristics as nth for the given
+ collection."
+ [coll]
+ (nth coll (rand-int (count coll))))
+
+(defn group-by
+ "Returns a map of the elements of coll keyed by the result of
+ f on each element. The value at each key will be a vector of the
+ corresponding elements, in the order they appeared in coll."
+ [f coll]
+ (persistent!
+ (reduce
+ (fn [ret x]
+ (let [k (f x)]
+ (assoc! ret k (conj (get ret k []) x))))
+ (transient {}) coll)))
+
+(defn make-hierarchy
+ "Creates a hierarchy object for use with derive, isa? etc."
+ [] {:parents {} :descendants {} :ancestors {}})
+
+(def
+ ^{:private true
+ :jsdoc ["@type {*}"]}
+ -global-hierarchy nil)
+
+(defn- get-global-hierarchy []
+ (when (nil? -global-hierarchy)
+ (set! -global-hierarchy (atom (make-hierarchy))))
+ -global-hierarchy)
+
+(defn- swap-global-hierarchy! [f & args]
+ (apply swap! (get-global-hierarchy) f args))
+
+(defn ^boolean isa?
+ "Returns true if (= child parent), or child is directly or indirectly derived from
+ parent, either via a JavaScript type inheritance relationship or a
+ relationship established via derive. h must be a hierarchy obtained
+ from make-hierarchy, if not supplied defaults to the global
+ hierarchy"
+ ([child parent] (isa? @(get-global-hierarchy) child parent))
+ ([h child parent]
+ (or (= child parent)
+ ;; (and (class? parent) (class? child)
+ ;; (. ^Class parent isAssignableFrom child))
+ (contains? ((:ancestors h) child) parent)
+ ;;(and (class? child) (some #(contains? ((:ancestors h) %) parent) (supers child)))
+ (and (vector? parent) (vector? child)
+ (== (count parent) (count child))
+ (loop [ret true i 0]
+ (if (or (not ret) (== i (count parent)))
+ ret
+ (recur (isa? h (child i) (parent i)) (inc i))))))))
+
+(defn parents
+ "Returns the immediate parents of tag, either via a JavaScript type
+ inheritance relationship or a relationship established via derive. h
+ must be a hierarchy obtained from make-hierarchy, if not supplied
+ defaults to the global hierarchy"
+ ([tag] (parents @(get-global-hierarchy) tag))
+ ([h tag] (not-empty (get (:parents h) tag))))
+
+(defn ancestors
+ "Returns the immediate and indirect parents of tag, either via a JavaScript type
+ inheritance relationship or a relationship established via derive. h
+ must be a hierarchy obtained from make-hierarchy, if not supplied
+ defaults to the global hierarchy"
+ ([tag] (ancestors @(get-global-hierarchy) tag))
+ ([h tag] (not-empty (get (:ancestors h) tag))))
+
+(defn descendants
+ "Returns the immediate and indirect children of tag, through a
+ relationship established via derive. h must be a hierarchy obtained
+ from make-hierarchy, if not supplied defaults to the global
+ hierarchy. Note: does not work on JavaScript type inheritance
+ relationships."
+ ([tag] (descendants @(get-global-hierarchy) tag))
+ ([h tag] (not-empty (get (:descendants h) tag))))
+
+(defn derive
+ "Establishes a parent/child relationship between parent and
+ tag. Parent must be a namespace-qualified symbol or keyword and
+ child can be either a namespace-qualified symbol or keyword or a
+ class. h must be a hierarchy obtained from make-hierarchy, if not
+ supplied defaults to, and modifies, the global hierarchy."
+ ([tag parent]
+ (assert (namespace parent))
+ ;; (assert (or (class? tag) (and (instance? cljs.core.Named tag) (namespace tag))))
+ (swap-global-hierarchy! derive tag parent) nil)
+ ([h tag parent]
+ (assert (not= tag parent))
+ ;; (assert (or (class? tag) (instance? clojure.lang.Named tag)))
+ ;; (assert (instance? clojure.lang.INamed tag))
+ ;; (assert (instance? clojure.lang.INamed parent))
+ (let [tp (:parents h)
+ td (:descendants h)
+ ta (:ancestors h)
+ tf (fn [m source sources target targets]
+ (reduce (fn [ret k]
+ (assoc ret k
+ (reduce conj (get targets k #{}) (cons target (targets target)))))
+ m (cons source (sources source))))]
+ (or
+ (when-not (contains? (tp tag) parent)
+ (when (contains? (ta tag) parent)
+ (throw (js/Error. (str tag "already has" parent "as ancestor"))))
+ (when (contains? (ta parent) tag)
+ (throw (js/Error. (str "Cyclic derivation:" parent "has" tag "as ancestor"))))
+ {:parents (assoc (:parents h) tag (conj (get tp tag #{}) parent))
+ :ancestors (tf (:ancestors h) tag td parent ta)
+ :descendants (tf (:descendants h) parent ta tag td)})
+ h))))
+
+(defn underive
+ "Removes a parent/child relationship between parent and
+ tag. h must be a hierarchy obtained from make-hierarchy, if not
+ supplied defaults to, and modifies, the global hierarchy."
+ ([tag parent]
+ (swap-global-hierarchy! underive tag parent)
+ nil)
+ ([h tag parent]
+ (let [parentMap (:parents h)
+ childsParents (if (parentMap tag)
+ (disj (parentMap tag) parent) #{})
+ newParents (if (not-empty childsParents)
+ (assoc parentMap tag childsParents)
+ (dissoc parentMap tag))
+ deriv-seq (flatten (map #(cons (first %) (interpose (first %) (second %)))
+ (seq newParents)))]
+ (if (contains? (parentMap tag) parent)
+ (reduce #(apply derive %1 %2) (make-hierarchy)
+ (partition 2 deriv-seq))
+ h))))
+
+(defn- reset-cache
+ [method-cache method-table cached-hierarchy hierarchy]
+ (swap! method-cache (fn [_] (deref method-table)))
+ (swap! cached-hierarchy (fn [_] (deref hierarchy))))
+
+(defn- prefers*
+ [x y prefer-table]
+ (let [xprefs (@prefer-table x)]
+ (or
+ (when (and xprefs (xprefs y))
+ true)
+ (loop [ps (parents y)]
+ (when (pos? (count ps))
+ (when (prefers* x (first ps) prefer-table)
+ true)
+ (recur (rest ps))))
+ (loop [ps (parents x)]
+ (when (pos? (count ps))
+ (when (prefers* (first ps) y prefer-table)
+ true)
+ (recur (rest ps))))
+ false)))
+
+(defn- dominates
+ [x y prefer-table hierarchy]
+ (or (prefers* x y prefer-table) (isa? hierarchy x y)))
+
+(defn- find-and-cache-best-method
+ [name dispatch-val hierarchy method-table prefer-table method-cache cached-hierarchy default-dispatch-val]
+ (let [best-entry (reduce (fn [be [k _ :as e]]
+ (if (isa? @hierarchy dispatch-val k)
+ (let [be2 (if (or (nil? be) (dominates k (first be) prefer-table @hierarchy))
+ e
+ be)]
+ (when-not (dominates (first be2) k prefer-table @hierarchy)
+ (throw (js/Error.
+ (str "Multiple methods in multimethod '" name
+ "' match dispatch value: " dispatch-val " -> " k
+ " and " (first be2) ", and neither is preferred"))))
+ be2)
+ be))
+ nil @method-table)
+ best-entry (if-let [entry (and (nil? best-entry) (@method-table default-dispatch-val))]
+ [default-dispatch-val entry]
+ best-entry)]
+ (when best-entry
+ (if (= @cached-hierarchy @hierarchy)
+ (do
+ (swap! method-cache assoc dispatch-val (second best-entry))
+ (second best-entry))
+ (do
+ (reset-cache method-cache method-table cached-hierarchy hierarchy)
+ (find-and-cache-best-method name dispatch-val hierarchy method-table prefer-table
+ method-cache cached-hierarchy default-dispatch-val))))))
+
+(defprotocol IMultiFn
+ (-reset [mf])
+ (-add-method [mf dispatch-val method])
+ (-remove-method [mf dispatch-val])
+ (-prefer-method [mf dispatch-val dispatch-val-y])
+ (-get-method [mf dispatch-val])
+ (-methods [mf])
+ (-prefers [mf])
+ (-default-dispatch-val [mf])
+ (-dispatch-fn [mf]))
+
+(defn- throw-no-method-error [name dispatch-val]
+ (throw (js/Error. (str "No method in multimethod '" name "' for dispatch value: " dispatch-val))))
+
+(deftype MultiFn [name dispatch-fn default-dispatch-val hierarchy
+ method-table prefer-table method-cache cached-hierarchy]
+ IFn
+ (-invoke [mf]
+ (let [dispatch-val (dispatch-fn)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn)))
+ (-invoke [mf a]
+ (let [dispatch-val (dispatch-fn a)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a)))
+ (-invoke [mf a b]
+ (let [dispatch-val (dispatch-fn a b)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b)))
+ (-invoke [mf a b c]
+ (let [dispatch-val (dispatch-fn a b c)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c)))
+ (-invoke [mf a b c d]
+ (let [dispatch-val (dispatch-fn a b c d)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d)))
+ (-invoke [mf a b c d e]
+ (let [dispatch-val (dispatch-fn a b c d e)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e)))
+ (-invoke [mf a b c d e f]
+ (let [dispatch-val (dispatch-fn a b c d e f)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f)))
+ (-invoke [mf a b c d e f g]
+ (let [dispatch-val (dispatch-fn a b c d e f g)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g)))
+ (-invoke [mf a b c d e f g h]
+ (let [dispatch-val (dispatch-fn a b c d e f g h)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h)))
+ (-invoke [mf a b c d e f g h i]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i)))
+ (-invoke [mf a b c d e f g h i j]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j)))
+ (-invoke [mf a b c d e f g h i j k]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k)))
+ (-invoke [mf a b c d e f g h i j k l]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l)))
+ (-invoke [mf a b c d e f g h i j k l m]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l m)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l m)))
+ (-invoke [mf a b c d e f g h i j k l m n]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l m n)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l m n)))
+ (-invoke [mf a b c d e f g h i j k l m n o]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l m n o)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l m n o)))
+ (-invoke [mf a b c d e f g h i j k l m n o p]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l m n o p)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l m n o p)))
+ (-invoke [mf a b c d e f g h i j k l m n o p q]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l m n o p q)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l m n o p q)))
+ (-invoke [mf a b c d e f g h i j k l m n o p q r]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l m n o p q r)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l m n o p q r)))
+ (-invoke [mf a b c d e f g h i j k l m n o p q r s]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l m n o p q r s)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l m n o p q r s)))
+ (-invoke [mf a b c d e f g h i j k l m n o p q r s t]
+ (let [dispatch-val (dispatch-fn a b c d e f g h i j k l m n o p q r s t)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (target-fn a b c d e f g h i j k l m n o p q r s t)))
+ (-invoke [mf a b c d e f g h i j k l m n o p q r s t rest]
+ (let [dispatch-val (apply dispatch-fn a b c d e f g h i j k l m n o p q r s t rest)
+ target-fn (-get-method mf dispatch-val)]
+ (when-not target-fn
+ (throw-no-method-error name dispatch-val))
+ (apply target-fn a b c d e f g h i j k l m n o p q r s t rest)))
+
+ IMultiFn
+ (-reset [mf]
+ (swap! method-table (fn [mf] {}))
+ (swap! method-cache (fn [mf] {}))
+ (swap! prefer-table (fn [mf] {}))
+ (swap! cached-hierarchy (fn [mf] nil))
+ mf)
+
+ (-add-method [mf dispatch-val method]
+ (swap! method-table assoc dispatch-val method)
+ (reset-cache method-cache method-table cached-hierarchy hierarchy)
+ mf)
+
+ (-remove-method [mf dispatch-val]
+ (swap! method-table dissoc dispatch-val)
+ (reset-cache method-cache method-table cached-hierarchy hierarchy)
+ mf)
+
+ (-get-method [mf dispatch-val]
+ (when-not (= @cached-hierarchy @hierarchy)
+ (reset-cache method-cache method-table cached-hierarchy hierarchy))
+ (if-let [target-fn (@method-cache dispatch-val)]
+ target-fn
+ (find-and-cache-best-method name dispatch-val hierarchy method-table
+ prefer-table method-cache cached-hierarchy default-dispatch-val)))
+
+ (-prefer-method [mf dispatch-val-x dispatch-val-y]
+ (when (prefers* dispatch-val-x dispatch-val-y prefer-table)
+ (throw (js/Error. (str "Preference conflict in multimethod '" name "': " dispatch-val-y
+ " is already preferred to " dispatch-val-x))))
+ (swap! prefer-table
+ (fn [old]
+ (assoc old dispatch-val-x
+ (conj (get old dispatch-val-x #{})
+ dispatch-val-y))))
+ (reset-cache method-cache method-table cached-hierarchy hierarchy))
+
+ (-methods [mf] @method-table)
+ (-prefers [mf] @prefer-table)
+ (-default-dispatch-val [mf] default-dispatch-val)
+ (-dispatch-fn [mf] dispatch-fn)
+
+ INamed
+ (-name [this] (-name name))
+ (-namespace [this] (-namespace name))
+
+ IHash
+ (-hash [this] (goog/getUid this)))
+
+(defn remove-all-methods
+ "Removes all of the methods of multimethod."
+ [multifn]
+ (-reset multifn))
+
+(defn remove-method
+ "Removes the method of multimethod associated with dispatch-value."
+ [multifn dispatch-val]
+ (-remove-method multifn dispatch-val))
+
+(defn prefer-method
+ "Causes the multimethod to prefer matches of dispatch-val-x over dispatch-val-y
+ when there is a conflict"
+ [multifn dispatch-val-x dispatch-val-y]
+ (-prefer-method multifn dispatch-val-x dispatch-val-y))
+
+(defn methods
+ "Given a multimethod, returns a map of dispatch values -> dispatch fns"
+ [multifn] (-methods multifn))
+
+(defn get-method
+ "Given a multimethod and a dispatch value, returns the dispatch fn
+ that would apply to that value, or nil if none apply and no default"
+ [multifn dispatch-val] (-get-method multifn dispatch-val))
+
+(defn prefers
+ "Given a multimethod, returns a map of preferred value -> set of other values"
+ [multifn] (-prefers multifn))
+
+(defn default-dispatch-val
+ "Given a multimethod, return it's default-dispatch-val."
+ [multifn] (-default-dispatch-val multifn))
+
+(defn dispatch-fn
+ "Given a multimethod, return it's dispatch-fn."
+ [multifn] (-dispatch-fn multifn))
+
+;; UUID
+(defprotocol IUUID "A marker protocol for UUIDs")
+
+(deftype UUID [uuid ^:mutable __hash]
+ IUUID
+
+ Object
+ (toString [_] uuid)
+ (equiv [this other]
+ (-equiv this other))
+
+ IEquiv
+ (-equiv [_ other]
+ (and (instance? UUID other) (identical? uuid (.-uuid other))))
+
+ IPrintWithWriter
+ (-pr-writer [_ writer _]
+ (-write writer (str "#uuid \"" uuid "\"")))
+
+ IHash
+ (-hash [this]
+ (when (nil? __hash)
+ (set! __hash (hash uuid)))
+ __hash)
+
+ IComparable
+ (-compare [_ other]
+ (garray/defaultCompare uuid (.-uuid other))))
+
+(defn uuid [s]
+ (assert (string? s))
+ (UUID. (.toLowerCase s) nil))
+
+(defn random-uuid []
+ (letfn [(hex [] (.toString (rand-int 16) 16))]
+ (let [rhex (.toString (bit-or 0x8 (bit-and 0x3 (rand-int 16))) 16)]
+ (uuid
+ (str (hex) (hex) (hex) (hex)
+ (hex) (hex) (hex) (hex) "-"
+ (hex) (hex) (hex) (hex) "-"
+ "4" (hex) (hex) (hex) "-"
+ rhex (hex) (hex) (hex) "-"
+ (hex) (hex) (hex) (hex)
+ (hex) (hex) (hex) (hex)
+ (hex) (hex) (hex) (hex))))))
+
+(defn ^boolean uuid?
+ [x] (implements? IUUID x))
+
+;;; ExceptionInfo
+
+(defn- pr-writer-ex-info [obj writer opts]
+ (-write writer "#error {:message ")
+ (pr-writer (.-message obj) writer opts)
+ (when (.-data obj)
+ (-write writer ", :data ")
+ (pr-writer (.-data obj) writer opts))
+ (when (.-cause obj)
+ (-write writer ", :cause ")
+ (pr-writer (.-cause obj) writer opts))
+ (-write writer "}"))
+
+(defn ^{:jsdoc ["@constructor"]}
+ ExceptionInfo [message data cause]
+ (let [e (js/Error. message)]
+ (this-as this
+ (set! (.-message this) message)
+ (set! (.-data this) data)
+ (set! (.-cause this) cause)
+ (do
+ (set! (.-name this) (.-name e))
+ ;; non-standard
+ (set! (.-description this) (.-description e))
+ (set! (.-number this) (.-number e))
+ (set! (.-fileName this) (.-fileName e))
+ (set! (.-lineNumber this) (.-lineNumber e))
+ (set! (.-columnNumber this) (.-columnNumber e))
+ (set! (.-stack this) (.-stack e)))
+ this)))
+
+(set! (.. ExceptionInfo -prototype -__proto__) js/Error.prototype)
+
+(extend-type ExceptionInfo
+ IPrintWithWriter
+ (-pr-writer [obj writer opts]
+ (pr-writer-ex-info obj writer opts)))
+
+(set! (.. ExceptionInfo -prototype -toString)
+ (fn []
+ (this-as this (pr-str* this))))
+
+(defn ex-info
+ "Create an instance of ExceptionInfo, an Error type that carries a
+ map of additional data."
+ ([msg data] (ex-info msg data nil))
+ ([msg data cause]
+ (ExceptionInfo. msg data cause)))
+
+(defn ex-data
+ "Returns exception data (a map) if ex is an ExceptionInfo.
+ Otherwise returns nil."
+ [ex]
+ (when (instance? ExceptionInfo ex)
+ (.-data ex)))
+
+(defn ex-message
+ "Returns the message attached to the given Error / ExceptionInfo object.
+ For non-Errors returns nil."
+ [ex]
+ (when (instance? js/Error ex)
+ (.-message ex)))
+
+(defn ex-cause
+ "Returns exception cause (an Error / ExceptionInfo) if ex is an
+ ExceptionInfo.
+ Otherwise returns nil."
+ [ex]
+ (when (instance? ExceptionInfo ex)
+ (.-cause ex)))
+
+(defn comparator
+ "Returns an JavaScript compatible comparator based upon pred."
+ [pred]
+ (fn [x y]
+ (cond (pred x y) -1 (pred y x) 1 :else 0)))
+
+(defn ^boolean special-symbol?
+ "Returns true if x names a special form"
+ [x]
+ (contains?
+ '#{if def fn* do let* loop* letfn* throw try catch finally
+ recur new set! ns deftype* defrecord* . js* & quote case* var ns*}
+ x))
+
+(defn test
+ "test [v] finds fn at key :test in var metadata and calls it,
+ presuming failure will throw exception"
+ [v]
+ (let [f (.-cljs$lang$test v)]
+ (if f
+ (do (f) :ok)
+ :no-test)))
+
+
+(deftype TaggedLiteral [tag form]
+ Object
+ (toString [coll]
+ (pr-str* coll))
+
+ IEquiv
+ (-equiv [this other]
+ (and (instance? TaggedLiteral other)
+ (= tag (.-tag other))
+ (= form (.-form other))))
+
+ IHash
+ (-hash [this]
+ (+ (* 31 (hash tag))
+ (hash form)))
+
+ ILookup
+ (-lookup [this v]
+ (-lookup this v nil))
+ (-lookup [this v not-found]
+ (case v
+ :tag tag
+ :form form
+ not-found))
+
+ IPrintWithWriter
+ (-pr-writer [o writer opts]
+ (-write writer (str "#" tag " "))
+ (pr-writer form writer opts)))
+
+(defn ^boolean tagged-literal?
+ "Return true if the value is the data representation of a tagged literal"
+ [value]
+ (instance? TaggedLiteral value))
+
+(defn tagged-literal
+ "Construct a data representation of a tagged literal from a
+ tag symbol and a form."
+ [tag form]
+ {:pre [(symbol? tag)]}
+ (TaggedLiteral. tag form))
+
+(def
+ ^{:private true
+ :jsdoc ["@type {*}"]}
+ js-reserved-arr
+ #js ["arguments" "abstract" "await" "boolean" "break" "byte" "case"
+ "catch" "char" "class" "const" "continue"
+ "debugger" "default" "delete" "do" "double"
+ "else" "enum" "export" "extends" "final"
+ "finally" "float" "for" "function" "goto" "if"
+ "implements" "import" "in" "instanceof" "int"
+ "interface" "let" "long" "native" "new"
+ "package" "private" "protected" "public"
+ "return" "short" "static" "super" "switch"
+ "synchronized" "this" "throw" "throws"
+ "transient" "try" "typeof" "var" "void"
+ "volatile" "while" "with" "yield" "methods"
+ "null" "constructor"])
+
+(def
+ ^{:jsdoc ["@type {null|Object}"]}
+ js-reserved nil)
+
+(defn- js-reserved? [x]
+ (when (nil? js-reserved)
+ (set! js-reserved
+ (reduce #(do (gobject/set %1 %2 true) %1)
+ #js {} js-reserved-arr)))
+ (.hasOwnProperty js-reserved x))
+
+(defn- demunge-pattern []
+ (when-not DEMUNGE_PATTERN
+ (set! DEMUNGE_PATTERN
+ (let [ks (sort (fn [a b] (- (. b -length) (. a -length)))
+ (js-keys DEMUNGE_MAP))]
+ (loop [ks ks ret ""]
+ (if (seq ks)
+ (recur
+ (next ks)
+ (str
+ (cond-> ret
+ (not (identical? ret "")) (str "|"))
+ (first ks)))
+ (str ret "|\\$"))))))
+ DEMUNGE_PATTERN)
+
+(defn- munge-str [name]
+ (let [sb (StringBuffer.)]
+ (loop [i 0]
+ (if (< i (. name -length))
+ (let [c (.charAt name i)
+ sub (gobject/get CHAR_MAP c)]
+ (if-not (nil? sub)
+ (.append sb sub)
+ (.append sb c))
+ (recur (inc i)))))
+ (.toString sb)))
+
+(defn munge [name]
+ (let [name' (munge-str (str name))
+ name' (cond
+ (identical? name' "..") "_DOT__DOT_"
+ (js-reserved? name') (str name' "$")
+ :else name')]
+ (if (symbol? name)
+ (symbol name')
+ name')))
+
+(defn- demunge-str [munged-name]
+ (let [r (js/RegExp. (demunge-pattern) "g")
+ munged-name (if (gstring/endsWith munged-name "$")
+ (.substring munged-name 0 (dec (. munged-name -length)))
+ munged-name)]
+ (loop [ret "" last-match-end 0]
+ (if-let [match (.exec r munged-name)]
+ (let [[x] match]
+ (recur
+ (str ret
+ (.substring munged-name last-match-end
+ (- (. r -lastIndex) (. x -length)))
+ (if (identical? x "$") "/" (gobject/get DEMUNGE_MAP x)))
+ (. r -lastIndex)))
+ (str ret
+ (.substring munged-name last-match-end (.-length munged-name)))))))
+
+(defn demunge [name]
+ ((if (symbol? name) symbol str)
+ (let [name' (str name)]
+ (if (identical? name' "_DOT__DOT_")
+ ".."
+ (demunge-str name')))))
+
+(defonce ^{:jsdoc ["@type {*}"] :private true}
+ tapset nil)
+
+(defn- maybe-init-tapset []
+ (when (nil? tapset)
+ (set! tapset (atom #{}))))
+
+(defn add-tap
+ "Adds f, a fn of one argument, to the tap set. This function will be called with
+ anything sent via tap>. Remember f in order to remove-tap"
+ [f]
+ (maybe-init-tapset)
+ (swap! tapset conj f)
+ nil)
+
+(defn remove-tap
+ "Remove f from the tap set."
+ [f]
+ (maybe-init-tapset)
+ (swap! tapset disj f)
+ nil)
+
+(defn ^boolean tap>
+ "Sends x to any taps. Returns the result of *exec-tap-fn*, a Boolean value."
+ [x]
+ (maybe-init-tapset)
+ (*exec-tap-fn*
+ (fn []
+ (doseq [tap @tapset]
+ (try
+ (tap x)
+ (catch js/Error ex))))))
+
+;; -----------------------------------------------------------------------------
+;; Bootstrap helpers - incompatible with advanced compilation
+
+(defn- ns-lookup
+ "Bootstrap only."
+ [ns-obj k]
+ (fn [] (gobject/get ns-obj k)))
+
+;; Bootstrap only
+(deftype Namespace [obj name]
+ Object
+ (findInternedVar [this sym]
+ (let [k (munge (str sym))]
+ (when ^boolean (gobject/containsKey obj k)
+ (let [var-sym (symbol (str name) (str sym))
+ var-meta {:ns this}]
+ (Var. (ns-lookup obj k) var-sym var-meta)))))
+ (getName [_] name)
+ (toString [_]
+ (str name))
+ IEquiv
+ (-equiv [_ other]
+ (if (instance? Namespace other)
+ (= name (.-name other))
+ false))
+ IHash
+ (-hash [_]
+ (hash name)))
+
+(def
+ ^{:doc "Bootstrap only." :jsdoc ["@type {*}"]}
+ NS_CACHE nil)
+
+(defn- find-ns-obj*
+ "Bootstrap only."
+ [ctxt xs]
+ (cond
+ (nil? ctxt) nil
+ (nil? xs) ctxt
+ :else (recur (gobject/get ctxt (first xs)) (next xs))))
+
+(defn find-ns-obj
+ "Bootstrap only."
+ [ns]
+ (let [munged-ns (munge (str ns))
+ segs (.split munged-ns ".")]
+ (case *target*
+ "nodejs" (if ^boolean js/COMPILED
+ ; Under simple optimizations on nodejs, namespaces will be in module
+ ; rather than global scope and must be accessed by a direct call to eval.
+ ; The first segment may refer to an undefined variable, so its evaluation
+ ; may throw ReferenceError.
+ (find-ns-obj*
+ (try
+ (let [ctxt (js/eval (first segs))]
+ (when (and ctxt (object? ctxt))
+ ctxt))
+ (catch js/ReferenceError e
+ nil))
+ (next segs))
+ (find-ns-obj* goog/global segs))
+ ("default" "webworker") (find-ns-obj* goog/global segs)
+ (throw (js/Error. (str "find-ns-obj not supported for target " *target*))))))
+
+(defn ns-interns*
+ "Returns a map of the intern mappings for the namespace.
+ Bootstrap only."
+ [sym]
+ (let [ns-obj (find-ns-obj sym)
+ ns (Namespace. ns-obj sym)]
+ (letfn [(step [ret k]
+ (let [var-sym (symbol (demunge k))]
+ (assoc ret
+ var-sym (Var. #(gobject/get ns-obj k)
+ (symbol (str sym) (str var-sym)) {:ns ns}))))]
+ (reduce step {} (js-keys ns-obj)))))
+
+(defn create-ns
+ "Create a new namespace named by the symbol. Bootstrap only."
+ ([sym]
+ (create-ns sym (find-ns-obj sym)))
+ ([sym ns-obj]
+ (Namespace. ns-obj sym)))
+
+(defn find-ns
+ "Returns the namespace named by the symbol or nil if it doesn't exist.
+ Bootstrap only."
+ [ns]
+ (when (nil? NS_CACHE)
+ (set! NS_CACHE (atom {})))
+ (let [the-ns (get @NS_CACHE ns)]
+ (if-not (nil? the-ns)
+ the-ns
+ (let [ns-obj (find-ns-obj ns)]
+ (when-not (nil? ns-obj)
+ (let [new-ns (create-ns ns ns-obj)]
+ (swap! NS_CACHE assoc ns new-ns)
+ new-ns))))))
+
+(defn find-macros-ns
+ "Returns the macros namespace named by the symbol or nil if it doesn't exist.
+ Bootstrap only."
+ [ns]
+ (when (nil? NS_CACHE)
+ (set! NS_CACHE (atom {})))
+ (let [ns-str (str ns)
+ ns (if (not ^boolean (gstring/contains ns-str "$macros"))
+ (symbol (str ns-str "$macros"))
+ ns)
+ the-ns (get @NS_CACHE ns)]
+ (if-not (nil? the-ns)
+ the-ns
+ (let [ns-obj (find-ns-obj ns)]
+ (when-not (nil? ns-obj)
+ (let [new-ns (create-ns ns ns-obj)]
+ (swap! NS_CACHE assoc ns new-ns)
+ new-ns))))))
+
+(defn ns-name
+ "Returns the name of the namespace, a Namespace object.
+ Bootstrap only."
+ [ns-obj]
+ (.-name ns-obj))
+
+(defn uri?
+ "Returns true x is a goog.Uri instance."
+ {:added "1.9"}
+ [x]
+ (instance? goog.Uri x))
+
+(defn- maybe-enable-print! []
+ (cond
+ (exists? js/console)
+ (enable-console-print!)
+
+ (or (identical? *target* "nashorn")
+ (identical? *target* "graaljs"))
+ (let [system (.type js/Java "java.lang.System")]
+ (set! *print-newline* false)
+ (set-print-fn!
+ (fn []
+ (let [xs (js-arguments)
+ s (.join (garray/clone xs) "")]
+ (.println (.-out system) s))))
+ (set-print-err-fn!
+ (fn []
+ (let [xs (js-arguments)
+ s (.join (garray/clone xs) "")]
+ (.println (.-error system) s)))))))
+
+(maybe-enable-print!)
+
+(defonce
+ ^{:doc "Runtime environments may provide a way to evaluate ClojureScript
+ forms. Whatever function *eval* is bound to will be passed any forms which
+ should be evaluated." :dynamic true}
+ *eval*
+ (fn [_]
+ (throw (js/Error. "cljs.core/*eval* not bound"))))
+
+(defn eval
+ "Evaluates the form data structure (not text!) and returns the result.
+ Delegates to cljs.core/*eval*. Intended for use in self-hosted ClojureScript,
+ which sets up an implementation of cljs.core/*eval* for that environment."
+ [form]
+ (*eval* form))