diff --git a/.github/workflows/clojure.yml b/.github/workflows/clojure.yml index 22bfe20..f85c990 100644 --- a/.github/workflows/clojure.yml +++ b/.github/workflows/clojure.yml @@ -2,18 +2,60 @@ name: Clojure CI on: push: - branches: [ master ] + branches: ["*"] pull_request: - branches: [ master ] + branches: ["master"] -jobs: - build: +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + test: + name: Test runs-on: ubuntu-latest + timeout-minutes: 30 steps: - - uses: actions/checkout@v2 - - name: Install dependencies - run: lein deps - - name: Run tests - run: lein test + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "25.0.2" + + - name: Install Clojure tooling + uses: DeLaGuardo/setup-clojure@13.5.2 + with: + cli: latest + lein: latest + bb: latest + + - name: Cache Clojure dependencies + uses: actions/cache@v4 + with: + path: | + ~/.m2/repository + ~/.gitlibs + ~/.lein + key: ${{ runner.os }}-clojure-${{ hashFiles('project.clj', 'deps.edn') }} + restore-keys: | + ${{ runner.os }}-clojure- + + - name: Show tool versions + run: | + java --version + clojure -Sdescribe + lein version + bb --version + + - name: Run Leiningen tests + run: lein test + + - name: Run tools.deps tests + run: clojure -M:test diff --git a/.gitignore b/.gitignore index 46d8b9a..9347919 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /target /classes /checkouts +/plans pom.xml pom.xml.asc *.jar @@ -8,3 +9,12 @@ pom.xml.asc /.lein-* /.nrepl-port *~ +# Benchmark results (local records) +/bench-results/ +/doc/api/ + +# Claude Code +/.claude/ +.DS_Store +/.cpcache +/AGENTS.md diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..1444b58 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,113 @@ +# Changelog + +## [0.2.0] - 2026-04-08 + +### New Collection Types + +- **Rope** (`rope`) — persistent chunked sequence for O(log n) structural editing + (concat, split, splice, insert, remove). Backed by a weight-balanced tree of + chunk vectors with a formal Chunk Size Invariant. Up to 1968x faster than + `PersistentVector` on repeated random edits at 500K elements; 3-10x faster + on concatenation; 1.3-1.7x faster on reduce at scale. Includes + structure-sharing subrange views via `rope-sub`, transient support for batch construction, + parallel `r/fold`, `java.util.List` interop, and lexicographic `Comparable`. +- **Range Map** (`range-map`) — non-overlapping `[lo, hi)` ranges with automatic carve-out on insert +- **Segment Tree** (`segment-tree`, `sum-tree`, `min-tree`, `max-tree`) — O(log n) range aggregation with any associative operation +- **Priority Queue** (`priority-queue`) — O(log n) push/peek/pop with min and max access +- **Ordered Multiset** (`ordered-multiset`) — sorted bag allowing duplicate elements +- **Fuzzy Set/Map** (`fuzzy-set`, `fuzzy-map`) — nearest-neighbor lookup by distance with configurable tiebreaking + +### New Operations + +- **Set algebra**: `union`, `intersection`, `difference`, `subset?`, `superset?`, `disjoint?` +- **Positional**: `rank`, `slice`, `median`, `percentile` +- **Navigation**: `nearest` (floor/ceiling with keyword tests `:<=`, `:>=`, `:<`, `:>`), `subrange`, `split-key`, `split-at` +- **Interval**: `overlapping`, `span` +- **Range map**: `ranges`, `span`, `gaps`, `assoc-coalescing`, `get-entry`, `range-remove` +- **Segment tree**: `query`, `aggregate`, `update-val`, `update-fn` +- **Priority queue**: `push`, `push-all`, `peek-min`, `peek-min-val`, `pop-min`, `peek-max`, `peek-max-val`, `pop-max` +- **Multiset**: `multiplicity`, `disj-one`, `disj-all`, `distinct-elements`, `element-frequencies` +- **Fuzzy**: `fuzzy-nearest`, `fuzzy-exact-contains?`, `fuzzy-exact-get` +- **Rope**: `rope-concat`, `rope-concat-all`, `rope-split`, `rope-sub`, `rope-insert`, `rope-remove`, `rope-splice`, `rope-chunks`, `rope-chunks-reverse`, `rope-chunk-count`, `rope-str` +- **Map**: `assoc-new`, `ordered-merge-with` +- **Comparator**: `general-compare` — opt-in total order over all values including non-Comparable types (Namespace, Var, etc.). ~20% slower lookups on Comparable types vs default. + +### Specialized Constructors + +- Rope: `rope` +- Type-specific: `long-ordered-set`, `long-ordered-map`, `double-ordered-set`, `double-ordered-map`, `string-ordered-set`, `string-ordered-map` +- Custom comparator: `ordered-set-by`, `ordered-map-by`, `ordered-set-with`, `ordered-map-with`, `ordered-multiset-by`, `fuzzy-set-by`, `fuzzy-map-by`, `segment-tree-by`, `segment-tree-with` +- Exported comparators: `long-compare`, `double-compare`, `string-compare`, `general-compare`, `compare-by` + +### Interface Implementations + +- `clojure.lang.Sorted` — native `subseq`/`rsubseq` on ordered-set and ordered-map +- `clojure.core.reducers/CollFold` — chunked parallel fold; ordered-set/map, rope, and compatible tree-backed types split into larger chunks before delegating to `r/fold` +- `clojure.lang.IEditableCollection` / `ITransientCollection` — transient support for `Rope` with mutable tail buffer for efficient batch construction +- `clojure.core.protocols/CollReduce` — implemented directly on all collection deftypes for correct fast-path reduction +- `clojure.lang.IHashEq` — correct `hash` for use in hash-based collections +- `java.io.Serializable` — Java serialization support +- `IReduceInit`/`IReduce` — direct tree traversal for fast `reduce` +- Direct `ISeq` implementations (`KeySeq`, `EntrySeq`) replace lazy-seq wrappers + +### EDN Tagged Literals + +Round-trip serialization via `data_readers.clj`: `#ordered/set`, `#ordered/map`, `#ordered/interval-set`, `#ordered/interval-map`, `#ordered/range-map`, `#ordered/priority-queue`, `#ordered/multiset`, `#ordered/rope`. Collections with custom comparators (including `general-compare`) print in opaque `#` form to avoid non-round-trippable tagged literals. + +### Performance + +- **Parallel set operations** via ForkJoinPool with operation-specific root thresholds (`65,536–131,072`), `65,536` recursive thresholds, and `64` sequential cutoff +- **Primitive node types** (`LongKeyNode`, `DoubleKeyNode`) — unboxed key storage +- **Primitive lookup fast path** — `long-ordered-set` bypasses `Comparator` dispatch +- **Interval overlap** — `intersects?` reduced from up to 12 comparisons to 2 (closed-interval identity: `a0 <= b1 AND a1 <= b0`) +- **Reduction refactor** — unary reducers (nodes, keys, entries) share a single enumerator-based kernel; kv reducers remain separate to avoid packing overhead. All support `reduced` short-circuiting. +- Fold benchmarking includes a non-trivial frequency-map workload comparing `ordered-set` fold against `hash-set` reduce, `sorted-set` fold/reduce, and `data.avl` fold/reduce +- Benchmark/test infrastructure shares common workload generators, reference helpers, and competitor builders via `test-utils` and `bench-utils` + +See [benchmarks](doc/benchmarks.md) for current numbers and analysis. + +### Build + +- Namespace root is now `ordered-collections.*` / `ordered_collections.*` rather than `com.dean.ordered-collections.*` +- Source/test tree lives under `src/ordered_collections` and `test/ordered_collections` +- `lein stats` — babashka-based project statistics report (clj-kondo analysis, git churn, codebase metrics) + +### Bug Fixes + +- `SortedSet.tailSet` now returns elements >= x (was exclusive) +- `SortedSet.subSet` now returns elements >= from, < to +- Interval tree construction uses sequential reduce (parallel fold lost dynamic binding for node allocator at >2048 elements) +- `segment-tree` range queries are generic over ordered keys rather than assuming integer-only query bounds +- `general-compare` collections print opaque (`#`) rather than emitting tagged literals that cannot round-trip through EDN +- Priority queue uses direct seq adapters instead of lazy `map` wrappers; stronger coverage for duplicate-priority ordering and boundary cases + +### Documentation + +- New [Ropes](doc/ropes.md) — rope tutorial, use cases, and design +- New [Collections API](doc/collections-api.md) — per-type constructor and operation reference +- [Migration guide](doc/vs-clojure-data-avl.md) corrected (`oc/rank` not `oc/rank-of`) +- Performance documentation consolidated in `doc/benchmarks.md`; the older `perf-analysis.md` and `when-to-use.md` are removed +- Cookbook examples refreshed for current semantics +- Generated `doc/api` output is no longer tracked in the repository + +### Breaking Changes + +- **Removed** `mutable-ordered-set`, `mutable-ordered-map`, `mutable-interval-set`, `mutable-interval-map` +- **Removed** `transient`/`persistent!` support (path-copying made it a no-op) +- **Renamed** public function: `rank-of` → `rank` (returns `nil` instead of `-1` for missing elements) +- Public namespace root and Maven/Lein artifact coordinate are now `ordered-collections` + +--- + +## [0.1.2] - 2024 + +- Documentation improvements +- Minor bug fixes + +## [0.1.1] - 2024 + +- Initial public release +- Weight-balanced persistent binary trees +- `ordered-set`, `ordered-map`, `interval-set`, `interval-map` +- Efficient set operations (intersection, union, difference) +- `nth` and `indexOf` in O(log n) time diff --git a/README.md b/README.md index b0051c0..6724769 100644 --- a/README.md +++ b/README.md @@ -1,282 +1,535 @@ -# com.dean.interval-tree +
+One Tree, Many Forests + -This library provides a collection of data structures implemented using a -modular, extensible, foldable, weight balanced persistent binary tree: -ordered-sets, ordered-maps, interval-sets, and interval-maps. +# ordered-collections -![tests](https://github.com/dco-dev/interval-tree/actions/workflows/clojure.yml/badge.svg) -[![Clojars Project](https://img.shields.io/clojars/v/com.dean/interval-tree.svg)](https://clojars.org/com.dean/interval-tree) +**Fast, modern, _ropes_ and ordered collections that do more than +sort.** -### Usage +Drop-in replacements for `sorted-set` and `sorted-map.` With +inherent parallelism, work-optimal set algebra, positional access, +parallel fold, and specialized collections for problems you didn't know +you could solve efficiently: -To install, add the following dependency to your project or build file: +
+ +- **Ropes** — concat, split, splice, insert: **10–5000x** faster than Clojure vector at scale +- **Sets and Maps** work exactly as you're used to, but do more, up to **50x** faster +- **Interval maps** for overlap queries ("what's scheduled at 3pm?") +- **Range maps** for non-overlapping regions ("which subnet owns this IP?") +- **Segment trees** for range aggregation ("total sales from day 10 to 50?") +- **Fuzzy collections** for nearest-neighbor lookup ("snap 9.3 to the closest valid size") +- **Priority queues**, **multisets**, and more + +All built from a modular, extensible, weight-balanced tree platform with shared +foundation for splitting, joining, and parallel operations. + +![tests](https://github.com/dco-dev/ordered-collections/actions/workflows/clojure.yml/badge.svg) +[![Clojars Project](https://img.shields.io/clojars/v/com.dean/ordered-collections.svg)](https://clojars.org/com.dean/ordered-collections) + +### Documentation + +- [Zorp's Sneaker Emporium](doc/zorp-example.md) — Narrative guide with extended examples +- [Cookbook](doc/cookbook.md) — Practical patterns: leaderboards, time-series, scheduling, queues, multisets, and more +- [Collections API](doc/collections-api.md) — Collection-by-collection constructor and operation reference +- [Ropes](doc/ropes.md) — Rope tutorial, use cases, and design +- [Benchmarks](doc/benchmarks.md) — Detailed performance measurements +- [Competitive Analysis](doc/competitive-analysis.md) — Comparison with other libraries +- [vs clojure.data.avl](doc/vs-clojure-data-avl.md) — For data.avl users considering a switch +- [Algorithms](doc/algorithms.md) — Tree structure, rotations, split/join, interval augmentation +- [Why Weight-Balanced Trees?](doc/why-weight-balanced-trees.md) — Comparison with red-black and AVL trees +- [One Tree, Many Forests](doc/concept/concept.md) — Conceptual architecture and design rationale + +--- + +## Quick Start + +Use `ordered-set` and `ordered-map` exactly like +`clojure.core/sorted-set` and `clojure.core/sorted-map`. All the functions you know work the same way. The difference is under the +hood — and in the new things you can do. + + +```clojure +(require '[ordered-collections.core :as oc]) + +;; Ropes — O(log n) split, splice, concat + +(def r (oc/rope [:a :b :c :d :e])) ;=> #ordered/rope [:a :b :c :d:e] + +(apply oc/rope-concat + (reverse (oc/rope-split r 2))) ;=> #ordered/rope [:c :d :e :a :b] + +(oc/rope-insert r 2 [:x :y]) ;=> #ordered/rope [:a :b :x :y :c :d :e] + +;; Sets + +(def s (oc/ordered-set [3 1 4 1 5 9 2 6])) ;=> #ordered/set [1 2 3 4 5 6 9] + +(s 4) ;=> 4 +(s 7) ;=> nil +(conj s 0) ;=> #{0 1 2 3 4 5 6 9} + +;; Maps + +(def m (oc/ordered-map {:b 2 :a 1 :c 3})) ;=> #ordered/map [[:a 1] [:b 2] [:c 3]] + +(m :b) ;=> 2 +(assoc m :d 4) ;=> {:a 1, :b 2, :c 3, :d 4} ``` -[com.dean/interval-tree "0.1.2"] +--- + +## Performance + +Across the measured workloads, `ordered-collections` is faster than +both `clojure.core/sorted-set` and `clojure.data.avl` at every +cardinality Set algebra is the standout, with 28-57x wins at 500K. +Even against unordered `clojure.core/set`the benchmarks still show +roughly 4-19x wins. + +### Rope vs PersistentVector + +| Workload | N=10K | N=100K | N=500K | +|---|---:|---:|---:| +| 200 random edits | **43x** | **498x** | **1968x** | +| Single splice | **6x** | **116x** | **584x** | +| Concat many pieces | **3.4x** | **5.4x** | **9.5x** | +| Chunk iteration | **58x** | **83x** | **117x** | +| Fold (sum) | **5.6x** | **1.5x** | **1.3x** | +| Reduce (sum) | 0.4x | **1.7x** | **1.3x** | +| Random nth (1000) | 0.7x | 0.5x | 0.4x | + +The rope wins on 6 of 7 workloads at scale and the advantage grows with +collection size. Concat improves with N because the rope collects chunks in +O(k) while the vector copies O(n) elements. Reduce beats vectors at N ≥ 100K +thanks to 256-element chunk locality. Random access is slower (O(log n) vs +O(1)) but bounded. See [Ropes](doc/ropes.md) for the full tutorial. + +### Set algebra + +#### vs clojure.core/sorted-set + +| Operation | N=10K | N=100K | N=500K | +|-----------|------:|-------:|-------:| +| Union | **15.4x** | **26.4x** | **56.6x** | +| Intersection | **9.0x** | **17.0x** | **36.2x** | +| Difference | **9.6x** | **22.1x** | **50.2x** | + +#### vs clojure.data.avl + +| Operation | N=10K | N=100K | N=500K | +|-----------|------:|-------:|-------:| +| Union | **10.9x** | **20.5x** | **42.1x** | +| Intersection | **7.2x** | **13.0x** | **28.1x** | +| Difference | **7.2x** | **12.7x** | **32.0x** | + +#### vs clojure.core/set + +| Operation | N=10K | N=100K | N=500K | +|-----------|------:|-------:|-------:| +| Union | **4.2x** | **7.2x** | **16.3x** | +| Intersection | **3.8x** | **6.1x** | **12.9x** | +| Difference | **4.4x** | **7.6x** | **18.6x** | + +### Set equality + +| | vs hash-set | vs sorted-set | vs data.avl | +|--|------------:|--------------:|------------:| +| N=10K | **2.8x** | **12.0x** | **14.1x** | +| N=100K | **2.3x** | **9.3x** | **9.5x** | + +### Other operations + +| Operation | vs sorted-set | vs data.avl | +|-----------|---------------|-------------| +| Construction | **3.0x / 2.8x / 3.1x** | **1.5x / 1.3x / 1.7x** | +| Lookup | 1.1x / 1.1x / 1.1x | 1.0x / 1.0x / 1.0x | +| Split | — | **6.8x / 7.2x / 7.8x** | +| Fold | **2.5x / 4.1x / 4.1x** | **5.8x / 5.9x / 8.8x** | + +*Benchmarked on a 2023 MacBook Pro (M2). See [Benchmarks](doc/benchmarks.md) for full results.* + +--- + +## How It Works + +The core is a **weight-balanced binary tree**. Each node knows its +subtree size, enabling O(log n) positional access and efficient parallel +decomposition. + +**Split and join** are the fundamental primitives — splitting at a key +produces two trees in O(log n); joining is also O(log n). Set +operations, subrange extraction, and parallel fold all reduce to +split/join. Set operations use Adams' divide-and-conquer algorithm +(1992) extended with the parallel forkl-join based approach from +Blelloch, Ferizovic & Sun (2016). + +Collection constructors provide the comparator and node-construction hooks, so +the same tree algorithms can back generic, primitive-specialized, and augmented +variants. + +**Augmented trees** extend the basic structure: interval trees store +max-endpoint per subtree for O(log n + k) overlap queries; segment trees +store aggregates for O(log n) range queries. + +See [Algorithms](doc/algorithms.md) for implementation details and [Why +Weight-Balanced Trees?](doc/why-weight-balanced-trees.md) for comparison +with red-black and AVL trees. + +--- + +## Collections + +The fundamental collection types currently implemented are: +`ordered-set`, `ordered-map`, `rope`, `interval-set`, `interval-map`, +`range-map`, `segment-tree`, `priority-queue`, `ordered-multiset`, `fuzzy-set`, +and `fuzzy-map`. + +| Constructor | Description | +|-------------|-------------| +| **Ordered Set** | | +| `(oc/ordered-set coll)` | Sorted set (drop-in for `sorted-set`) | +| `(oc/ordered-set-by pred coll)` | Sorted set with custom comparator | +| `(oc/long-ordered-set coll)` | Sorted set optimized for Long keys | +| `(oc/string-ordered-set coll)` | Sorted set optimized for String keys | +| **Ordered Map** | | +| `(oc/ordered-map coll)` | Sorted map (drop-in for `sorted-map`) | +| `(oc/ordered-map-by pred coll)` | Sorted map with custom comparator | +| `(oc/long-ordered-map coll)` | Sorted map optimized for Long keys | +| `(oc/string-ordered-map coll)` | Sorted map optimized for String keys | +| **Interval Collections** | | +| `(oc/interval-set coll)` | Set supporting interval overlap queries | +| `(oc/interval-map coll)` | Map supporting interval overlap queries | +| **Range Map** | | +| `(oc/range-map)` | Non-overlapping ranges (Guava TreeRangeMap) | +| **Segment Tree** | | +| `(oc/segment-tree f identity coll)` | O(log n) range aggregate queries | +| `(oc/segment-tree-by pred f identity coll)` | Segment tree with custom ordering predicate | +| `(oc/segment-tree-with cmp f identity coll)` | Segment tree with custom Comparator | +| **Priority Queue** | | +| `(oc/priority-queue pairs)` | Priority queue from `[priority value]` pairs | +| **Ordered Multiset** | | +| `(oc/ordered-multiset coll)` | Sorted multiset (allows duplicates) | +| **Rope** | | +| `(oc/rope coll)` | Persistent sequence for structural editing | +| `(oc/rope-concat a b)` | Concatenate two ropes — O(log n) | +| `(oc/rope-splice r start end items)` | Replace a range — O(log n) | +| **Fuzzy Collections** | | +| `(oc/fuzzy-set coll)` | Returns closest element to query | +| `(oc/fuzzy-map coll)` | Returns value for closest key to query | + +--- + +## Ropes + +A rope is a persistent sequence optimized for **structural editing** — +concatenation, splitting, splicing, and insertion in the middle of large +sequences. Where `PersistentVector` is O(n) for mid-sequence edits, +the rope is O(log n). + +```clojure +(def r (oc/rope (range 100000))) + +;; Splice into the middle — O(log n), not O(n) +(def edited (oc/rope-splice r 50000 50010 [:new :data])) + +;; Split — O(log n) +(let [[left right] (oc/rope-split r 50000)] + [(count left) (count right)]) ;=> [50000 50000] + +;; Concatenate — O(log n) +(oc/rope-concat (oc/rope [1 2 3]) (oc/rope [4 5 6])) +;=> #ordered/rope [1 2 3 4 5 6] ``` -#### Public API +--- -The public api resides in the top-level `com.dean.interval-tree.core` namespace: +## Capabilities -```clj -(require '[com.dean.interval-tree.core :as dean]) +Operations that `sorted-set` and `sorted-map` don't provide — at any collection size. +For the full collection-by-collection surface area, see [Collections API](doc/collections-api.md). + +### Positional Access & Rank + +```clojure +(def s (oc/ordered-set [50 30 20 40 10])) + +(nth s 2) ;=> 30 O(log n) +(oc/rank s 30) ;=> 2 O(log n) +(oc/median s) ;=> 30 O(log n) +(oc/percentile s 90) ;=> 50 O(log n) +(oc/slice s 1 4) ;=> (20 30 40) ``` -The basic operation of this library is as a drop-in replacement for -`clojure.core/sorted-set` and `clojure.core/sorted-map`. +### Nearest / Floor / Ceiling + +```clojure +(def s (oc/ordered-set [200 200 400 300 500])) + +(oc/nearest s :<= 350) ;=> 300 (floor) +(oc/nearest s :>= 350) ;=> 400 (ceiling) +(oc/nearest s :< 300) ;=> 200 (predecessor) +(oc/nearest s :> 300) ;=> 400 (successor) +``` -#### Constructors +### Split & Subrange -* `(dean/ordered-set coll)` -* `(dean/ordered-set-by pred coll)` -* `(dean/ordered-map coll)` -* `(dean/ordered-map-by pred coll)` -* `(dean/interval-set coll)` -* `(dean/interval-map coll)` +```clojure +(def s (oc/ordered-set [5 4 3 1 2])) -### Topics +(oc/split-key 3 s) ;=> [#{1 2} 3 #{4 5}] O(log n) +(oc/split-at 2 s) ;=> [#{1 2} #{3 4 5}] O(log n) -#### What is an Interval Map? +;; subrange returns a collection, not a seq +(oc/subrange s :>= 2 :<= 4) ;=> #{2 3 4} +``` -Imagine you'd like to associate values with members of a set of -intervals over some continuous domain such as time or real numbers. -An example of this is shown below. An interval map answers the question, -which intervals overlap at some point on the domain. At 3.14159, in this -case, would be `x4` and `x7`. The interval map is sparse itself, of -course, and would only need to contain the 8 constituent intervals. +### Interval Queries ``` - x8: +-----+ - x7: +-----------------------------------+ - x6: + - x5: +-----------+ - x4: +-----------------------------+ - x3: +-----+ - x2: +-----------------+ - x1: +-----------+ - - 0=====1=====2=====3=====4=====5=====6=====7=====8=====9 + meeting: +-------+ + lunch: +-------+ + review: +-------+ + 9==10==11==12==13==14==15==16==17 ``` -This corresponds to the following example code: +```clojure +(def schedule + (oc/interval-map + {[9 12] "meeting" [14 17] "review" [11 15] "lunch"})) -```clj +(schedule 11) ;=> ("meeting" "lunch") point query +(schedule [10 14]) ;=> ("meeting" "lunch" "review") range query +(oc/span schedule) ;=> [9 17] +``` -(def x (dean/interval-map {[1 3] :x1 - [4 7] :x2 - [8 9] :x3 - [0 5] :x4 - [6 8] :x5 - [9 9] :x6 - [3 9] :x7 - [4 5] :x8})) +### Range Maps -(x 3.141592654) ;; => [:x4 :x7] -(x [5 5]) ;; => [:x4 :x7 :x8 :x2] +Non-overlapping ranges — each point maps to exactly one value. Inserting +a new range automatically carves out whatever it overlaps. -(get x 9) ;; => [:x7 :x3 :x6] -(get x 9.00001) ;; => nil -(get x [1 4]) ;; => [:x4 :x1 :x7 :x8 :x2] +```clojure +(def tiers + (-> (oc/range-map) + (assoc [0 100] :bronze) + (assoc [100 500] :silver) + (assoc [500 5000] :gold))) +(tiers 250) ;=> :silver +(oc/get-entry tiers 250) ;=> [[100 500] :silver] ``` -#### Efficient Set Operations +Insert a flash-sale range — bronze and silver are automatically split: -This library implements a diverse collection of efficent set operations -on foldably parallel ordered sets: +```clojure +(oc/ranges (assoc tiers [50 200] :flash)) +;; => ([[0 50] :bronze] ← auto-trimmed +;; [[50 200] :flash] ← inserted +;; [[200 500] :silver] ← auto-trimmed +;; [[500 5000] :gold]) ``` - (def foo (shuffle (range 500000))) - (def bar (shuffle (range 1000000))) - (def s0 (shuffle (range 0 1000000 2))) - (def s1 (shuffle (range 0 1000000 3))) +### Segment Trees -;; -;;; dean/ordered-set -;; +```clojure +(def sales (oc/sum-tree {1 100, 2 200, 3 150, 4 300, 5 250})) - (time (def x (ordered-set foo))) ;; 500K: "Elapsed time: 564.248517 msecs" - (time (def y (ordered-set bar))) ;; 1M: "Elapsed time: 1187.734211 msecs" +(oc/query sales 2 4) ;=> 650 O(log n) +(oc/aggregate sales) ;=> 1000 O(1) - (time (def s (dean/intersection - (ordered-set s0) - (ordered-set s1)))) ;; 833K: "Elapsed time: 1242.961445 msecs" +;; Update and re-query - (time (r/fold + + y)) ;; 1M: "Elapsed time: 54.363545 msecs" +(def sales' (assoc sales 3 500)) +(oc/query sales' 2 4) ;=> 1000 +;; Also: min-tree, max-tree, or any associative operation -;; -;;; clojure.core/sorted-set -;; +(def peaks (oc/segment-tree max 0 {1 100, 2 200, 3 150})) +(oc/query peaks 1 3) ;=> 200 +``` - (time (def v (into (sorted-set) foo))) ;; 500K: "Elapsed time: 839.188189 msecs" - (time (def w (into (sorted-set) bar))) ;; 1M: "Elapsed time: 1974.798286 msecs" +### Fuzzy Lookup - (time (def s (clojure.set/intersection - (into (sorted-set) s0) - (into (sorted-set) s1)))) ;; 833K: "Elapsed time: 1589.786106 msecs" +```clojure +(def sizes (oc/fuzzy-set [6 7 8 9 10 11 12 13])) +(sizes 9.3) ;=> 9 +(oc/fuzzy-nearest sizes 9.3) ;=> [9 0.30] - (time (r/fold + + w)) ;; 1M: "Elapsed time: 167.916539 msecs" +(def tiers (oc/fuzzy-map {0 :bronze 500 :silver 1000 :gold})) +(tiers 480) ;=> :silver ``` -### Testing +### Priority Queue & Multiset -Testing is accomplished with the standard `lein test` -``` -$ time lein test +```clojure +;; Priority queue (min-heap) -lein test com.dean.interval-tree.interval-map-test +(def pq (oc/priority-queue [[3 :medium] [1 :urgent] [5 :low]])) +(peek pq) ;=> [1 :urgent] +(peek (pop pq)) ;=> [3 :medium] -lein test com.dean.interval-tree.interval-set-test +;; Multiset (sorted bag, allows duplicates) -lein test com.dean.interval-tree.interval-test +(def ms (oc/ordered-multiset [3 1 4 1 5 9 2 6 5 3 5])) +(oc/multiplicity ms 5) ;=> 3 +``` -lein test com.dean.interval-tree.ordered-map-test +### Parallel Fold -lein test com.dean.interval-tree.ordered-set-test +All collection types implement `CollFold` for efficient `r/fold`: -lein test com.dean.interval-tree.tree-test +```clojure +(require '[clojure.core.reducers :as r]) -Ran 30 tests containing 98214 assertions. -0 failures, 0 errors. +(def combinef (fn ([] {}) ([m1 m2] (merge-with + m1 m2)))) +(def reducef (fn [m x] (update m (mod x 100) (fnil inc 0)))) -real 5m34.487s -user 10m21.397s -sys 0m5.047s +(r/fold combinef reducef (oc/ordered-set (range 1000000))) + +;; 1M-element frequency-map workload from the benchmark suite: +;; ~6.9x faster than hash-set reduce, ~4.5x faster than sorted-set fold, +;; ~3.4x faster than data.avl fold ``` +--- -### Modularity +## Testing -This data structure library is designed around the following concepts of -modularity and extensibility. +``` +$ lein test -#### Clojure/Java Interfaces +Ran 454 tests containing 466,000+ assertions. +0 failures, 0 errors. +``` -The top level collections are built on the standard Clojure/Java -interfaces, so, for example, working with an `ordered-set` is -identical to working with Clojure's `sorted-set`, using all of the same -standard collection functions, for the 99% case: meta, nth, seq, rseq, -assoc(-in), get(-in), invoke, compare, to-array, empty, .indexOf, -.lastIndexof, size, iterator-seq, first, last, =, count, empty, -contains, conj. disj, cons, fold, and many old friends will just -work, using an efficient implementation that takes full advantage of the -capabilities of our underlying tree index. +The test suite includes generative tests via `test.check` and equivalence +tests against `sorted-set`, `sorted-map`, and `clojure.data.avl`. -#### PExtensibleset +### Tooling -An exception to the above is due to the fact that `clojure.set` does not -provide interfaces for extensible sets. So, we provide our own -intersection, union, difference, subset, and superset. These operators -work most efficiently on com.dean.interval-tree collections and provide -support for backward interoperability with clojure (or possibly other) -set datatypes. +``` +$ lein codox # Generate API docs in doc/api +$ lein stats # Print project statistics +``` -#### Root Container +### Benchmarks -The individual collection types (ordered-set, ordered-map, interval-set, -interval-map} are defined by their individual Class (clojure -`deftype`) of top level container that holds the root of an -indexed tree. This container describes the behavior of the underlying -tree data structure along several architectural dimensions. +``` +$ lein bench # Criterium, N=100K (~5 min) +$ lein bench --full # Criterium, N=10K,100K,500K (~40 min) +$ lein bench --readme --full # README tables only (~10 min) +$ lein bench --sizes 50000 # Custom sizes + +$ lein bench-simple # Quick iteration bench (100 to 100K) +$ lein bench-simple --full # Full suite (100 to 1M) +$ lein bench-range-map # Range-map vs Guava TreeRangeMap +$ lein bench-parallel # Parallel threshold crossover analysis +$ lein bench-report # Analyze latest benchmark results +``` + +[Criterium](https://github.com/hugoduncan/criterium) results are written to +`bench-results/.edn`. -##### INodeCollection +--- -The fundamental collection of nodes provides an interface to node -allocation machinery and to the root contained node. A variant -based on persistent (on-disk) storage, for example, has been built -with customizations at this layer. +## Inspiration -##### IBalancedCollection +The implementation of this weight-balanced binary tree data +structure library was inspired by the following: -For functional balanced trees, provides an interface to the `stitch` -function that returns a new, properly balanced tree containing one newly -allocated node adjoined. The provided algorithm is -[weight balanced](https://en.wikipedia.org/wiki/Weight-balanced_tree) -however others may be used. We've experimented with red-black trees, -in particular, as variants at this layer. +- Adams (1992) + 'Implementing Sets Efficiently in a Functional Language' + Technical Report CSTR 92-10, University of Southampton. + -##### IOrderedCollection +- Hirai and Yamamoto (2011) + 'Balancing Weight-Balanced Trees' + Journal of Functional Programming / 21 (3): + Pages 287-307 + -Ordered collections define a comparator and predicates to determine the -underlying algorithmic compatibility of other collections. Interval -Collections are a special type of OrderedCollection. +- Oleg Kiselyov + 'Towards the best collection API, A design of the overall optimal + collection traversal interface' + -#### Tree +- Nievergelt and Reingold (1972) + 'Binary Search Trees of Bounded Balance' + STOC '72 Proceedings + 4th Annual ACM symposium on Theory of Computing + Pages 137-142 + -The heart of the library is our [persistent tree](https://github.com/dco-dev/interval-tree/blob/master/src/com/dean/interval_tree/tree/tree.clj). +- Driscoll, Sarnak, Sleator, and Tarjan (1989) + 'Making Data Structures Persistent' + Journal of Computer and System Sciences Volume 38 Issue 1, February 1989 + 18th Annual ACM Symposium on Theory of Computing + Pages 86-124 + -The code is well documented and explains in more detail the efficiencies -of the internal collection operators. +- MIT Scheme weight balanced tree as reimplemented by Yoichi Hirai + and Kazuhiko Yamamoto using the revised non-variant algorithm recommended + integer balance parameters from (Hirai/Yamamoto 2011). + -This species of binary tree supports representations of sets, maps, -and vectors. In addition to indexed key and range query, it -supports the `nth` operation to return nth node from the beginning of -the ordered tree, and `node-rank` to return the rank (sequential -position) of a given key within the ordered tree, both in logarithmic -time. +- Wikipedia + 'Interval Tree' + -The axes of exstensibility of the tree implemntation -(`*compare*`,`*n-join*`, `*t-join*`) correspond to the interfaces -described above. +- Wikipedia + 'Segment Tree' + -### Inspiration +- Google Guava + 'RangeMap' + - This implementation of a weight-balanced binary interval-tree data - structure was inspired by the following: +- Wikipedia + 'Weight Balanced Tree' + - - Adams (1992) - 'Implementing Sets Efficiently in a Functional Language' - Technical Report CSTR 92-10, University of Southampton. - +- Andrew Baine (2007) + 'Purely Functional Data Structures in Common Lisp' + Google Summer of Code 2007, mentored by Rahul Jain + + - - Hirai and Yamamoto (2011) - 'Balancing Weight-Balanced Trees' - Journal of Functional Programming / 21 (3): - Pages 287-307 - +- Scott L. Burson + 'Functional Set-Theoretic Collections for Common Lisp' + - - Oleg Kiselyov - 'Towards the best collection API, A design of the overall optimal - collection traversal interface' - +- Adams (1993) + 'Efficient sets—a balancing act' + Journal of Functional Programming 3(4): 553-562 + - - Nievergelt and Reingold (1972) - 'Binary Search Trees of Bounded Balance' - STOC '72 Proceedings - 4th Annual ACM symposium on Theory of Computing - Pages 137-142 +- Blelloch, Ferizovic, and Sun (2016) + 'Just Join for Parallel Ordered Sets' + ACM SPAA 2016 + - - Driscoll, Sarnak, Sleator, and Tarjan (1989) - 'Making Data Structures Persistent' - Journal of Computer and System Sciences Volume 38 Issue 1, February 1989 - 18th Annual ACM Symposium on Theory of Computing - Pages 86-124 - - - MIT Scheme weight balanced tree as reimplemented by Yoichi Hirai - and Kazuhiko Yamamoto using the revised non-variant algorithm recommended - integer balance parameters from (Hirai/Yamomoto 2011). +- Boehm, Atkinson, and Plass (1995) + 'Ropes: an Alternative to Strings' + Software: Practice and Experience 25(12) + - - Wikipedia - 'Interval Tree' - +- Haskell containers library (Data.Set, Data.Map) + - - Wikipedia - 'Weight Balanced Tree' - +- SLIB Weight-Balanced Trees (Aubrey Jaffer) + - - Andrew Baine, Rahul Jaine (2007) - 'Purely Functional Data Structures in Common Lisp' - Google Summer of Code 2007 - - +- PAM: Parallel Augmented Maps + - - Scott L. Burson - 'Functional Set-Theoretic Collections for Common Lisp' - +--- -### License +## License 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 LICENSE.txt 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. + +--- + +*For extended examples featuring Zorp, Kevin the sentient flip-flop, and Big Toe Tony's 47 feet, see [Zorp's Sneaker Emporium](doc/zorp-example.md).* diff --git a/bb.edn b/bb.edn new file mode 100644 index 0000000..a51c02d --- /dev/null +++ b/bb.edn @@ -0,0 +1,10 @@ +{:paths ["etc/lib"] + :deps {com.github.danlentz/clj-figlet {:mvn/version "0.1.4"} + com.github.danlentz/clj-format {:mvn/version "0.1.1"}} + :tasks + {stats {:doc "Project stats report" + :task (load-file "etc/stats.bb")} + bench-report {:doc "Benchmark report from bench-results EDN" + :task (load-file "etc/bench_report.bb")} + paper {:doc "Build the concept paper PDF" + :task (load-file "etc/paper.bb")}}} diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000..f75baa0 --- /dev/null +++ b/deps.edn @@ -0,0 +1,63 @@ +{:paths ["src" "resources"] + + :deps {org.clojure/clojure {:mvn/version "1.12.4"}} + + :aliases + {:dev + {:extra-paths ["test"] + :extra-deps {org.clojure/data.avl {:mvn/version "0.2.0"} + org.clojure/test.check {:mvn/version "1.1.1"} + org.clojure/math.combinatorics {:mvn/version "0.3.2"} + criterium/criterium {:mvn/version "0.4.6"} + com.clojure-goes-fast/clj-memory-meter {:mvn/version "0.3.0"} + com.google.guava/guava {:mvn/version "33.0.0-jre"}} + :jvm-opts ["-Djdk.attach.allowAttachSelf" + "-XX:+EnableDynamicAgentLoading"]} + + :test + {:extra-paths ["test"] + :extra-deps {org.clojure/data.avl {:mvn/version "0.2.0"} + org.clojure/test.check {:mvn/version "1.1.1"} + org.clojure/math.combinatorics {:mvn/version "0.3.2"} + com.clojure-goes-fast/clj-memory-meter {:mvn/version "0.3.0"} + com.google.guava/guava {:mvn/version "33.0.0-jre"} + io.github.cognitect-labs/test-runner + {:git/tag "v0.5.1" :git/sha "dfb30dd"}} + :jvm-opts ["-Djdk.attach.allowAttachSelf" + "-XX:+EnableDynamicAgentLoading"] + :main-opts ["-m" "cognitect.test-runner"]} + + :bench + {:extra-paths ["test"] + :extra-deps {org.clojure/data.avl {:mvn/version "0.2.0"} + org.clojure/test.check {:mvn/version "1.1.1"} + criterium/criterium {:mvn/version "0.4.6"} + com.clojure-goes-fast/clj-memory-meter {:mvn/version "0.3.0"} + com.google.guava/guava {:mvn/version "33.0.0-jre"}} + :jvm-opts ["-Djdk.attach.allowAttachSelf" + "-XX:+EnableDynamicAgentLoading" + "-Xmx8g"] + :main-opts ["-m" "ordered-collections.bench-runner"]} + + :bench-simple + {:extra-paths ["test"] + :extra-deps {org.clojure/data.avl {:mvn/version "0.2.0"} + criterium/criterium {:mvn/version "0.4.6"} + com.google.guava/guava {:mvn/version "33.0.0-jre"}} + :jvm-opts ["-Djdk.attach.allowAttachSelf" + "-XX:+EnableDynamicAgentLoading" + "-Xmx8g"] + :main-opts ["-m" "ordered-collections.simple-bench"]} + + :bench-range-map + {:extra-paths ["test"] + :extra-deps {com.google.guava/guava {:mvn/version "33.0.0-jre"}} + :jvm-opts ["-Xmx8g"] + :main-opts ["-m" "ordered-collections.range-map-bench"]} + + :bench-parallel + {:extra-paths ["test"] + :extra-deps {org.clojure/data.avl {:mvn/version "0.2.0"} + criterium/criterium {:mvn/version "0.4.6"}} + :jvm-opts ["-Xmx8g"] + :main-opts ["-m" "ordered-collections.parallel-threshold-bench"]}}} diff --git a/doc/algorithms.md b/doc/algorithms.md new file mode 100644 index 0000000..1b148a5 --- /dev/null +++ b/doc/algorithms.md @@ -0,0 +1,796 @@ +# Algorithms + +## Weight-Balanced Trees + +Each node stores a key, value, left and right children, and **subtree weight** (= 1 + size(left) + size(right)). Specialized node types exist for performance: `LongKeyNode` (unboxed `long` key), `DoubleKeyNode` (unboxed `double` key), and `IntervalNode` (additional max-endpoint field for interval augmentation). + +These are not separate tree implementations. The library uses one shared tree +algebra, parameterized by two hooks: `order/*compare*` for ordering semantics +and `*t-join*` for node reconstruction. Collection constructors bind those at +the boundary, so the same split/join/search code serves generic nodes, +primitive-specialized nodes, and augmented variants. + +``` + ┌─────────────────┐ + │ key: 50 │ + │ val: "fifty" │ + │ weight: 7 │ + └────────┬────────┘ + │ + ┌──────────┴──────────┐ + ▼ ▼ + ┌─────────┐ ┌─────────┐ + │ key: 25 │ │ key: 75 │ + │ wt: 3 │ │ wt: 3 │ + └────┬────┘ └────┬────┘ + │ │ + ┌──┴──┐ ┌──┴──┐ + ▼ ▼ ▼ ▼ + [10] [30] [60] [90] + wt:1 wt:1 wt:1 wt:1 +``` + +Leaves are a sentinel value (weight 0). The weight field serves double duty: it *is* the balance invariant and it enables O(log n) positional access. + +## Balance Invariant + +Hirai-Yamamoto parameters (δ=3, γ=2): + +``` +weight(left) + 1 ≤ δ × (weight(right) + 1) +weight(right) + 1 ≤ δ × (weight(left) + 1) +``` + +No subtree can be more than 3× its sibling's weight. When violated, `stitch-wb` applies a single or double rotation: + +- **Single rotation** when the heavy child's *outer* subtree dominates (checked via γ) +- **Double rotation** when the heavy child's *inner* subtree dominates + +``` +Single right: Double right: + [C] [A] [C] [B] + / \ / \ / \ / \ + [A] z x [C] [A] z [A] [C] + / \ / \ / \ / \ / \ + x [B] [B] z w [B] w x y z + / \ + x y +``` + +Hirai & Yamamoto (2011) proved using Coq that (δ=3, γ=2) is the unique integer parameter pair guaranteeing O(log n) height and correct rebalancing for all insert/delete sequences. Height bound: ≤ log₃/₂ n ≈ 1.71 log₂ n. + +![Rotations and Stitch](assets/rotation-stitch.svg) + +## Split and Join + +Everything reduces to these two primitives. + +**Split** divides a tree at a key into (left, found, right): + +``` +split(tree, 50): + + [40] + / \ + [20] [60] + / \ / \ + [10][30][50][80] + + ↓ + + LEFT (<50) FOUND RIGHT (>50) + [40] 50 [60] + / \ \ + [20] [30] [80] + / +[10] +``` + +**Join** (`node-concat3`) combines two trees with a pivot key, rebalancing as needed. When the trees are similarly sized, the pivot becomes the root directly. When one side is much heavier, join walks down the heavy side until it finds a subtree of comparable weight, inserts the pivot there, and rebalances upward. + +``` +join(left, 50, right): + + LEFT RIGHT [50] + [25] [75] / \ + / \ / \ → [25] [75] +[10] [30] [60] [90] / \ / \ + [10][30][60][90] +``` + +**Join without pivot** (`node-concat2`) extracts the greatest element from the left tree and uses it as the pivot for `node-concat3`. Used by intersection and difference when the split key is absent. + +Both split and join are O(log n). The key property of weight-balanced trees: weight composes trivially — `weight(join(L, k, R)) = weight(L) + 1 + weight(R)` — so no auxiliary recomputation (height, color) is needed after joining. This gives WBTs lower constant factors for split/join than AVL or red-black trees. + +Because `join` is also the representation hook, the same recursive algorithms +rebuild the correct node type automatically. Different collection variants +inherit the same operation structure while choosing different storage or +augmentation behavior at node construction time. + +## Enumerators: The Fundamental Traversal Interface + +Below split/join, the tree's basic traversal primitive is the **enumerator**. +An enumerator is a compact explicit traversal state: a chain of frames +representing the current node plus the remaining path to the next node in +sorted order. + +The forward enumerator descends the left spine: + +``` +node-enumerator(root) + = [current-node | continuation] +``` + +Advancing the enumerator does two things: +- if the current node has a right subtree, descend that subtree's left spine +- otherwise, resume from the saved continuation + +The reverse enumerator is symmetric: descend the right spine, then resume +outward through saved continuations. + +Why this matters: +- it gives in-order traversal without recursion or lazy-seq allocation in the hot path +- it is the common substrate for `node-reduce`, `node-reduce-right`, sequence construction, and tree-to-tree linear merges +- it keeps traversal mechanics separate from collection presentation (`seq`, `rseq`, key seqs, entry seqs) + +This is close in spirit to Oleg Kiselyov's "Towards the best collection API: +A design of the overall optimal collection traversal interface", which argues +for enumerator-style traversal as the fundamental collection-walking primitive. +The tree code applies that idea at the node level and then builds the public +seq/reduce interfaces on top of it. + +![Enumerator: Left-Spine Decomposition](assets/enumerator-spine.svg) + +Conceptually, the layering is: + +``` +enumerator ; explicit tree-walk state + ↓ +node-reduce ; eager traversal API +node-seq / direct seq types + ↓ +collection seq/reduce interfaces +``` + +This is why the tree code treats enumerators as fundamental rather than as a +small helper for `seq`. They are the shared low-level traversal interface from +which both eager reduction and Clojure-facing sequence behavior are derived. + +## The Reduction Stack + +The enumerator feeds into a layered reduction architecture. Unary reducers +(nodes, keys, entries) share a single factory (`make-unary-reducer`) that +combines an enumerator direction with a projection function. The kv reducer +is hand-written separately because its 3-arity `(f acc k v)` shape doesn't +fit the unary projection model — forcing it through a projection would require +packing k and v into a MapEntry just to unpack them. Direct seq types +(`KeySeq`, `EntrySeq`) walk the enumerator without lazy-seq allocation. +Parallel fold splits the tree into chunks (via positional split) and reduces +each chunk independently. + +![The Reduction Stack](assets/reduction-stack.svg) + +## The Join-Based Paradigm + +All tree operations reduce to split and join (Adams 1992, Blelloch et al. 2016): + +| Operation | Implementation | +|-----------|----------------| +| insert(k, v) | split at k, join with new node | +| delete(k) | split at k, join left and right | +| union(A, B) | split A at root(B), recurse on halves, join | +| intersection(A, B) | split A at root(B), recurse, join if found, concat if not | +| difference(A, B) | split A at root(B), recurse, concat halves | + +Balance logic lives only in join. All operations inherit O(log n) balancing automatically. + +## Set Operations + +Union, intersection, and difference use Adams' divide-and-conquer: + +``` +union(T₁, T₂): + if T₁ empty: return T₂ + if T₂ empty: return T₁ + (k, v) = root(T₂) + (L₁, _, R₁) = split(T₁, k) + return join(union(L₁, left(T₂)), k, v, union(R₁, right(T₂))) + +intersection(T₁, T₂): + if T₁ empty or T₂ empty: return ∅ + (k, v) = root(T₂) + (L₁, present, R₁) = split(T₁, k) + L = intersection(L₁, left(T₂)) + R = intersection(R₁, right(T₂)) + if present: return join(L, k, v, R) + else: return concat(L, R) + +difference(T₁, T₂): + if T₁ empty: return ∅ + if T₂ empty: return T₁ + (k, _) = root(T₂) + (L₁, _, R₁) = split(T₁, k) + return concat(difference(L₁, left(T₂)), difference(R₁, right(T₂))) +``` + +**Work complexity:** O(m log(n/m + 1)) where m ≤ n. This is information-theoretically optimal — it matches the comparison-based lower bound. When m ≪ n (e.g., merging a small set into a large one), this approaches O(m log n). When m ≈ n, it's O(n). The naive element-by-element insertion approach is always O(m log n), which is worse when m is large. + +### Parallelism + +The two recursive calls in each operation are independent. The implementation forks the left recursion as a `ForkJoinTask` and computes the right recursion inline, then joins: + +``` +fork-join: + left-task = fork(union(L₁, left(T₂))) ← submitted to ForkJoinPool + right-result = union(R₁, right(T₂)) ← computed inline + left-result = left-task.join() ← wait for fork + return join(left-result, k, v, right-result) +``` + +The current implementation uses operation-specific root thresholds: +- union: `131,072` +- intersection: `65,536` +- difference: `131,072` +- ordered-map merge: `65,536` + +Below those root thresholds, the operations stay sequential. Once in the +parallel path, recursive splits re-fork at `65,536`, subject to the branch-shape +guard described below. Tiny subtrees still use the direct sequential cutoff of +`64`. + +Span is O(log² n), giving near-linear speedup on many cores (Blelloch et al. 2016). + +## Fork-Join Parallelism + +Six operations use Java's `ForkJoinPool` for automatic parallelism: union, intersection, difference, merge-with, and two forms of parallel fold. Set operations use the three-layer fork-join pattern directly; fold delegates to `clojure.core.reducers/fold`. + +### The pattern + +Every parallel operation has three layers: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Entry point │ +│ Is the caller already in a ForkJoinPool worker thread? │ +│ yes → call par-fn directly │ +│ no → submit par-fn to the common pool via .invoke │ +├─────────────────────────────────────────────────────────────┤ +│ par-fn (parallel recursion) │ +│ Is the subtree large enough to justify forking? │ +│ yes → fork left subtree, compute right inline, join │ +│ no → call seq-fn │ +├─────────────────────────────────────────────────────────────┤ +│ seq-fn (sequential recursion) │ +│ Same algorithm, no fork overhead │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Why the pool entry point is needed + +`ForkJoinTask.fork()` can only be called from within a `ForkJoinPool` worker thread. When user code calls `union` from a regular thread (e.g. the main thread or a core.async thread), the operation must first be submitted to the pool. Once inside the pool, recursive calls are already on worker threads and can fork directly: + +``` +(if (ForkJoinTask/inForkJoinPool) + (par-fn root) ;; already inside pool + (.invoke fork-join-pool ;; enter pool + (ForkJoinTask/adapt (fn [] (par-fn root))))) +``` + +### Task representation + +The hot recursive path no longer goes through `Callable` plus +`ForkJoinTask/adapt`, and it no longer relies on repeated dynamic-var rebinding. +Instead, the sequential and parallel kernels use explicit-argument helpers +(`cmp`, `create`) and fork a small internal `RecursiveTask` wrapper. + +That matters because the set-algebra recursion is fine-grained: if task +creation, comparator rebinding, or closure allocation are too expensive, the +practical crossover climbs far above where the algorithm should pay off. + +### Threshold tuning + +Parallelism uses four guards to keep fork overhead from dominating: + +| Threshold | Value | Purpose | +|-----------|-------|---------| +| `union` root threshold | 131,072 | Enter parallel union only above this combined subtree size | +| `intersection` root threshold | 65,536 | Enter parallel intersection only above this combined subtree size | +| `difference` root threshold | 131,072 | Enter parallel difference only above this combined subtree size | +| `merge` root threshold | 65,536 | Enter parallel ordered-map merge only above this combined subtree size | +| recursive threshold | 65,536 | Once already in the parallel path, re-fork only above this combined subtree size | +| `+parallel-min-branch+` | 65,536 | Only fork when both recursive branches are substantive enough | +| `+sequential-cutoff+` | 64 | Subtree size below which set operations use direct linear merge | +| `+min-fold-chunk-size+` | 4,096 | Minimum chunk size for parallel fold (floor on user-supplied value) | + +The root thresholds are operation-specific because one conservative value left +too many practical wins on the table. Union and difference reconstruct more +output than intersection; merge behaves differently again; comparator cost and +tree shape also matter. The fold chunk floor prevents excessive O(log n) tree +splits when `r/fold`'s default chunk size (256) would create too many chunks. + +`parallel_threshold_bench.clj` is useful for local tuning, but it does not +produce one stable crossover point across machines. In the April 2, 2026 +reruns, the production-path benchmark favored per-operation entry thresholds +plus a lower recursive threshold and a branch-shape guard. That matches the +actual workload differences between union, intersection, difference, and +ordered-map merge more closely than a single universal threshold. + +### Operations using this pattern + +**Set operations** (union, intersection, difference, merge-with): The tree's divide-and-conquer structure maps directly to fork-join. Split T₁ at T₂'s root, fork the left halves, compute the right halves inline, join results. Work O(m log(n/m + 1)), span O(log² n). + +**Parallel fold** (`node-fold`): Split the tree into roughly equal subtrees using `node-split` at evenly-spaced positions, then fold them in parallel via `r/fold`. Splitting is done eagerly in the caller's thread (where dynamic bindings are available); each chunk's sequential reduce uses `node-reduce` which needs no bindings. Work O(n), span O(n/p + k log n) where k is the number of chunks. + +## Positional Access + +Weight at each node enables O(log n) index operations without any additional data structure. + +### nth (index → element) + +``` +nth(tree, i): + left-size = weight(left) + if i < left-size: recurse into left + if i == left-size: return this node + else: recurse into right with i' = i - left-size - 1 +``` + +### rank (element → index) + +Accumulate left subtree sizes while descending: + +``` +rank(tree, key): + acc = 0 + if key < node.key: recurse left, keep acc + if key = node.key: return acc + weight(left) + if key > node.key: acc += weight(left) + 1, recurse right +``` + +### Derived operations + +- **slice(start, end)**: split-at start, split-at (end - start) on the right half +- **median**: nth at ⌊n/2⌋ +- **percentile(p)**: nth at ⌊n × p / 100⌋ + +All O(log n). Available on `ordered-set`, `ordered-map`, `fuzzy-set`, `fuzzy-map`. + +## Nearest (Floor / Ceiling) + +`ordered-set` and `ordered-map` implement directional nearest-neighbor via tree descent: + +| Test | Meaning | +|------|---------| +| `:<=` | floor — greatest element ≤ k | +| `:<` | predecessor — greatest element < k | +| `:>=` | ceiling — least element ≥ k | +| `:>` | successor — least element > k | + +Standard BST descent with candidate tracking. O(log n). + +## Parallel Fold + +Collections implement `clojure.core.reducers/CollFold` via `node-fold`. The tree is split into roughly equal chunks using `node-split`; those chunks are then folded in parallel by `clojure.core.reducers/fold`. + +Minimum chunk size: **`+min-fold-chunk-size+` = 4,096**. User-supplied chunk sizes below that floor are rounded up to avoid excessive tree splitting overhead. + +Span is approximately O(n/p + k log n), where `p` is processor count and `k` is the number of chunks. + +## Interval Tree Augmentation + +`IntervalNode` adds a field `z`: the maximum right endpoint in the subtree. This is maintained during rotations — each node's `z` is the max of its own interval's endpoint and its children's `z` values. + +``` + ┌─────────────────────┐ + │ interval: [3,7] │ + │ max-end: 15 │ ← max of all endpoints in subtree + └─────────┬───────────┘ + │ + ┌──────────┴──────────┐ + ▼ ▼ +┌─────────┐ ┌─────────┐ +│ [1,5] │ │ [8,15] │ +│ max: 5 │ │ max: 15 │ +└────┬────┘ └────┬────┘ + │ │ + ┌──┴──┐ ┌──┴──┐ + ▼ ▼ ▼ ▼ +[0,2] [4,6] [6,10] [12,15] +max:2 max:6 max:10 max:15 +``` + +### Query algorithm + +The implementation supports both point queries and interval-vs-interval overlap queries. Given a query interval `i`: + +``` +search(node, i): + if leaf: return + + # Search right if query's endpoint ≥ node's start point + if b(i) >= a(node.key): + search(right, i) + + # Check current node for intersection + if intersects?(i, node.key): + collect(node) + + # Search left only if query's start ≤ max endpoint in left subtree + if a(i) <= left.z: + search(left, i) +``` + +`intersects?` checks for any common point between two intervals (overlap, containment in either direction). The `z` field enables pruning: if `left.z < a(query)`, no interval in the left subtree can overlap the query. + +Complexity: O(log n + k) where k = number of matching intervals. + +Point queries are a special case: a point `p` is treated as the interval `[p, p]`. + +## Range Map + +`range-map` enforces non-overlapping ranges. Each point maps to exactly one value. Ranges are half-open: `[lo, hi)`. + +### Insert (assoc) + +Inserting `[25, 75) → :new` into a tree containing `[0, 100) → :a`: + +``` +Step 1: Find all ranges overlapping [25, 75) + → [[0, 100) → :a] + +Step 2: Remove overlapping ranges from tree + +Step 3: Re-insert trimmed portions outside [25, 75) + → [0, 25) → :a, [75, 100) → :a + +Step 4: Insert new range + → [0, 25) → :a, [25, 75) → :new, [75, 100) → :a +``` + +### Coalescing insert (assoc-coalescing) + +When adjacent ranges have the same value, merge them: + +``` +Before: [0, 50) → :a [50, 100) → :a (two ranges) +Insert [100, 150) → :a with coalescing: +After: [0, 50) → :a [50, 150) → :a (adjacent merged) +``` + +Complexity: O(k log n) where k = number of overlapping/adjacent ranges. + +## Segment Tree + +Each `AggregateNode` stores a pre-computed aggregate (`agg`) of its entire subtree under a user-specified associative operation. Created via a custom node constructor that computes `agg = op(left.agg, op(value, right.agg))` at every node. + +``` + ┌─────────────┐ + │ key: 3 │ + │ val: 40 │ + │ agg: 150 ◄──────── sum of entire tree + └──────┬──────┘ + ┌───────────┴───────────┐ + ┌──────┴──────┐ ┌──────┴──────┐ + │ key: 1 │ │ key: 4 │ + │ val: 20 │ │ val: 50 │ + │ agg: 30 │ │ agg: 80 │ + └──────┬──────┘ └──────┬──────┘ + │ │ + ┌──────┴──────┐ ┌──────┴──────┐ + │ key: 0 │ │ key: 5 │ + │ val: 10 │ │ val: 30 │ + │ agg: 10 │ │ agg: 30 │ + └─────────────┘ └─────────────┘ +``` + +### Range query + +Two implementations: `query-range` (basic) and `query-range-fast` (uses subtree bounds to short-circuit). + +``` +query-range-fast(node, lo, hi): + if leaf: return identity + + # Find subtree's actual key range + l-lo = min key in left subtree (or node.key if left is leaf) + r-hi = max key in right subtree (or node.key if right is leaf) + + # Entire subtree outside range + if r-hi < lo or l-lo > hi: return identity + + # Entire subtree inside range → use pre-computed aggregate! + if lo ≤ l-lo and r-hi ≤ hi: return node.agg + + # Partial overlap → recurse + L = query-range-fast(left, lo, hi) + V = node.val if lo ≤ node.key ≤ hi, else identity + R = query-range-fast(right, lo, hi) + return op(L, op(V, R)) +``` + +The key optimization: when a subtree is entirely within the query range, return its `agg` directly instead of recursing. This gives O(log n) for both queries and updates. + +## Fuzzy Lookup + +Fuzzy collections find the closest element by distance. The algorithm uses split: + +``` +find-nearest(tree, query): + (left, exact, right) = split(tree, query) + + if exact: return exact + + floor = greatest(left) ← O(log n) + ceiling = least(right) ← O(log n) + + return argmin(|query - floor|, |query - ceiling|) +``` + +When equidistant, a configurable tiebreaker (`:< ` or `:>`) determines preference. The `distance-fn` is also configurable (defaults to numeric absolute difference). + +**Invariant:** The nearest element by distance is always a sort-order neighbor (floor or ceiling), so split gives us the only two candidates. O(log n). + +## Handling Duplicates + +`ordered-multiset` and `priority-queue` allow duplicate keys by appending an internal sequence counter. + +**Multiset** stores `[value, seqnum]` pairs. Comparison: first by value, then by seqnum. This gives stable insertion order for equal values and FIFO behavior on removal. + +**Priority queue** stores `[priority, seqnum, value]` triples. Sorted by priority first, then seqnum. `peek` returns the minimum-priority element; among equal priorities, the earliest inserted. + +## Complexity Summary + +| Operation | Time | Notes | +|-----------|------|-------| +| Lookup | O(log n) | All collections | +| Insert / Delete | O(log n) | Persistent (path copying) | +| nth / rank | O(log n) | Via subtree weights | +| median / percentile | O(log n) | Via nth | +| nearest (floor/ceiling) | O(log n) | Ordered sets and maps | +| Split (by key or index) | O(log n) | | +| Join | O(log n) | Universal primitive | +| Union / Intersection / Difference | O(m log(n/m+1)) | Work-optimal, fork-join parallel | +| Parallel fold | O(n/p + log²n) | p = processors | +| Interval query | O(log n + k) | k = result count | +| Range-map assoc | O(k log n) | k = overlapping ranges | +| Segment-tree query | O(log n) | Pre-computed aggregates | +| Fuzzy lookup | O(log n) | Split + floor/ceiling | +| Rope nth | O(log n) | Descent by element counts | +| Rope concat | O(log n) | Structural join | +| Rope split | O(log n) | Split-join with concat3 | +| Rope splice / insert / remove | O(log n) | Split + concat | +| Rope reduce | O(n) | Chunk-aware traversal | +| Rope parallel fold | O(n/p + log²n) | Fork-join over split halves | + +## Ropes: Implicit-Index Chunk Trees + +A rope is a persistent sequence built on the same weight-balanced tree +infrastructure, but with a fundamentally different indexing model. Where +ordered sets and maps use a comparator to position elements by key, a rope +uses **positional indexing** — the element's position in the sequence is +determined entirely by subtree element counts. + +### Node Representation + +Each rope node reuses `SimpleNode` with repurposed fields: + +``` + ┌────────────────────────┐ + │ k: chunk [a b c ...] │ ← vector of elements (the "chunk") + │ v: 1042 │ ← total element count of subtree + │ x: 9 │ ← node count (for WBT balance) + │ l: ● r: ● │ + └────────────────────────┘ +``` + +Two distinct size metrics coexist: + +- `tree/node-size` (field `x`) — **node count**, used by WBT rotations +- `rope-size` (field `v`) — **element count**, used for indexed access + +This separation is essential. The tree stays balanced by node count (so all the +existing rotation machinery works unchanged), while indexed operations descend +by element count. + +### Chunk Size Invariant (CSI) + +Chunks are bounded by a formal invariant analogous to B-tree minimum fill: + +``` +target = 256 min = 256 + +Every chunk has size in [min, target] except: + - If the rope has ≤ 1 chunk, it may be any size in [1, target] + - Otherwise, only the rightmost chunk (the "runt") may be [1, target] +``` + +CSI is enforced locally at each mutation site: + +| Operation | Enforcement | +|---|---| +| `rope-concat` | Position-aware boundary check: l's rightmost becomes internal (must be ≥ min); r's leftmost only needs fixing if r has ≥ 2 chunks. `merge-boundary` pulls one neighbor when combined boundary < min. | +| `rope-split` | `ensure-split-parts` repairs the right fringe of the left half and the left fringe of the right half. | +| `rope-sub` | `ensure-left-fringe` + `ensure-right-fringe` after recursive extraction. | +| `rope-conj-right` | Fills rightmost chunk up to target; overflows to new node. | +| `coll->root` | `partition-all target` always produces valid chunks. | + +`rechunk-balanced` is the core partitioning helper: it packs greedily at target +size, but when the last full chunk would leave a remainder below min, it splits +the final two pieces evenly so both halves are ≥ min. + +### Indexed Access + +`rope-nth` descends by subtree element counts: + +``` +rope-nth(node, i): + ls = element-count(left) + cs = chunk-size(node) + if i < ls: recurse into left + if i < ls + cs: return chunk[i - ls] + else: recurse into right with i' = i - ls - cs +``` + +Cost: O(log n) — one comparison per tree level, then a constant-time vector +lookup within the chunk. + +### Split + +`rope-split-at` follows the standard split-join pattern from Blelloch et al., +adapted for positional indexing. The key optimization: it uses `rope-join` +(a concat3 — balanced join with a known pivot chunk) during unwind rather than +`raw-rope-concat` (concat2, which must extract a pivot). + +``` +rope-split(node, i): + ls = element-count(left) + cs = chunk-size(node) + + if i < ls: + (ll, lr) = rope-split(left, i) + return (ll, rope-join(chunk, lr, right)) ← concat3, O(|height diff|) + + if i within chunk: + split the chunk vector via subvec + return (concat(left, left-piece), concat(right-piece, right)) + + if i > ls + cs: + (rl, rr) = rope-split(right, i - ls - cs) + return (rope-join(chunk, left, rl), rr) +``` + +`rope-join` is O(|height(l) - height(r)|) per call, and the height differences +telescope across levels, giving **O(log n) total** for the full split. The +earlier implementation used concat2 at each level, which was O(log²n). + +### Concatenation + +`rope-concat` is the rope's fundamental structural operation. For the common +case (both boundary chunks ≥ min), it delegates directly to `raw-rope-concat` +— the standard WBT join, O(log n). + +When boundary chunks need repair (the left tree's rightmost was a runt that +now becomes internal), `merge-boundary` removes the two boundary chunks, +combines them, rechunks, and rebuilds. If the combined content is still below +min, it pulls one additional neighbor chunk — at most one level of cascading. + +### Subrope (Range Extraction) + +`rope-sub` does direct recursive range extraction rather than split-twice: + +``` +slice(node, start, end): + if range fully covers node: return node ← full subtree sharing + left-part = slice(left, start, min(end, ls)) + mid-part = subvec chunk at boundaries + right-part = slice(right, max(0, start-rs), end-rs) + return concat(concat(left-part, mid-part), right-part) +``` + +This reuses whole subtrees when the requested window fully contains them, +taking chunk subvecs only at the two cut boundaries. Fringe normalization +is applied once at the end. + +### Transient Tail Buffer + +`TransientRope` uses a mutable `ArrayList` as a tail buffer. `conj!` appends +to the tail in O(1); when the tail reaches target chunk size (256 elements), +it is flushed into the persistent tree via `rope-concat`. This amortizes tree +operations over 256 element appends, cutting build time roughly in half +compared to persistent `conj`. + +``` +conj!(transient, x): + tail.add(x) + if tail.size >= target: + chunk = vec(tail) + tail.clear() + root = rope-concat(root, coll->root(chunk)) + +persistent!(transient): + flush remaining tail + return Rope(root) +``` + +### Why Not a Comparator? + +The rope deliberately avoids the library's `order/*compare*` / `tree/*t-join*` +dynamic variable hooks. Position is the ordering — there is no meaningful key +to compare. This means the rope cannot reuse `node-split`, `node-concat3`, +or the comparator-driven add/remove paths. Instead, it has its own +position-aware equivalents (`rope-split-at`, `rope-join`, `rope-nth`, etc.) +that thread through the tree by element count rather than key comparison. + +The shared infrastructure it *does* reuse: `node-stitch` (rotation logic), +`node-weight` (balance metric), `SimpleNode` (storage), and the enumerator / +reducer machinery for traversal. + +### Performance vs PersistentVector + +``` +Rope WINS (advantage grows with N): + +┌────────────────────┬───────┬────────┬────────┬──────────────────────┐ +│ Workload │ N=10K │ N=100K │ N=500K │ Asymptotic │ +├────────────────────┼───────┼────────┼────────┼──────────────────────┤ +│ 200 random edits │ 43x │ 498x │ 1968x │ O(k·log n) vs O(k·n) │ +│ Single splice │ 6x │ 116x │ 584x │ O(log n) vs O(n) │ +│ Concat many pieces │ 3.4x │ 5.4x │ 9.5x │ O(k) vs O(n) │ +│ Chunk iteration │ 58x │ 83x │ 117x │ natural structure │ +│ Reduce (sum) │ 0.4x │ 1.7x │ 1.3x │ 256-elem chunk wins │ +└────────────────────┴───────┴────────┴────────┴──────────────────────┘ + +Rope loses (bounded, inherent O(log n) vs O(1)): + +┌────────────────────┬───────┬────────┬────────┐ +│ Workload │ N=10K │ N=100K │ N=500K │ +├────────────────────┼───────┼────────┼────────┤ +│ Split │ 19x │ 7x │ 21x │ +│ Slice │ 65x │ 51x │ 24x │ +│ Random nth (1000) │ 1.6x │ 1.9x │ 2.5x │ +└────────────────────┴───────┴────────┴────────┘ +``` + +Reduce beats vectors at N ≥ 100K because the rope's 256-element chunk size +gives better cache locality per reduction step than PersistentVector's 32-wide +trie nodes. The direct recursive tree walk (no enumerator frames) and native +vector `.reduce` delegation keep per-element overhead minimal. + +Every remaining loss is structural — there are no non-inherent performance gaps: + +``` +┌─────────────────────┬──────────┬───────────────────────────────────────────────────┐ +│ Loss │ Ratio │ Why inherent │ +├─────────────────────┼──────────┼───────────────────────────────────────────────────┤ +│ Split/slice │ ~15-60x │ O(log n) tree walk vs O(1) subvec wrapper │ +│ Random nth │ 1.3-2.6x │ O(log n) tree descent vs O(1) trie lookup │ +│ Reduce at 10K │ 0.6x │ Fixed tree-walk overhead for 39 chunks │ +│ Build via transient │ 2.2-2.6x │ Periodic O(log n) tree flush vs O(1) array append │ +│ Build via conj │ 12-18x │ O(log n) per append vs O(1) amortized │ +└─────────────────────┴──────────┴───────────────────────────────────────────────────┘ +``` + +Split/slice/nth are the price of tree-backed indexing — `subvec` wraps the +existing vector in constant time, while the rope must walk its tree. The +absolute times are microseconds (5-12µs for split, ~250µs for 1000 random +nths). Construction is best done via `(oc/rope coll)` which is a single O(n) +chunking pass, not element-by-element `conj`. + +The editing wins are unbounded: each mid-sequence edit on a vector copies O(n) +elements, while the rope does O(log n) tree work. At 500K elements, 200 random +edits take 3ms on the rope vs 5.4 seconds on the vector. + +### References + +- Boehm, Atkinson & Plass (1995): "Ropes: an Alternative to Strings" — the canonical rope paper; lazy concatenation, Fibonacci rebalancing, stack-based iteration +- Blelloch, Ferizovic & Sun (2016): "Just Join for Parallel Ordered Sets" — the split-join paradigm that the rope's `rope-split-at` / `rope-join` follows + +--- + +## References + +- Adams (1992): "Implementing Sets Efficiently in a Functional Language" — split/join paradigm, divide-and-conquer set operations +- Adams (1993): "Efficient sets—a balancing act" — elegant functional pearls treatment +- Hirai & Yamamoto (2011): "Balancing Weight-Balanced Trees" — Coq-verified (δ=3, γ=2) parameters +- Blelloch, Ferizovic & Sun (2016): "Just Join for Parallel Ordered Sets" — work-optimality proof, parallel algorithms +- Sun, Ferizovic & Blelloch (2018): "PAM: Parallel Augmented Maps" — augmented tree framework (interval/segment trees) diff --git a/doc/api/com.dean.interval-tree.tree.html b/doc/api/com.dean.interval-tree.tree.html deleted file mode 100644 index 6045018..0000000 --- a/doc/api/com.dean.interval-tree.tree.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean.interval-tree.tree documentation

com.dean.interval-tree.tree

difference

intersection

interval-map

(interval-map)(interval-map coll)

interval-set

(interval-set)(interval-set coll)

ordered-map

(ordered-map)(ordered-map coll)(ordered-map compare-fn coll)

ordered-map-by

(ordered-map-by pred coll)

ordered-set

(ordered-set)(ordered-set coll)

ordered-set-by

(ordered-set-by pred coll)

subset

superset

union

\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.interval-map.html b/doc/api/com.dean.interval-tree.tree.interval-map.html deleted file mode 100644 index 6b97b2a..0000000 --- a/doc/api/com.dean.interval-tree.tree.interval-map.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean.interval-tree.tree.interval-map documentation

com.dean.interval-tree.tree.interval-map

with-interval-map

macro

(with-interval-map x & body)
\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.interval-set.html b/doc/api/com.dean.interval-tree.tree.interval-set.html deleted file mode 100644 index c346d93..0000000 --- a/doc/api/com.dean.interval-tree.tree.interval-set.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean.interval-tree.tree.interval-set documentation

com.dean.interval-tree.tree.interval-set

with-interval-set

macro

(with-interval-set x & body)
\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.interval.html b/doc/api/com.dean.interval-tree.tree.interval.html deleted file mode 100644 index a8a721a..0000000 --- a/doc/api/com.dean.interval-tree.tree.interval.html +++ /dev/null @@ -1,11 +0,0 @@ - -com.dean.interval-tree.tree.interval documentation

com.dean.interval-tree.tree.interval

includes?

(includes? i0 i1)
Inclusive intervals?    [==========]
-[====]

intersects?

(intersects? i0 i1)
returns true if there is any common point between intervals i0 and i1
-

ordered-pair

(ordered-pair x y)(ordered-pair x)
Ensure a normalized interval pair.
-

ordered-pair?

(ordered-pair? x)
valid interval pair?
-

overlaps?

(overlaps? i0 i1)
Overlapping intervals?   [=========]
-[=========]

PInterval

protocol

an interval is represented as an ordered pair of endpoints
-

members

a

(a _)
interval start coordinate
-

b

(b _)
interval end coordinate
-
\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.node.html b/doc/api/com.dean.interval-tree.tree.node.html deleted file mode 100644 index f368800..0000000 --- a/doc/api/com.dean.interval-tree.tree.node.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean.interval-tree.tree.node documentation

com.dean.interval-tree.tree.node

-k

(-k n)

-kv

(-kv n)

-l

(-l n)

-r

(-r n)

-v

(-v n)

-x

(-x n)

-z

(-z n)

leaf

(leaf)

leaf?

(leaf? x)
\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.order.html b/doc/api/com.dean.interval-tree.tree.order.html deleted file mode 100644 index c0d50a6..0000000 --- a/doc/api/com.dean.interval-tree.tree.order.html +++ /dev/null @@ -1,4 +0,0 @@ - -com.dean.interval-tree.tree.order documentation

com.dean.interval-tree.tree.order

*compare*

dynamic

<=

(<= x)(<= x y)(<= x y & more)

>=

(>= x)(>= x y)(>= x y & more)

compare

(compare x y)

compare-by

(compare-by pred)
Given a predicate that defines a total order over some domain,
-return a three-way comparator built from it.

compare<

(compare< x y)

compare<=

(compare<= x y)

compare=

(compare= x y)

compare>

(compare> x y)

compare>=

(compare>= x y)

max

(max x & args)

normal-compare

(normal-compare x y)

normalize

(normalize x)
\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.ordered-map.html b/doc/api/com.dean.interval-tree.tree.ordered-map.html deleted file mode 100644 index f28fd72..0000000 --- a/doc/api/com.dean.interval-tree.tree.ordered-map.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean.interval-tree.tree.ordered-map documentation

com.dean.interval-tree.tree.ordered-map

with-ordered-map

macro

(with-ordered-map x & body)
\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.ordered-set.html b/doc/api/com.dean.interval-tree.tree.ordered-set.html deleted file mode 100644 index 9df1a2f..0000000 --- a/doc/api/com.dean.interval-tree.tree.ordered-set.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean.interval-tree.tree.ordered-set documentation

com.dean.interval-tree.tree.ordered-set

with-ordered-set

macro

(with-ordered-set x & body)
\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.protocol.html b/doc/api/com.dean.interval-tree.tree.protocol.html deleted file mode 100644 index c4088e5..0000000 --- a/doc/api/com.dean.interval-tree.tree.protocol.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean.interval-tree.tree.protocol documentation

com.dean.interval-tree.tree.protocol

PExtensibleSet

protocol

members

difference

(difference this that)

intersection

(intersection this that)

subset

(subset this that)

superset

(superset this that)

union

(union this that)
\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.root.html b/doc/api/com.dean.interval-tree.tree.root.html deleted file mode 100644 index 17a35b8..0000000 --- a/doc/api/com.dean.interval-tree.tree.root.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean.interval-tree.tree.root documentation

com.dean.interval-tree.tree.root

\ No newline at end of file diff --git a/doc/api/com.dean.interval-tree.tree.tree.html b/doc/api/com.dean.interval-tree.tree.tree.html deleted file mode 100644 index cb601b1..0000000 --- a/doc/api/com.dean.interval-tree.tree.tree.html +++ /dev/null @@ -1,154 +0,0 @@ - -com.dean.interval-tree.tree.tree documentation

com.dean.interval-tree.tree.tree

*n-join*

dynamic

*t-join*

dynamic

+delta+

The primary balancing rotation coefficient that is used for the
-determination whether two subtrees of a node are in balance or
-require adjustment by means of a rotation operation.  The specific
-rotation to be performed is determined by `+gamma+`.

+gamma+

The secondary balancing rotation coefficient that is used for the
-determination of whether a single or double rotation operation should
-occur, once it has been decided based on `+delta+` that a rotation is
-indeed required.

kvlr

macro

(kvlr [ksym vsym lsym rsym] n & body)
destructure node n: key value left right. This is the principal destructuring macro
-for operating on regions of trees

lr

macro

(lr [lsym rsym] n & body)

maybe-z

(maybe-z n)

node-add

(node-add n k)(node-add n k v)
Insert a new key/value into the tree rooted at n.
-

node-chunked-fold

(node-chunked-fold i n combinef reducef)
Parallel chunked fold mechansim to suport clojure.core.reducers/CollFold
-

node-compare

(node-compare accessor n1 n2)
return 3-way comparison of the trees n1 and n2 using an accessor
-to compare specific node consitituent values: :k, :v, :kv, or any
-user-specifed function.  Default, when not specified, to the
-entire node structure. return-value semantics:
- -1  -> n1 is LESS-THAN    n2
-  0  -> n1 is EQUAL-TO     n2
- +1  -> n1 is GREATER-THAN n2

node-concat2

(node-concat2 l r)
Join two trees, the left rooted at l, and the right at r,
-performing a single balancing operation on the resulting tree, if
-needed. Assumes all keys in l are smaller than all keys in r, and
-the relative balance of l and r is such that no more than one rotation
-operation will be required to balance the resulting tree.

node-concat3

(node-concat3 k v l r)
Join two trees, the left rooted at l, and the right at r,
-with a new key/value, performing rotation operations on the resulting
-trees and subtrees. Assumes all keys in l are smaller than all keys in
-r, and the relative balance of l and r is such that no more than one
-rotation operation will be required to balance the resulting tree.

node-create

(node-create k v l r)
Join left and right subtrees at root k/v.
-Assumes all keys in l < k < all keys in r.

node-create-weight-balanced

(node-create-weight-balanced k v l r)
Join left and right weight-balanced subtrees at root k/v.
-Assumes all keys in l < k < all keys in r.

node-create-weight-balanced-interval

(node-create-weight-balanced-interval i v l r)
Join left and right weight-balanced interval subtrees at root k/v.
-Assumes all keys in l < k < all keys in r.

node-enum-first

node-enum-prior

(node-enum-prior enum)

node-enum-rest

(node-enum-rest enum)

node-enumerator

(node-enumerator n)(node-enumerator n enum)
Efficient mechanism to accomplish partial enumeration of
-tree-structure into a seq representation without incurring the
-overhead of operating over the entire tree.  Used internally for
-implementation of higher-level collection api routines

node-enumerator-reverse

(node-enumerator-reverse n)(node-enumerator-reverse n enum)

node-filter

(node-filter p n)
return a tree with all nodes of n satisfying predicate p.
-

node-find

(node-find n k)
find a node in n whose key = k
-

node-find-best-interval

(node-find-best-interval n i pred)

node-find-intervals

(node-find-intervals n i)

node-find-nearest

(node-find-nearest n k & [gt-or-lt])
Find the nearest k according to relation expressed by :< or :>
-

node-fold-left

(node-fold-left f n)(node-fold-left f base n)
Fold-left (reduce) the collection from least to greatest.
-

node-fold-right

(node-fold-right f n)(node-fold-right f base n)
Fold-right (reduce) the collection from greatest to least.
-

node-greatest

(node-greatest n)
Return the node containing the minimum key of the tree rooted at n
-

node-healthy?

(node-healthy? n)
verify node `n` and all descendants satisfy the node-invariants
-of a weight-balanced binary tree.

node-invert

(node-invert n)
return a tree in which the keys and values of n are reversed.
-

node-iter

(node-iter n f)
For the side-effect, apply f to each node of the tree rooted at n.
-

node-iter-reverse

(node-iter-reverse n f)
For the side-effect, apply f to each node of the tree rooted at n.
-

node-least

(node-least n)
Return the node containing the minimum key of the tree rooted at n
-

node-map-compare

node-map-merge

(node-map-merge n1 n2 merge-fn)
Merge two maps in worst case linear time.
-

node-nth

(node-nth n index)
Return nth node from the beginning of the ordered tree rooted at n.
-(Logarithmic Time)

node-rank

(node-rank n k)
Return the rank (sequential position) of a given KEY within the
-ordered tree rooted at n. (Logarithmic Time)

node-remove

(node-remove n k)
remove the node whose key is equal to k, if present.
-

node-remove-greatest

(node-remove-greatest n)
Return a tree the same as the one rooted at n, with the node
-containing the maximum key removed. See node-greatest.

node-remove-least

(node-remove-least n)
Return a tree the same as the one rooted at n, with the node
-containing the minimum key removed. See node-least.

node-seq

(node-seq n)
Return a (lazy) seq of nodes in tree rooted at n in the order they occur.
-(Logarithmic Time)

node-seq-reverse

(node-seq-reverse n)
Return a (lazy) seq of nodes in tree rooted at n in reverse order.
-

node-set-compare

node-set-difference

(node-set-difference n1 n2)

node-set-intersection

(node-set-intersection n1 n2)
set intersection
-

node-set-union

(node-set-union n1 n2)
set union
-

node-singleton

(node-singleton k v)
Create and return a newly allocated, balanced tree
-containing a single association, that of key K with value V.

node-size

(node-size n)
returns the balance metric of the tree rooted at n.
-

node-split

(node-split n k)
returns a triple (l present r) where: l is the set of elements of
-n that are < k, r is the set of elements of n that are > k, present
-is false if n contains no element equal to k, or (k v) if n contains
-an element with key equal to k.

node-split-greater

(node-split-greater n k)
return a tree of all nodes whose key is greater than k (Logarithmic time).
-

node-split-lesser

(node-split-lesser n k)
return a tree of all nodes whose key is less than k (Logarithmic time).
-

node-split-nth

(node-split-nth n i)
return a tree of all nodes whose position is >= i. (Logarithmic Time)
-

node-stitch

(node-stitch k v l r)
The `stitch` operation is the sole balancing constructor and
-interface to the specific balancing rotation algorithm of the tree.
-other balancing algorithms (AVL Tree, Red-Black Tree) can be
-implemented here without effect to other aspects of the tree.
-Sometimes referred to as `n-join` operation

node-stitch-weight-balanced

(node-stitch-weight-balanced k v l r)
Weight-Balancing Algorithm:
-
-Join left and right subtrees at root k/v, performing a single or
-double rotation to balance the resulting tree, if needed.  Assumes
-all keys in l < k < all keys in r, and the relative weight balance
-of the left and right subtrees is such that no more than one
-single/double rotation will result in each subtree being less than
-+delta+ times the weight of the other.  This is the heart of tree
-construction.

node-subseq

(node-subseq n from)(node-subseq n from to)
Return a (lazy) seq of nodes for the slice of the tree beginning
-at position `from` ending at `to`.

node-subset?

(node-subset? super sub)
return true if `sub` is a subset of `super`
-

node-vec

(node-vec n & {:keys [accessor reverse?]})
Eagerly return a vector of all nodes in tree rooted at n in
-the specified order, optionally using an accessor to extract
-specific node consitituent values: :k, :v, :kv, or any
-user-specifed function.  Default, when not specified, to the
-entire node structure.

node-weight

(node-weight n)
returns node weight as appropriate for rotation calculations using
-the 'revised non-variant algorithm' for weight balanced binary tree.

rotate-double-left

(rotate-double-left ak av x c)
Perform a double left rotation, moving Y1, the left subtree of the
-left subtree of the right subtree of A, into the left subtree (shown
-below).  This must occur in order to restore proper balance when the
-weight of the left subtree of node A is less then the weight of the
-right subtree of node A multiplied by rotation coefficient +delta+
-and the weight of the left subtree of node B is greater than or equal
-to the weight of the right subtree of node B multiplied by rotation
-coefficient +gamma+.
-
-              ,---,                                    ,---,
-              | A |                                    | B |
-           ___:---:___                             ____:---:____
-      ,---:           :---,                   ,---:             :---,
-      | X |           | C |                   | A |             | C |
-      '---'           :---:         =>        :---:             :---:
-                 ,---:     :---,         ,---:     :---,   ,---:     :---,
-                 | B |     | Z |         | X |     | y1|   | y2|     | Z |
-                 :---:     '---'         '---'     '---'   '---'     '---'
-            ,---:     :---,
-            | y1|     | y2|
-            '---'     '---'

rotate-double-right

(rotate-double-right ck cv a z)
Perform a double right rotation, moving Y2, the right subtree of
-the right subtree of the left subtree of C, into the right
-subtree (shown below).  This must occur in order to restore proper
-balance when the weight of the right subtree of node C is less then
-the weight of the left subtree of node C multiplied by rotation
-coefficient +delta+ and the weight of the right subtree of node B
-is greater than or equal to the weight of the left subtree of node B
-multiplied by rotation coefficient +gamma+.
-
-              ,---,                                    ,---,
-              | C |                                    | B |
-           ___:---:___                             ____:---:____
-      ,---:           :---,                   ,---:             :---,
-      | A |           | Z |                   | A |             | C |
-      :---:           '---'        =>         :---:             :---:
- ,---:     :---,                         ,---:     :---,   ,---:     :---,
- | X |     | B |                         | X |     | y1|   | y2|     | Z |
- '---'     :---:                         '---'     '---'   '---'     '---'
-      ,---:     :---,
-      | y1|     | y2|
-      '---'     '---'

rotate-single-left

(rotate-single-left ak av x b)
Perform a single left rotation, moving Y, the left subtree of the
-right subtree of A, into the left subtree (shown below).  This must
-occur in order to restore proper balance when the weight of the left
-subtree of node A is less then the weight of the right subtree of
-node A multiplied by rotation coefficient +delta+ and the weight of
-the left subtree of node B is less than the weight of the right subtree
-of node B multiplied by rotation coefficient +gamma+
-
-              ,---,                                  ,---,
-              | A |                                  | B |
-              :---:                                  :---:
-             :     :                                :     :
-        ,---:       :---,                      ,---:       :---,
-        | X |       | B |           =>         | A |       | Z |
-        '---'       :---:                      :---:       '---'
-               ,---:     :---,            ,---:     :---,
-               | Y |     | Z |            | X |     | Y |
-               '---'     '---'            '---'     '---'

rotate-single-right

(rotate-single-right bk bv a z)
Perform a single right rotation, moving Y, the right subtree of the
-left subtree of B, into the right subtree (shown below).  This must
-occur in order to restore proper balance when the weight of the right
-subtree of node B is less then the weight of the left subtree of
-node B multiplied by rotation coefficient +delta+ and the weight of the
-right subtree of node A is less than the weight of the left subtree
-of node A multiplied by rotation coefficient +gamma+.
-
-              ,---,                                  ,---,
-              | B |                                  | A |
-              :---:                                  :---:
-             :     :                                :     :
-        ,---:       :---,                      ,---:       :---,
-        | A |       | Z |          =>          | X |       | B |
-        :---:       '---'                      '---'       :---:
-   ,---:     :---,                                    ,---:     :---,
-   | X |     | Y |                                    | Y |     | Z |
-   '---'     '---'                                    '---'     '---'
\ No newline at end of file diff --git a/doc/api/css/default.css b/doc/api/css/default.css deleted file mode 100644 index 33f78fe..0000000 --- a/doc/api/css/default.css +++ /dev/null @@ -1,551 +0,0 @@ -body { - font-family: Helvetica, Arial, sans-serif; - font-size: 15px; -} - -pre, code { - font-family: Monaco, DejaVu Sans Mono, Consolas, monospace; - font-size: 9pt; - margin: 15px 0; -} - -h1 { - font-weight: normal; - font-size: 29px; - margin: 10px 0 2px 0; - padding: 0; -} - -h2 { - font-weight: normal; - font-size: 25px; -} - -h5.license { - margin: 9px 0 22px 0; - color: #555; - font-weight: normal; - font-size: 12px; - font-style: italic; -} - -.document h1, .namespace-index h1 { - font-size: 32px; - margin-top: 12px; -} - -#header, #content, .sidebar { - position: fixed; -} - -#header { - top: 0; - left: 0; - right: 0; - height: 22px; - color: #f5f5f5; - padding: 5px 7px; -} - -#content { - top: 32px; - right: 0; - bottom: 0; - overflow: auto; - background: #fff; - color: #333; - padding: 0 18px; -} - -.sidebar { - position: fixed; - top: 32px; - bottom: 0; - overflow: auto; -} - -.sidebar.primary { - background: #e2e2e2; - border-right: solid 1px #cccccc; - left: 0; - width: 250px; -} - -.sidebar.secondary { - background: #f2f2f2; - border-right: solid 1px #d7d7d7; - left: 251px; - width: 200px; -} - -#content.namespace-index, #content.document { - left: 251px; -} - -#content.namespace-docs { - left: 452px; -} - -#content.document { - padding-bottom: 10%; -} - -#header { - background: #3f3f3f; - box-shadow: 0 0 8px rgba(0, 0, 0, 0.4); - z-index: 100; -} - -#header h1 { - margin: 0; - padding: 0; - font-size: 18px; - font-weight: lighter; - text-shadow: -1px -1px 0px #333; -} - -#header h1 .project-version { - font-weight: normal; -} - -.project-version { - padding-left: 0.15em; -} - -#header a, .sidebar a { - display: block; - text-decoration: none; -} - -#header a { - color: #f5f5f5; -} - -.sidebar a { - color: #333; -} - -#header h2 { - float: right; - font-size: 9pt; - font-weight: normal; - margin: 4px 3px; - padding: 0; - color: #bbb; -} - -#header h2 a { - display: inline; -} - -.sidebar h3 { - margin: 0; - padding: 10px 13px 0 13px; - font-size: 19px; - font-weight: lighter; -} - -.sidebar h3 a { - color: #444; -} - -.sidebar h3.no-link { - color: #636363; -} - -.sidebar ul { - padding: 7px 0 6px 0; - margin: 0; -} - -.sidebar ul.index-link { - padding-bottom: 4px; -} - -.sidebar li { - display: block; - vertical-align: middle; -} - -.sidebar li a, .sidebar li .no-link { - border-left: 3px solid transparent; - padding: 0 10px; - white-space: nowrap; -} - -.sidebar li .no-link { - display: block; - color: #777; - font-style: italic; -} - -.sidebar li .inner { - display: inline-block; - padding-top: 7px; - height: 24px; -} - -.sidebar li a, .sidebar li .tree { - height: 31px; -} - -.depth-1 .inner { padding-left: 2px; } -.depth-2 .inner { padding-left: 6px; } -.depth-3 .inner { padding-left: 20px; } -.depth-4 .inner { padding-left: 34px; } -.depth-5 .inner { padding-left: 48px; } -.depth-6 .inner { padding-left: 62px; } - -.sidebar li .tree { - display: block; - float: left; - position: relative; - top: -10px; - margin: 0 4px 0 0; - padding: 0; -} - -.sidebar li.depth-1 .tree { - display: none; -} - -.sidebar li .tree .top, .sidebar li .tree .bottom { - display: block; - margin: 0; - padding: 0; - width: 7px; -} - -.sidebar li .tree .top { - border-left: 1px solid #aaa; - border-bottom: 1px solid #aaa; - height: 19px; -} - -.sidebar li .tree .bottom { - height: 22px; -} - -.sidebar li.branch .tree .bottom { - border-left: 1px solid #aaa; -} - -.sidebar.primary li.current a { - border-left: 3px solid #a33; - color: #a33; -} - -.sidebar.secondary li.current a { - border-left: 3px solid #33a; - color: #33a; -} - -.namespace-index h2 { - margin: 30px 0 0 0; -} - -.namespace-index h3 { - font-size: 16px; - font-weight: bold; - margin-bottom: 0; -} - -.namespace-index .topics { - padding-left: 30px; - margin: 11px 0 0 0; -} - -.namespace-index .topics li { - padding: 5px 0; -} - -.namespace-docs h3 { - font-size: 18px; - font-weight: bold; -} - -.public h3 { - margin: 0; - float: left; -} - -.usage { - clear: both; -} - -.public { - margin: 0; - border-top: 1px solid #e0e0e0; - padding-top: 14px; - padding-bottom: 6px; -} - -.public:last-child { - margin-bottom: 20%; -} - -.members .public:last-child { - margin-bottom: 0; -} - -.members { - margin: 15px 0; -} - -.members h4 { - color: #555; - font-weight: normal; - font-variant: small-caps; - margin: 0 0 5px 0; -} - -.members .inner { - padding-top: 5px; - padding-left: 12px; - margin-top: 2px; - margin-left: 7px; - border-left: 1px solid #bbb; -} - -#content .members .inner h3 { - font-size: 12pt; -} - -.members .public { - border-top: none; - margin-top: 0; - padding-top: 6px; - padding-bottom: 0; -} - -.members .public:first-child { - padding-top: 0; -} - -h4.type, -h4.dynamic, -h4.added, -h4.deprecated { - float: left; - margin: 3px 10px 15px 0; - font-size: 15px; - font-weight: bold; - font-variant: small-caps; -} - -.public h4.type, -.public h4.dynamic, -.public h4.added, -.public h4.deprecated { - font-size: 13px; - font-weight: bold; - margin: 3px 0 0 10px; -} - -.members h4.type, -.members h4.added, -.members h4.deprecated { - margin-top: 1px; -} - -h4.type { - color: #717171; -} - -h4.dynamic { - color: #9933aa; -} - -h4.added { - color: #508820; -} - -h4.deprecated { - color: #880000; -} - -.namespace { - margin-bottom: 30px; -} - -.namespace:last-child { - margin-bottom: 10%; -} - -.index { - padding: 0; - font-size: 80%; - margin: 15px 0; - line-height: 16px; -} - -.index * { - display: inline; -} - -.index p { - padding-right: 3px; -} - -.index li { - padding-right: 5px; -} - -.index ul { - padding-left: 0; -} - -.type-sig { - clear: both; - color: #088; -} - -.type-sig pre { - padding-top: 10px; - margin: 0; -} - -.usage code { - display: block; - color: #008; - margin: 2px 0; -} - -.usage code:first-child { - padding-top: 10px; -} - -p { - margin: 15px 0; -} - -.public p:first-child, .public pre.plaintext { - margin-top: 12px; -} - -.doc { - margin: 0 0 26px 0; - clear: both; -} - -.public .doc { - margin: 0; -} - -.namespace-index .doc { - margin-bottom: 20px; -} - -.namespace-index .namespace .doc { - margin-bottom: 10px; -} - -.markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td { - line-height: 22px; -} - -.markdown li { - padding: 2px 0; -} - -.markdown h2 { - font-weight: normal; - font-size: 25px; - margin: 30px 0 10px 0; -} - -.markdown h3 { - font-weight: normal; - font-size: 20px; - margin: 30px 0 0 0; -} - -.markdown h4 { - font-size: 15px; - margin: 22px 0 -4px 0; -} - -.doc, .public, .namespace .index { - max-width: 680px; - overflow-x: visible; -} - -.markdown pre > code { - display: block; - padding: 10px; -} - -.markdown pre > code, .src-link a { - border: 1px solid #e4e4e4; - border-radius: 2px; -} - -.markdown code:not(.hljs), .src-link a { - background: #f6f6f6; -} - -pre.deps { - display: inline-block; - margin: 0 10px; - border: 1px solid #e4e4e4; - border-radius: 2px; - padding: 10px; - background-color: #f6f6f6; -} - -.markdown hr { - border-style: solid; - border-top: none; - color: #ccc; -} - -.doc ul, .doc ol { - padding-left: 30px; -} - -.doc table { - border-collapse: collapse; - margin: 0 10px; -} - -.doc table td, .doc table th { - border: 1px solid #dddddd; - padding: 4px 6px; -} - -.doc table th { - background: #f2f2f2; -} - -.doc dl { - margin: 0 10px 20px 10px; -} - -.doc dl dt { - font-weight: bold; - margin: 0; - padding: 3px 0; - border-bottom: 1px solid #ddd; -} - -.doc dl dd { - padding: 5px 0; - margin: 0 0 5px 10px; -} - -.doc abbr { - border-bottom: 1px dotted #333; - font-variant: none; - cursor: help; -} - -.src-link { - margin-bottom: 15px; -} - -.src-link a { - font-size: 70%; - padding: 1px 4px; - text-decoration: none; - color: #5555bb; -} diff --git a/doc/api/css/highlight.css b/doc/api/css/highlight.css deleted file mode 100644 index d0cdaa3..0000000 --- a/doc/api/css/highlight.css +++ /dev/null @@ -1,97 +0,0 @@ -/* -github.com style (c) Vasily Polovnyov -*/ - -.hljs { - display: block; - overflow-x: auto; - padding: 0.5em; - color: #333; - background: #f8f8f8; -} - -.hljs-comment, -.hljs-quote { - color: #998; - font-style: italic; -} - -.hljs-keyword, -.hljs-selector-tag, -.hljs-subst { - color: #333; - font-weight: bold; -} - -.hljs-number, -.hljs-literal, -.hljs-variable, -.hljs-template-variable, -.hljs-tag .hljs-attr { - color: #008080; -} - -.hljs-string, -.hljs-doctag { - color: #d14; -} - -.hljs-title, -.hljs-section, -.hljs-selector-id { - color: #900; - font-weight: bold; -} - -.hljs-subst { - font-weight: normal; -} - -.hljs-type, -.hljs-class .hljs-title { - color: #458; - font-weight: bold; -} - -.hljs-tag, -.hljs-name, -.hljs-attribute { - color: #000080; - font-weight: normal; -} - -.hljs-regexp, -.hljs-link { - color: #009926; -} - -.hljs-symbol, -.hljs-bullet { - color: #990073; -} - -.hljs-built_in, -.hljs-builtin-name { - color: #0086b3; -} - -.hljs-meta { - color: #999; - font-weight: bold; -} - -.hljs-deletion { - background: #fdd; -} - -.hljs-addition { - background: #dfd; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} diff --git a/doc/api/index.html b/doc/api/index.html deleted file mode 100644 index c2cae52..0000000 --- a/doc/api/index.html +++ /dev/null @@ -1,3 +0,0 @@ - -com.dean/interval-tree 0.1.0

com.dean/interval-tree 0.1.0

Released under the Eclipse Public License

Modular, Extensible, Foldable Weight-Balanced Tree.

Installation

To install, add the following dependency to your project or build file:

[com.dean/interval-tree "0.1.0"]

Namespaces

com.dean.interval-tree.tree.node

Public variables and functions:

com.dean.interval-tree.tree.root

Public variables and functions:

    \ No newline at end of file diff --git a/doc/api/js/highlight.min.js b/doc/api/js/highlight.min.js deleted file mode 100644 index 6486ffd..0000000 --- a/doc/api/js/highlight.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! highlight.js v9.6.0 | BSD3 License | git.io/hljslicense */ -!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/[&<>]/gm,function(e){return I[e]})}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return R(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||R(i))return i}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function u(e){l+=""}function c(e){("start"===e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):E(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"===e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function l(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function h(e,n,t,r){var a=r?"":y.classPrefix,i='',i+n+o}function p(){var e,t,r,a;if(!E.k)return n(B);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(B);r;)a+=n(B.substr(t,r.index-t)),e=g(E,r),e?(M+=e[1],a+=h(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(B);return a+n(B.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!x[E.sL])return n(B);var t=e?l(E.sL,B,!0,L[E.sL]):f(B,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(L[E.sL]=t.top),h(t.language,t.value,!1,!0)}function b(){k+=null!=E.sL?d():p(),B=""}function v(e){k+=e.cN?h(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(B+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?B+=n:(t.eB&&(B+=n),b(),t.rB||t.eB||(B=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?B+=n:(a.rE||a.eE||(B+=n),b(),a.eE&&(B=n));do E.cN&&(k+=C),E.skip||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return B+=n,n.length||1}var N=R(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var w,E=i||N,L={},k="";for(w=E;w!==N;w=w.parent)w.cN&&(k=h(w.cN,"",!0)+k);var B="",M=0;try{for(var I,j,O=0;;){if(E.t.lastIndex=O,I=E.t.exec(t),!I)break;j=m(t.substr(O,I.index-O),I[0]),O=I.index+j}for(m(t.substr(O)),w=E;w.parent;w=w.parent)w.cN&&(k+=C);return{r:M,value:k,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function f(e,t){t=t||y.languages||E(x);var r={r:0,value:n(e)},a=r;return t.filter(R).forEach(function(n){var t=l(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function g(e){return y.tabReplace||y.useBR?e.replace(M,function(e,n){return y.useBR&&"\n"===e?"
    ":y.tabReplace?n.replace(/\t/g,y.tabReplace):void 0}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n,t,r,o,s,p=i(e);a(p)||(y.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,s=n.textContent,r=p?l(p,s,!0):f(s),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),s)),r.value=g(r.value),e.innerHTML=r.value,e.className=h(e.className,p,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function d(e){y=o(y,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");w.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function N(){return E(x)}function R(e){return e=(e||"").toLowerCase(),x[e]||x[L[e]]}var w=[],E=Object.keys,x={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="
    ",y={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},I={"&":"&","<":"<",">":">"};return e.highlight=l,e.highlightAuto=f,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=R,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("clojure",function(e){var t={"builtin-name":"def defonce cond apply if-not if-let if not not= = < > <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"},r="a-zA-Z_\\-!.?+*=<>&#'",n="["+r+"]["+r+"0-9/;:]*",a="[-+]?\\d+(\\.\\d+)?",o={b:n,r:0},s={cN:"number",b:a,r:0},i=e.inherit(e.QSM,{i:null}),c=e.C(";","$",{r:0}),d={cN:"literal",b:/\b(true|false|nil)\b/},l={b:"[\\[\\{]",e:"[\\]\\}]"},m={cN:"comment",b:"\\^"+n},p=e.C("\\^\\{","\\}"),u={cN:"symbol",b:"[:]{1,2}"+n},f={b:"\\(",e:"\\)"},h={eW:!0,r:0},y={k:t,l:n,cN:"name",b:n,starts:h},b=[f,i,m,p,c,u,l,s,d,o];return f.c=[e.C("comment",""),y,h],h.c=b,l.c=b,{aliases:["clj"],i:/\S/,c:[f,i,m,p,c,u,l,s,d]}});hljs.registerLanguage("clojure-repl",function(e){return{c:[{cN:"meta",b:/^([\w.-]+|\s*#_)=>/,starts:{e:/$/,sL:"clojure"}}]}}); \ No newline at end of file diff --git a/doc/api/js/jquery.min.js b/doc/api/js/jquery.min.js deleted file mode 100644 index 73f33fb..0000000 --- a/doc/api/js/jquery.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
    ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f -}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML="
    a",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/\s*$/g,sb={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:l.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?""!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("