From 73830097874b5629d45d9360a0e1592f3a03b897 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 15:34:22 +0000 Subject: [PATCH] Deployed c23e90c with MkDocs version: 1.6.1 --- .nojekyll | 0 404.html | 586 ++ algorithms/img/binary_search.png | Bin 0 -> 82094 bytes algorithms/img/divide_and_conquer.png | Bin 0 -> 24061 bytes algorithms/img/inzva-logo.png | Bin 0 -> 7530 bytes algorithms/img/linear_search.png | Bin 0 -> 108811 bytes algorithms/img/ternary_search.png | Bin 0 -> 33247 bytes algorithms/index.html | 1596 ++++ assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.c8b220af.min.js | 16 + assets/javascripts/bundle.c8b220af.min.js.map | 7 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.el.min.js | 1 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.he.min.js | 1 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.f8cc74c7.min.js | 42 + .../workers/search.f8cc74c7.min.js.map | 7 + assets/stylesheets/main.8608ea7d.min.css | 1 + assets/stylesheets/main.8608ea7d.min.css.map | 1 + assets/stylesheets/palette.06af60db.min.css | 1 + .../stylesheets/palette.06af60db.min.css.map | 1 + data-structures/deque/index.html | 629 ++ data-structures/fenwick-tree/index.html | 827 ++ data-structures/img/fenwick.png | Bin 0 -> 7569 bytes data-structures/img/linkedlist.png | Bin 0 -> 56587 bytes data-structures/img/mo.png | Bin 0 -> 149300 bytes data-structures/img/naive_update.png | Bin 0 -> 46955 bytes data-structures/img/query_soln.png | Bin 0 -> 142140 bytes data-structures/img/segtree.png | Bin 0 -> 55367 bytes data-structures/img/segtreequery.png | Bin 0 -> 57984 bytes data-structures/img/segtreeupdate.png | Bin 0 -> 59267 bytes data-structures/img/trie.png | Bin 0 -> 68708 bytes data-structures/img/updated_segtree.png | Bin 0 -> 141943 bytes data-structures/index.html | 1065 +++ data-structures/linked-list/index.html | 677 ++ .../lowest-common-ancestor/index.html | 654 ++ data-structures/mo-algorithm/index.html | 793 ++ data-structures/prefix-sum/index.html | 701 ++ data-structures/queue/index.html | 628 ++ data-structures/segment-tree/index.html | 1128 +++ data-structures/sparse-table/index.html | 741 ++ data-structures/sqrt-decomposition/index.html | 847 +++ data-structures/stack/index.html | 630 ++ data-structures/trie/index.html | 704 ++ dynamic-programming/bitmask-dp/index.html | 766 ++ .../common-dp-problems/index.html | 1063 +++ dynamic-programming/digit-dp/index.html | 811 ++ dynamic-programming/dp-on-dags/index.html | 758 ++ .../dp-on-rooted-trees/index.html | 744 ++ .../dynamic-programming/index.html | 793 ++ .../greedy-algorithms/index.html | 957 +++ dynamic-programming/img/1st_power_matrix.png | Bin 0 -> 217057 bytes dynamic-programming/img/3rd_power_matrix.png | Bin 0 -> 231840 bytes dynamic-programming/img/coin_change.png | Bin 0 -> 133174 bytes .../img/left_childright_sibling.png | Bin 0 -> 21001 bytes .../img/recursive_memoization.png | Bin 0 -> 225564 bytes dynamic-programming/index.html | 885 +++ .../tree-child-sibling-notation/index.html | 700 ++ .../walk-counting-with-matrix/index.html | 700 ++ graph/binary-search-tree/index.html | 897 +++ graph/bipartite-checking/index.html | 686 ++ graph/breadth-first-search/index.html | 737 ++ .../index.html | 828 ++ graph/cycle-finding/index.html | 640 ++ graph/definitions/index.html | 715 ++ graph/depth-first-search/index.html | 761 ++ graph/heap/index.html | 847 +++ graph/img/360px-Max-Heap.png | Bin 0 -> 21108 bytes graph/img/Heap-as-array.png | Bin 0 -> 13456 bytes graph/img/bfs.jpg | Bin 0 -> 24506 bytes graph/img/biconnectivity.png | Bin 0 -> 22328 bytes graph/img/binary-tree.png | Bin 0 -> 23185 bytes graph/img/binarytree.png | Bin 0 -> 16139 bytes graph/img/bipartite.png | Bin 0 -> 18502 bytes graph/img/bipartite_check.png | Bin 0 -> 25599 bytes graph/img/cut-point.png | Bin 0 -> 17786 bytes graph/img/dag.png | Bin 0 -> 19876 bytes graph/img/dfs.jpg | Bin 0 -> 43600 bytes graph/img/directed_acyclic_graph.png | Bin 0 -> 28311 bytes graph/img/first-flow.png | Bin 0 -> 401212 bytes graph/img/flow1.png | Bin 0 -> 22545 bytes graph/img/flow2.png | Bin 0 -> 23887 bytes graph/img/flow3.png | Bin 0 -> 23374 bytes graph/img/flow4.png | Bin 0 -> 24084 bytes graph/img/flow5.png | Bin 0 -> 23859 bytes graph/img/heap1.png | Bin 0 -> 42406 bytes graph/img/heap2.png | Bin 0 -> 21290 bytes graph/img/kruskal.jpg | Bin 0 -> 131539 bytes graph/img/mst.png | Bin 0 -> 5868 bytes graph/img/prim.png | Bin 0 -> 103047 bytes graph/img/scc-graph.png | Bin 0 -> 6390 bytes graph/img/scc.png | Bin 0 -> 14954 bytes graph/img/shortest.png | Bin 0 -> 38763 bytes graph/img/toporder.png | Bin 0 -> 13293 bytes graph/img/tree-def.png | Bin 0 -> 98591 bytes graph/img/types-of-edges.png | Bin 0 -> 54348 bytes graph/index.html | 1029 +++ graph/introduction/index.html | 610 ++ graph/max-flow/index.html | 789 ++ graph/minimum-spanning-tree/index.html | 751 ++ graph/representing-graphs/index.html | 763 ++ graph/shortest-path/index.html | 718 ++ .../index.html | 641 ++ .../strongly-connected-components/index.html | 686 ++ graph/topological-sort/index.html | 731 ++ graph/tree-traversals/index.html | 734 ++ graph/union-find/index.html | 689 ++ index.html | 707 ++ introduction/index.html | 1859 +++++ overrides/partials/content.html | 24 + search/search_index.json | 1 + sitemap.xml | 183 + sitemap.xml.gz | Bin 0 -> 656 bytes static/img/favicon.png | Bin 0 -> 11695 bytes static/img/logo.png | Bin 0 -> 25654 bytes static/javascripts/katex.js | 10 + static/stylesheets/main.css | 4 + 147 files changed, 44700 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 algorithms/img/binary_search.png create mode 100644 algorithms/img/divide_and_conquer.png create mode 100644 algorithms/img/inzva-logo.png create mode 100644 algorithms/img/linear_search.png create mode 100644 algorithms/img/ternary_search.png create mode 100644 algorithms/index.html create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.c8b220af.min.js create mode 100644 assets/javascripts/bundle.c8b220af.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.el.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.he.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.f8cc74c7.min.js create mode 100644 assets/javascripts/workers/search.f8cc74c7.min.js.map create mode 100644 assets/stylesheets/main.8608ea7d.min.css create mode 100644 assets/stylesheets/main.8608ea7d.min.css.map create mode 100644 assets/stylesheets/palette.06af60db.min.css create mode 100644 assets/stylesheets/palette.06af60db.min.css.map create mode 100644 data-structures/deque/index.html create mode 100644 data-structures/fenwick-tree/index.html create mode 100644 data-structures/img/fenwick.png create mode 100644 data-structures/img/linkedlist.png create mode 100644 data-structures/img/mo.png create mode 100644 data-structures/img/naive_update.png create mode 100644 data-structures/img/query_soln.png create mode 100644 data-structures/img/segtree.png create mode 100644 data-structures/img/segtreequery.png create mode 100644 data-structures/img/segtreeupdate.png create mode 100644 data-structures/img/trie.png create mode 100644 data-structures/img/updated_segtree.png create mode 100644 data-structures/index.html create mode 100644 data-structures/linked-list/index.html create mode 100644 data-structures/lowest-common-ancestor/index.html create mode 100644 data-structures/mo-algorithm/index.html create mode 100644 data-structures/prefix-sum/index.html create mode 100644 data-structures/queue/index.html create mode 100644 data-structures/segment-tree/index.html create mode 100644 data-structures/sparse-table/index.html create mode 100644 data-structures/sqrt-decomposition/index.html create mode 100644 data-structures/stack/index.html create mode 100644 data-structures/trie/index.html create mode 100644 dynamic-programming/bitmask-dp/index.html create mode 100644 dynamic-programming/common-dp-problems/index.html create mode 100644 dynamic-programming/digit-dp/index.html create mode 100644 dynamic-programming/dp-on-dags/index.html create mode 100644 dynamic-programming/dp-on-rooted-trees/index.html create mode 100644 dynamic-programming/dynamic-programming/index.html create mode 100644 dynamic-programming/greedy-algorithms/index.html create mode 100644 dynamic-programming/img/1st_power_matrix.png create mode 100644 dynamic-programming/img/3rd_power_matrix.png create mode 100644 dynamic-programming/img/coin_change.png create mode 100644 dynamic-programming/img/left_childright_sibling.png create mode 100644 dynamic-programming/img/recursive_memoization.png create mode 100644 dynamic-programming/index.html create mode 100644 dynamic-programming/tree-child-sibling-notation/index.html create mode 100644 dynamic-programming/walk-counting-with-matrix/index.html create mode 100644 graph/binary-search-tree/index.html create mode 100644 graph/bipartite-checking/index.html create mode 100644 graph/breadth-first-search/index.html create mode 100644 graph/bridges-and-articulation-points/index.html create mode 100644 graph/cycle-finding/index.html create mode 100644 graph/definitions/index.html create mode 100644 graph/depth-first-search/index.html create mode 100644 graph/heap/index.html create mode 100644 graph/img/360px-Max-Heap.png create mode 100644 graph/img/Heap-as-array.png create mode 100644 graph/img/bfs.jpg create mode 100644 graph/img/biconnectivity.png create mode 100644 graph/img/binary-tree.png create mode 100644 graph/img/binarytree.png create mode 100644 graph/img/bipartite.png create mode 100644 graph/img/bipartite_check.png create mode 100644 graph/img/cut-point.png create mode 100644 graph/img/dag.png create mode 100644 graph/img/dfs.jpg create mode 100644 graph/img/directed_acyclic_graph.png create mode 100644 graph/img/first-flow.png create mode 100644 graph/img/flow1.png create mode 100644 graph/img/flow2.png create mode 100644 graph/img/flow3.png create mode 100644 graph/img/flow4.png create mode 100644 graph/img/flow5.png create mode 100644 graph/img/heap1.png create mode 100644 graph/img/heap2.png create mode 100644 graph/img/kruskal.jpg create mode 100644 graph/img/mst.png create mode 100644 graph/img/prim.png create mode 100644 graph/img/scc-graph.png create mode 100644 graph/img/scc.png create mode 100644 graph/img/shortest.png create mode 100644 graph/img/toporder.png create mode 100644 graph/img/tree-def.png create mode 100644 graph/img/types-of-edges.png create mode 100644 graph/index.html create mode 100644 graph/introduction/index.html create mode 100644 graph/max-flow/index.html create mode 100644 graph/minimum-spanning-tree/index.html create mode 100644 graph/representing-graphs/index.html create mode 100644 graph/shortest-path/index.html create mode 100644 graph/strong-connectivity-and-biconnectivity/index.html create mode 100644 graph/strongly-connected-components/index.html create mode 100644 graph/topological-sort/index.html create mode 100644 graph/tree-traversals/index.html create mode 100644 graph/union-find/index.html create mode 100644 index.html create mode 100644 introduction/index.html create mode 100644 overrides/partials/content.html create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz create mode 100644 static/img/favicon.png create mode 100644 static/img/logo.png create mode 100644 static/javascripts/katex.js create mode 100644 static/stylesheets/main.css diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..4bac7e0 --- /dev/null +++ b/404.html @@ -0,0 +1,586 @@ + + + + + + + + + + + + + + + + + + + Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/algorithms/img/binary_search.png b/algorithms/img/binary_search.png new file mode 100644 index 0000000000000000000000000000000000000000..409349fbba1959b694f3651350bc39fe3f5afa17 GIT binary patch literal 82094 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 Be0u-@ literal 0 HcmV?d00001 diff --git a/algorithms/img/divide_and_conquer.png b/algorithms/img/divide_and_conquer.png new file mode 100644 index 0000000000000000000000000000000000000000..366743a28dc81f14863c3355bd1a76ff0155cbe5 GIT binary patch literal 24061 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 NM^jZ-rB=xr{Xby8=*Iv6 literal 0 HcmV?d00001 diff --git a/algorithms/img/linear_search.png b/algorithms/img/linear_search.png new file mode 100644 index 0000000000000000000000000000000000000000..78a394f7f4fb32640bc5bd742ed60da15ece1f54 GIT binary patch literal 108811 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 Jieybb{ty30&lUgx literal 0 HcmV?d00001 diff --git a/algorithms/img/ternary_search.png b/algorithms/img/ternary_search.png new file mode 100644 index 0000000000000000000000000000000000000000..ea4cc6b2d8403c94ef8e41b417f265d1c6099c0c GIT binary patch literal 33247 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�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 literal 0 HcmV?d00001 diff --git a/algorithms/index.html b/algorithms/index.html new file mode 100644 index 0000000..015b1dc --- /dev/null +++ b/algorithms/index.html @@ -0,0 +1,1596 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Algorithms - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + +

+ + Algorithms + +

+ +
+ + +

Editor: Kadir Emre Oto

+

Reviewers: Muhammed Burak Buğrul, Tahsin Enes Kuru

+

Search Algorithms

+

It may be necessary to determine if an array or solution set contains a specific data, and we call this finding proccess searching. In this article, three most common search algorithms will be discussed: linear search, binary search, and ternary search.

+

This visualization may help you understand how the search algorithms work.

+ +

Simplest search algorithm is linear search, also know as sequential search. In this technique, all elements in the collection of the data is checked one by one, if any element matches, algorithm returns the index; otherwise, it returns \(-1\).

+

Its time complexity is \(\mathcal{O}(N)\).

+
+Example for linear search +
Example for linear search
+
+
1
+2
+3
+4
+5
+6
int linearSearch(int *array, int size, int key) {
+    for (int i = 0; i < size; i++)
+        if (array[i] == key)
+            return i;
+    return -1;
+}
+
+ +

We know linear search is quite a slow algorithm because it compares each element of the set with search key, and there is a high-speed searching technique for sorted data instead of linear search, which is binary search. After each comparison, the algorithm eliminates half of the data using the sorting property.

+

We can also use binary search on increasing functions in the same way.

+

Procedure

+
    +
  1. Compare the key with the middle element of the array,
  2. +
  3. If it is a match, return the index of middle.
  4. +
  5. If the key is bigger than the middle, it means that the key must be in the right side of the middle. We can eliminate the left side.
  6. +
  7. If the key is smaller, it should be on the left side. The right side can be ignored.
  8. +
+

Complexity

+

\[ +\begin{align*} +T(N) &= T\left(\tfrac{N}{2}\right) + \mathcal{O}(1) \\ +T(N) &= \mathcal{O}(\log N) +\end{align*} +\]

+
+Example for binary search +
Example for binary search
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
int binarySearch(int *array, int size, int key) {
+    int left = 0, right = size, mid;
+
+    while (left < right) {
+        mid = (left + right) / 2;
+
+        if (array[mid] >= key)
+            right = mid;
+        else
+            left = mid + 1;
+    }
+    return array[left] == key ? left : -1;
+}
+
+ +

Suppose that we have a unimodal function, \(f(x)\), on an interval \([l, r]\), and we are asked to find the local minimum or the local maximum value of the function according to the behavior of it.

+

There are two types of unimodal functions:

+
    +
  1. +

    The function, \(f(x)\) strictly increases for \(x \leq m\), reaches a global maximum at \(x = m\), and then strictly decreases for \(m \leq x\). There are no other local maxima.

    +
  2. +
  3. +

    The function, \(f(x)\) strictly decreases for \(x \leq m\), reaches a global minimum at \(x = m\), and then strictly increases for \(m \leq x\). There are no other local minima.

    +
  4. +
+

In this document, we will implement the first type of unimodal function, and the second one can be solved using the same logic.

+

Procedure

+
    +
  1. Choose any two points \(m_1\), and \(m_2\) on the interval \([l, r]\), where \(l < m_1 < m_2 < r\).
  2. +
  3. If \(f(m_1) < f(m_2)\), it means the maxima should be in the interval \([m_1, r]\), so we can ignore the interval \([l, m_1]\), move \(l\) to \(m_1\)
  4. +
  5. Otherwise, \(f(m_1) \geq f(m_2)\), the maxima have to be in the interval \([l, m_2]\), move \(r\) to \(m_2\)
  6. +
  7. If \(r - l < \epsilon\), where \(\epsilon\) is a negligible value, stop the algorithm, return \(l\). Otherwise turn to the step 1.
  8. +
+

\(m_1\) and \(m_2\) can be selected by \(m_1 = l + \frac{r-l}{3}\) and \(m_2 = r - \frac{r-l}{3}\) to avoid increasing the time complexity.

+

Complexity

+

\[ +\begin{align*} +T(N) &= T\left(2 \cdot \tfrac{N}{3}\right) + \mathcal{O}(1) \\ +T(N) &= \mathcal{O}(\log N) +\end{align*} +\]

+
+Example for ternary search +
Example for ternary search
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
double f(double x);
+
+double ternarySearch(double left, double right, double eps = 1e-7) {
+    while (right - left > eps) {
+        double mid1 = left + (right - left) / 3;
+        double mid2 = right - (right - left) / 3;
+
+        if (f(mid1) < f(mid2))
+            left = mid1;
+        else
+            right = mid2;
+    }
+    return f(left);
+}
+
+

Sorting Algorithms

+

Sorting algorithms are used to put the elements of an array in a certain order according to the comparison operator. Numerical order or lexicographical orders are the most common ones, and there are a large number of sorting algorithms, but we discuss four of them:

+
    +
  • Insertion Sort
  • +
  • Merge Sort
  • +
  • Quick Sort
  • +
  • Radix Sort
  • +
+

For a better understanding, you are strongly recommended to go into this visualization site after reading the topics.

+

Insertion Sort

+

Think that you are playing a card game and want to sort them before the game. Your sorting strategy is simple: you have already sorted some part and every time you pick up the next card from unsorted part, you insert it into the correct place in sorted part. After you apply this process to all cards, the whole deck would be sorted.

+

This is the basic idea for sorting an array. We assume that the first element of the array is the sorted part, and other elements are in the unsorted part. Now, we choose the leftmost element of the unsorted part, and put it into the sorted part. In this way the left part of the array always remains sorted after every iteration, and when no element is left in the unsorted part, the array will be sorted.

+
1
+2
+3
+4
+5
void insertionSort(int *ar, int size) {
+    for (int i = 1; i < size; i++)
+        for (int j = i - 1; 0 <= j and ar[j] > ar[j + 1]; j--)
+            swap(ar[j], ar[j + 1]);
+}
+
+

Merge Sort

+

Merge Sort is one of the fastest sorting algorithms that uses Divide and Conquer paradigm. The algorithm divides the array into two halves, solves each part recursively using same sorting function and combines them in linear time by selecting the smallest value of the arrays every time.

+

Procedure

+
    +
  1. If the size of the array is 1, it is sorted already, stop the algorithm (base case),
  2. +
  3. Find the middle point of the array, and split it in two,
  4. +
  5. Do the algorithm for these parts separately from the first step,
  6. +
  7. After the two halves got sorted, merge them in linear time and the array will be sorted.
  8. +
+

Complexity

+

\[ +\begin{align*} +T(N) &= T\left(\tfrac{N}{2}\right) + \mathcal{O}(N) \\ +T(N) &= \mathcal{O}(N \cdot \log N) +\end{align*} +\]

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
void mergeSort(int *ar, int size) {
+    if (size <= 1) // base case
+        return;
+
+    mergeSort(ar, size / 2); // divide the array into two almost equal parts
+    mergeSort(ar + size / 2, size - size / 2);
+
+    int index = 0, left = 0, right = size / 2; // merge them
+    int *temp = new int[size];
+
+    while (left < size / 2 or right < size) {
+        if (right == size or (left < size / 2 and ar[left] < ar[right]))
+            temp[index++] = ar[left++];
+        else
+            temp[index++] = ar[right++];
+    }
+    for (int i = 0; i < size; i++)
+        ar[i] = temp[i];
+    delete[] temp;
+}
+
+

Quick Sort

+

Quick Sort is also a Divide and Conquer algorithm. The algorithm chooses an element from the array as a pivot and partitions the array around it. Partitioning is arranging the array that satisfies those: the pivot should be put to its correct place, all smaller values should be placed before the pivot, and all greater values should be placed after the pivot. The partitioning can be done in linear time, and after the partitioning, we can use the same sorting function to solve the left part of the pivot and the right part of the pivot recursively.

+

If the sellected pivot cannot divide the array uniformly after the partitioning, the time complexity can reach \(\mathcal{O}(n ^ 2)\) like insertion sort. To avoid this, the pivot can generally be picked randomly.

+

Procedure

+
    +
  1. If the size of the array is \(1\), it is sorted already, stop the algorithm (base case),
  2. +
  3. Choose a pivot randomly,
  4. +
  5. For all values in the array, collect smaller values in the left of the array and greater values in the right of array,
  6. +
  7. Move the pivot to the correct place,
  8. +
  9. Repeat the same algorithm for the left partition and the right partition.
  10. +
+

Complexity

+

\[ +\begin{align*} +T(N) &= T\left(\tfrac{N}{10}\right) + T\left(9 \cdot \tfrac{N}{10}\right) + \mathcal{O}(N) \\ +T(N) &= \mathcal{O}(N \cdot \log N) +\end{align*} +\]

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
void quickSort(int *ar, int size) {
+    if (size <= 1) // base case
+        return;
+
+    int position = 1; // find the correct place of pivot
+    swap(ar[0], ar[rand() % size]);
+
+    for (int i = 1; i < size; i++)
+        if (ar[0] > ar[i])
+            swap(ar[i], ar[position++]);
+    swap(ar[0], ar[position - 1]);
+
+    quickSort(ar, position - 1);
+    quickSort(ar + position, size - position);
+}
+
+

Radix Sort

+

Quick Sort and Merge Sort are comparison-based sorting algorithms and cannot run better than \(\mathcal{O}(N \log N)\). However, Radix Sort works in linear time (\(\mathcal{O}(N + K)\), where \(K\) is \(\log(\max(ar))\)).

+

Procedure

+
    +
  1. For each digit from the least significant to the most, sort the array using Counting Sort according to corresponding digit. Counting Sort is used for keys between specific range, and it counts the number of elements which have different key values. After counting the number of distict key values, we can determine the position of elements in the array.
  2. +
+

Complexity

+

\[ +\begin{align*} +T(N) &= \mathcal{O}(N) +\end{align*} +\]

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
void radixSort(int *ar, int size, int base = 10) {
+    int *temp = new int[size];
+    int *count = new int[base]();
+
+    // Find the maximum value.
+    int maxx = ar[0];
+    for (int i = 1; i < size; i++) {
+        if (ar[i] > maxx) {
+            maxx = ar[i];
+        }
+    }
+
+    for (int e = 1; maxx / e > 0; e *= base) {
+        memset(count, 0, sizeof(int) * base);
+
+        for (int i = 0; i < size; i++)
+            count[(ar[i] / e) % base]++;
+
+        for (int i = 1; i < base; i++)
+            count[i] += count[i - 1];
+
+        for (int i = size - 1; 0 <= i; i--)
+            temp[--count[(ar[i] / e) % base]] = ar[i];
+
+        for (int i = 0; i < size; i++)
+            ar[i] = temp[i];
+    }
+
+    delete[] temp;
+    delete[] count;
+}
+
+

Quickselect Algorithm

+

Quickselect is a selection algorithm that finds the \(k^{th}\) smallest element in an unordered list. The algorithm is closely related to QuickSort in partitioning stage; however, instead of recurring for both sides, it recurs only for the part that contains the \(k^{th}\) smallest element.

+

Procedure

+
    +
  1. Choose a pivot randomly,
  2. +
  3. For all values in the array, collect smaller values in the left of the array and greater values in the right of the array,
  4. +
  5. Move the pivot to the correct place,
  6. +
  7. If the current position is equal to \(k\), return the value at the position.
  8. +
  9. If the current position is more than \(k\), repeat the same algorithm for the left partition.
  10. +
  11. Else, update \(k\) and repeat the same algorithm for the right partition.
  12. +
+

Complexity

+
    +
  • In average: \(\mathcal{O}(N)\)
  • +
  • Worst-case: \(\mathcal{O}(N^2)\)
  • +
+
+

Note that this algorithm is fast in practice, but has poor worst-case performance, like quicksort. However, it still performs better on average than other algorithms that find the \(k^{th}\) smallest element in \(\mathcal{O}(n)\) in the worst case.

+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
// This function finds the k-th smallest element in arr within size si.
+int QuickSelect(int *arr, int si, int k) {
+    // Check if k is valid and if arr has no less elements than k.
+    if (0 < k && k <= si) {
+        // The quicksort-like partitioning. It is same until we find the index of the pivot.
+        int ind = 0;
+
+        // Get a random pivot to decrease the chance of getting worst-case scenario.
+        swap(arr[si - 1], arr[rand() % si]);
+        for (int j = 0; j < si - 1; j++) {
+            if (arr[j] <= arr[si - 1]) {
+                swap(arr[j], arr[ind]);
+                ind++;
+            }
+        }
+        swap(arr[si - 1], arr[ind]);
+
+        // Now check and recur to appropriate situation.
+        // If the index is equal with k-1 (as our array is 0-indexed) return the value.
+        if (ind == k - 1) {
+            return arr[ind];
+        }
+        // Else check if index is greater than k-1. If it is, recur to the left part.
+        else if (ind > k - 1) {
+            return QuickSelect(arr, ind, k);
+        }
+        // Else, recur to the right part.
+        else {
+            return QuickSelect(arr + ind + 1, si - ind - 1, k - ind - 1);
+        }
+    }
+    // If invalid values is given
+    return INT_MAX;
+}
+
+

Divide and Conquer

+

Divide and Conquer is a well-known paradigm that breaks up the problem into several parts, solves each part independently, and finally combines the solutions to the subproblems into the overall solution. Because each subproblem is solved recursively, they should be the smaller versions of the original problem; and the problem must have a base case to end the recursion.

+

Some example algorithms that use divide and conquer technique:

+
    +
  • Merge Sort
  • +
  • Count Inversions
  • +
  • Finding the Closest Pair of Points
  • +
  • Others
  • +
+
+The Flow of *Divide and Conquer* +
The Flow of Divide and Conquer
+
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf13b9f9d978896599290a74f77d5dbe7d1655c GIT binary patch literal 1870 zcmV-U2eJ5xP)Gc)JR9QMau)O=X#!i9;T z37kk-upj^(fsR36MHs_+1RCI)NNu9}lD0S{B^g8PN?Ww(5|~L#Ng*g{WsqleV}|#l zz8@ri&cTzw_h33bHI+12+kK6WN$h#n5cD8OQt`5kw6p~9H3()bUQ8OS4Q4HTQ=1Ol z_JAocz`fLbT2^{`8n~UAo=#AUOf=SOq4pYkt;XbC&f#7lb$*7=$na!mWCQ`dBQsO0 zLFBSPj*N?#u5&pf2t4XjEGH|=pPQ8xh7tpx;US5Cx_Ju;!O`ya-yF`)b%TEt5>eP1ZX~}sjjA%FJF?h7cX8=b!DZl<6%Cv z*G0uvvU+vmnpLZ2paivG-(cd*y3$hCIcsZcYOGh{$&)A6*XX&kXZd3G8m)G$Zz-LV z^GF3VAW^Mdv!)4OM8EgqRiz~*Cji;uzl2uC9^=8I84vNp;ltJ|q-*uQwGp2ma6cY7 z;`%`!9UXO@fr&Ebapfs34OmS9^u6$)bJxrucutf>`dKPKT%%*d3XlFVKunp9 zasduxjrjs>f8V=D|J=XNZp;_Zy^WgQ$9WDjgY=z@stwiEBm9u5*|34&1Na8BMjjgf3+SHcr`5~>oz1Y?SW^=K z^bTyO6>Gar#P_W2gEMwq)ot3; zREHn~U&Dp0l6YT0&k-wLwYjb?5zGK`W6S2v+K>AM(95m2C20L|3m~rN8dprPr@t)5lsk9Hu*W z?pS990s;Ez=+Rj{x7p``4>+c0G5^pYnB1^!TL=(?HLHZ+HicG{~4F1d^5Awl_2!1jICM-!9eoLhbbT^;yHcefyTAaqRcY zmuctDopPT!%k+}x%lZRKnzykr2}}XfG_ne?nRQO~?%hkzo;@RN{P6o`&mMUWBYMTe z6i8ChtjX&gXl`nvrU>jah)2iNM%JdjqoaeaU%yVn!^70x-flljp6Q5tK}5}&X8&&G zX3fpb3E(!rH=zVI_9Gjl45w@{(ITqngWFe7@9{mX;tO25Z_8 zQHEpI+FkTU#4xu>RkN>b3Tnc3UpWzPXWm#o55GKF09j^Mh~)K7{QqbO_~(@CVq! zS<8954|P8mXN2MRs86xZ&Q4EfM@JB94b=(YGuk)s&^jiSF=t3*oNK3`rD{H`yQ?d; ztE=laAUoZx5?RC8*WKOj`%LXEkgDd>&^Q4M^z`%u0rg-It=hLCVsq!Z%^6eB-OvOT zFZ28TN&cRmgU}Elrnk43)!>Z1FCPL2K$7}gwzIc48NX}#!A1BpJP?#v5wkNprhV** z?Cpalt1oH&{r!o3eSKc&ap)iz2BTn_VV`4>9M^b3;(YY}4>#ML6{~(4mH+?%07*qo IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/javascripts/bundle.c8b220af.min.js b/assets/javascripts/bundle.c8b220af.min.js new file mode 100644 index 0000000..34b23f9 --- /dev/null +++ b/assets/javascripts/bundle.c8b220af.min.js @@ -0,0 +1,16 @@ +"use strict";(()=>{var Wi=Object.create;var gr=Object.defineProperty;var Vi=Object.getOwnPropertyDescriptor;var Di=Object.getOwnPropertyNames,Vt=Object.getOwnPropertySymbols,Ni=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,ao=Object.prototype.propertyIsEnumerable;var io=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,$=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&io(e,r,t[r]);if(Vt)for(var r of Vt(t))ao.call(t,r)&&io(e,r,t[r]);return e};var so=(e,t)=>{var r={};for(var o in e)yr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Vt)for(var o of Vt(e))t.indexOf(o)<0&&ao.call(e,o)&&(r[o]=e[o]);return r};var xr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var zi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Di(t))!yr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Vi(t,n))||o.enumerable});return e};var Lt=(e,t,r)=>(r=e!=null?Wi(Ni(e)):{},zi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var co=(e,t,r)=>new Promise((o,n)=>{var i=p=>{try{s(r.next(p))}catch(c){n(c)}},a=p=>{try{s(r.throw(p))}catch(c){n(c)}},s=p=>p.done?o(p.value):Promise.resolve(p.value).then(i,a);s((r=r.apply(e,t)).next())});var lo=xr((Er,po)=>{(function(e,t){typeof Er=="object"&&typeof po!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(k){return!!(k&&k!==document&&k.nodeName!=="HTML"&&k.nodeName!=="BODY"&&"classList"in k&&"contains"in k.classList)}function p(k){var ft=k.type,qe=k.tagName;return!!(qe==="INPUT"&&a[ft]&&!k.readOnly||qe==="TEXTAREA"&&!k.readOnly||k.isContentEditable)}function c(k){k.classList.contains("focus-visible")||(k.classList.add("focus-visible"),k.setAttribute("data-focus-visible-added",""))}function l(k){k.hasAttribute("data-focus-visible-added")&&(k.classList.remove("focus-visible"),k.removeAttribute("data-focus-visible-added"))}function f(k){k.metaKey||k.altKey||k.ctrlKey||(s(r.activeElement)&&c(r.activeElement),o=!0)}function u(k){o=!1}function d(k){s(k.target)&&(o||p(k.target))&&c(k.target)}function y(k){s(k.target)&&(k.target.classList.contains("focus-visible")||k.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(k.target))}function L(k){document.visibilityState==="hidden"&&(n&&(o=!0),X())}function X(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function ee(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(k){k.target.nodeName&&k.target.nodeName.toLowerCase()==="html"||(o=!1,ee())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),X(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var qr=xr((dy,On)=>{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var $a=/["'&<>]/;On.exports=Pa;function Pa(e){var t=""+e,r=$a.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Rt=="object"&&typeof Yr=="object"?Yr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Rt=="object"?Rt.ClipboardJS=r():t.ClipboardJS=r()})(Rt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Ui}});var a=i(279),s=i.n(a),p=i(370),c=i.n(p),l=i(817),f=i.n(l);function u(D){try{return document.execCommand(D)}catch(A){return!1}}var d=function(A){var M=f()(A);return u("cut"),M},y=d;function L(D){var A=document.documentElement.getAttribute("dir")==="rtl",M=document.createElement("textarea");M.style.fontSize="12pt",M.style.border="0",M.style.padding="0",M.style.margin="0",M.style.position="absolute",M.style[A?"right":"left"]="-9999px";var F=window.pageYOffset||document.documentElement.scrollTop;return M.style.top="".concat(F,"px"),M.setAttribute("readonly",""),M.value=D,M}var X=function(A,M){var F=L(A);M.container.appendChild(F);var V=f()(F);return u("copy"),F.remove(),V},ee=function(A){var M=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},F="";return typeof A=="string"?F=X(A,M):A instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(A==null?void 0:A.type)?F=X(A.value,M):(F=f()(A),u("copy")),F},J=ee;function k(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?k=function(M){return typeof M}:k=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},k(D)}var ft=function(){var A=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=A.action,F=M===void 0?"copy":M,V=A.container,Y=A.target,$e=A.text;if(F!=="copy"&&F!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&k(Y)==="object"&&Y.nodeType===1){if(F==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(F==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if($e)return J($e,{container:V});if(Y)return F==="cut"?y(Y):J(Y,{container:V})},qe=ft;function Fe(D){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(M){return typeof M}:Fe=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},Fe(D)}function ki(D,A){if(!(D instanceof A))throw new TypeError("Cannot call a class as a function")}function no(D,A){for(var M=0;M0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=Fe(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var Y=this;this.listener=c()(V,"click",function($e){return Y.onClick($e)})}},{key:"onClick",value:function(V){var Y=V.delegateTarget||V.currentTarget,$e=this.action(Y)||"copy",Wt=qe({action:$e,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(Wt?"success":"error",{action:$e,text:Wt,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return vr("action",V)}},{key:"defaultTarget",value:function(V){var Y=vr("target",V);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(V){return vr("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(V,Y)}},{key:"cut",value:function(V){return y(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof V=="string"?[V]:V,$e=!!document.queryCommandSupported;return Y.forEach(function(Wt){$e=$e&&!!document.queryCommandSupported(Wt)}),$e}}]),M}(s()),Ui=Fi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,p){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(p))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(l,f,u,d,y){var L=c.apply(this,arguments);return l.addEventListener(u,L,y),{destroy:function(){l.removeEventListener(u,L,y)}}}function p(l,f,u,d,y){return typeof l.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return s(L,f,u,d,y)}))}function c(l,f,u,d){return function(y){y.delegateTarget=a(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=p},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function p(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(y))throw new TypeError("Third argument must be a Function");if(a.node(u))return c(u,d,y);if(a.nodeList(u))return l(u,d,y);if(a.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,y)})}}}function f(u,d,y){return s(document.body,u,d,y)}o.exports=p},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var p=window.getSelection(),c=document.createRange();c.selectNodeContents(i),p.removeAllRanges(),p.addRange(c),a=p.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var p=this.e||(this.e={});return(p[i]||(p[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var p=this;function c(){p.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),p=0,c=s.length;for(p;p0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function N(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],a;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(s){a={error:s}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(a)throw a.error}}return i}function q(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||p(d,L)})},y&&(n[d]=y(n[d])))}function p(d,y){try{c(o[d](y))}catch(L){u(i[0][3],L)}}function c(d){d.value instanceof nt?Promise.resolve(d.value.v).then(l,f):u(i[0][2],d)}function l(d){p("next",d)}function f(d){p("throw",d)}function u(d,y){d(y),i.shift(),i.length&&p(i[0][0],i[0][1])}}function uo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof he=="function"?he(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(a){return new Promise(function(s,p){a=e[i](a),n(s,p,a.done,a.value)})}}function n(i,a,s,p){Promise.resolve(p).then(function(c){i({value:c,done:s})},a)}}function H(e){return typeof e=="function"}function ut(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Nt=ut(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Qe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ue=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=he(a),p=s.next();!p.done;p=s.next()){var c=p.value;c.remove(this)}}catch(L){t={error:L}}finally{try{p&&!p.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var l=this.initialTeardown;if(H(l))try{l()}catch(L){i=L instanceof Nt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=he(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{ho(y)}catch(L){i=i!=null?i:[],L instanceof Nt?i=q(q([],N(i)),N(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Nt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ho(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Qe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Qe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=Ue.EMPTY;function zt(e){return e instanceof Ue||e&&"closed"in e&&H(e.remove)&&H(e.add)&&H(e.unsubscribe)}function ho(e){H(e)?e():e.unsubscribe()}var Pe={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var dt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,a=n.isStopped,s=n.observers;return i||a?Tr:(this.currentObservers=null,s.push(r),new Ue(function(){o.currentObservers=null,Qe(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new j;return r.source=this,r},t.create=function(r,o){return new To(r,o)},t}(j);var To=function(e){oe(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(g);var _r=function(e){oe(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(g);var _t={now:function(){return(_t.delegate||Date).now()},delegate:void 0};var At=function(e){oe(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=_t);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,p=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+p)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),p=0;p0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(gt);var Lo=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(yt);var kr=new Lo(Oo);var Mo=function(e){oe(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=vt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var a=r.actions;o!=null&&o===r._scheduled&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==o&&(vt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(gt);var _o=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o;r?o=r.id:(o=this._scheduled,this._scheduled=void 0);var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(yt);var me=new _o(Mo);var S=new j(function(e){return e.complete()});function Kt(e){return e&&H(e.schedule)}function Hr(e){return e[e.length-1]}function Xe(e){return H(Hr(e))?e.pop():void 0}function ke(e){return Kt(Hr(e))?e.pop():void 0}function Yt(e,t){return typeof Hr(e)=="number"?e.pop():t}var xt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Bt(e){return H(e==null?void 0:e.then)}function Gt(e){return H(e[bt])}function Jt(e){return Symbol.asyncIterator&&H(e==null?void 0:e[Symbol.asyncIterator])}function Xt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Zt=Zi();function er(e){return H(e==null?void 0:e[Zt])}function tr(e){return fo(this,arguments,function(){var r,o,n,i;return Dt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,nt(r.read())];case 3:return o=a.sent(),n=o.value,i=o.done,i?[4,nt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,nt(n)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function rr(e){return H(e==null?void 0:e.getReader)}function U(e){if(e instanceof j)return e;if(e!=null){if(Gt(e))return ea(e);if(xt(e))return ta(e);if(Bt(e))return ra(e);if(Jt(e))return Ao(e);if(er(e))return oa(e);if(rr(e))return na(e)}throw Xt(e)}function ea(e){return new j(function(t){var r=e[bt]();if(H(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ta(e){return new j(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?b(function(n,i){return e(n,i,o)}):le,Te(1),r?Ve(t):Qo(function(){return new nr}))}}function jr(e){return e<=0?function(){return S}:E(function(t,r){var o=[];t.subscribe(T(r,function(n){o.push(n),e=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new g}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,p=s===void 0?!0:s;return function(c){var l,f,u,d=0,y=!1,L=!1,X=function(){f==null||f.unsubscribe(),f=void 0},ee=function(){X(),l=u=void 0,y=L=!1},J=function(){var k=l;ee(),k==null||k.unsubscribe()};return E(function(k,ft){d++,!L&&!y&&X();var qe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!L&&!y&&(f=Ur(J,p))}),qe.subscribe(ft),!l&&d>0&&(l=new at({next:function(Fe){return qe.next(Fe)},error:function(Fe){L=!0,X(),f=Ur(ee,n,Fe),qe.error(Fe)},complete:function(){y=!0,X(),f=Ur(ee,a),qe.complete()}}),U(k).subscribe(l))})(c)}}function Ur(e,t){for(var r=[],o=2;oe.next(document)),e}function P(e,t=document){return Array.from(t.querySelectorAll(e))}function R(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Ie(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var wa=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(_e(1),Q(void 0),m(()=>Ie()||document.body),G(1));function et(e){return wa.pipe(m(t=>e.contains(t)),K())}function Ht(e,t){return C(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?kt(r=>Le(+!r*t)):le,Q(e.matches(":hover"))))}function Jo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Jo(e,r)}function x(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Jo(o,n);return o}function sr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function wt(e){let t=x("script",{src:e});return C(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(v(()=>$r(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),Te(1))))}var Xo=new g,Ta=C(()=>typeof ResizeObserver=="undefined"?wt("https://unpkg.com/resize-observer-polyfill"):I(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>Xo.next(t)))),v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function ce(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return Ta.pipe(w(r=>r.observe(t)),v(r=>Xo.pipe(b(o=>o.target===t),_(()=>r.unobserve(t)))),m(()=>ce(e)),Q(ce(e)))}function Tt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function cr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Zo(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function De(e){return{x:e.offsetLeft,y:e.offsetTop}}function en(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function tn(e){return O(h(window,"load"),h(window,"resize")).pipe(Me(0,me),m(()=>De(e)),Q(De(e)))}function pr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ne(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe(Me(0,me),m(()=>pr(e)),Q(pr(e)))}var rn=new g,Sa=C(()=>I(new IntersectionObserver(e=>{for(let t of e)rn.next(t)},{threshold:0}))).pipe(v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function tt(e){return Sa.pipe(w(t=>t.observe(e)),v(t=>rn.pipe(b(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function on(e,t=16){return Ne(e).pipe(m(({y:r})=>{let o=ce(e),n=Tt(e);return r>=n.height-o.height-t}),K())}var lr={drawer:R("[data-md-toggle=drawer]"),search:R("[data-md-toggle=search]")};function nn(e){return lr[e].checked}function Je(e,t){lr[e].checked!==t&&lr[e].click()}function ze(e){let t=lr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Oa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function La(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function an(){let e=h(window,"keydown").pipe(b(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:nn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),b(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!Oa(o,r)}return!0}),pe());return La().pipe(v(t=>t?S:e))}function ye(){return new URL(location.href)}function lt(e,t=!1){if(B("navigation.instant")&&!t){let r=x("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function sn(){return new g}function cn(){return location.hash.slice(1)}function pn(e){let t=x("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Ma(e){return O(h(window,"hashchange"),e).pipe(m(cn),Q(cn()),b(t=>t.length>0),G(1))}function ln(e){return Ma(e).pipe(m(t=>fe(`[id="${t}"]`)),b(t=>typeof t!="undefined"))}function $t(e){let t=matchMedia(e);return ir(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function mn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function Nr(e,t){return e.pipe(v(r=>r?t():S))}function zr(e,t){return new j(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let a=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+a*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function je(e,t){return zr(e,t).pipe(v(r=>r.text()),m(r=>JSON.parse(r)),G(1))}function fn(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),G(1))}function un(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),G(1))}function dn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function hn(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(dn),Q(dn()))}function bn(){return{width:innerWidth,height:innerHeight}}function vn(){return h(window,"resize",{passive:!0}).pipe(m(bn),Q(bn()))}function gn(){return z([hn(),vn()]).pipe(m(([e,t])=>({offset:e,size:t})),G(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(te("size")),n=z([o,r]).pipe(m(()=>De(e)));return z([r,t,n]).pipe(m(([{height:i},{offset:a,size:s},{x:p,y:c}])=>({offset:{x:a.x-p,y:a.y-c+i},size:s})))}function _a(e){return h(e,"message",t=>t.data)}function Aa(e){let t=new g;return t.subscribe(r=>e.postMessage(r)),t}function yn(e,t=new Worker(e)){let r=_a(t),o=Aa(t),n=new g;n.subscribe(o);let i=o.pipe(Z(),ie(!0));return n.pipe(Z(),Re(r.pipe(W(i))),pe())}var Ca=R("#__config"),St=JSON.parse(Ca.textContent);St.base=`${new URL(St.base,ye())}`;function xe(){return St}function B(e){return St.features.includes(e)}function Ee(e,t){return typeof t!="undefined"?St.translations[e].replace("#",t.toString()):St.translations[e]}function Se(e,t=document){return R(`[data-md-component=${e}]`,t)}function ae(e,t=document){return P(`[data-md-component=${e}]`,t)}function ka(e){let t=R(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>R(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function xn(e){if(!B("announce.dismiss")||!e.childElementCount)return S;if(!e.hidden){let t=R(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return C(()=>{let t=new g;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),ka(e).pipe(w(r=>t.next(r)),_(()=>t.complete()),m(r=>$({ref:e},r)))})}function Ha(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function En(e,t){let r=new g;return r.subscribe(({hidden:o})=>{e.hidden=o}),Ha(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))}function Pt(e,t){return t==="inline"?x("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"})):x("div",{class:"md-tooltip",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"}))}function wn(...e){return x("div",{class:"md-tooltip2",role:"tooltip"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function Tn(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("a",{href:r,class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}else return x("aside",{class:"md-annotation",tabIndex:0},Pt(t),x("span",{class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}function Sn(e){return x("button",{class:"md-clipboard md-icon",title:Ee("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var Ln=Lt(qr());function Qr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(p=>!e.terms[p]).reduce((p,c)=>[...p,x("del",null,(0,Ln.default)(c))," "],[]).slice(0,-1),i=xe(),a=new URL(e.location,i.base);B("search.highlight")&&a.searchParams.set("h",Object.entries(e.terms).filter(([,p])=>p).reduce((p,[c])=>`${p} ${c}`.trim(),""));let{tags:s}=xe();return x("a",{href:`${a}`,class:"md-search-result__link",tabIndex:-1},x("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&x("div",{class:"md-search-result__icon md-icon"}),r>0&&x("h1",null,e.title),r<=0&&x("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&x("nav",{class:"md-tags"},e.tags.map(p=>{let c=s?p in s?`md-tag-icon md-tag--${s[p]}`:"md-tag-icon":"";return x("span",{class:`md-tag ${c}`},p)})),o>0&&n.length>0&&x("p",{class:"md-search-result__terms"},Ee("search.result.term.missing"),": ",...n)))}function Mn(e){let t=e[0].score,r=[...e],o=xe(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),a=r.findIndex(l=>l.scoreQr(l,1)),...p.length?[x("details",{class:"md-search-result__more"},x("summary",{tabIndex:-1},x("div",null,p.length>0&&p.length===1?Ee("search.result.more.one"):Ee("search.result.more.other",p.length))),...p.map(l=>Qr(l,1)))]:[]];return x("li",{class:"md-search-result__item"},c)}function _n(e){return x("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>x("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?sr(r):r)))}function Kr(e){let t=`tabbed-control tabbed-control--${e}`;return x("div",{class:t,hidden:!0},x("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function An(e){return x("div",{class:"md-typeset__scrollwrap"},x("div",{class:"md-typeset__table"},e))}function Ra(e){var o;let t=xe(),r=new URL(`../${e.version}/`,t.base);return x("li",{class:"md-version__item"},x("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&x("span",{class:"md-version__alias"},e.aliases[0])))}function Cn(e,t){var o;let r=xe();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),x("div",{class:"md-version"},x("button",{class:"md-version__current","aria-label":Ee("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&x("span",{class:"md-version__alias"},t.aliases[0])),x("ul",{class:"md-version__list"},e.map(Ra)))}var Ia=0;function ja(e){let t=z([et(e),Ht(e)]).pipe(m(([o,n])=>o||n),K()),r=C(()=>Zo(e)).pipe(ne(Ne),pt(1),He(t),m(()=>en(e)));return t.pipe(Ae(o=>o),v(()=>z([t,r])),m(([o,n])=>({active:o,offset:n})),pe())}function Fa(e,t){let{content$:r,viewport$:o}=t,n=`__tooltip2_${Ia++}`;return C(()=>{let i=new g,a=new _r(!1);i.pipe(Z(),ie(!1)).subscribe(a);let s=a.pipe(kt(c=>Le(+!c*250,kr)),K(),v(c=>c?r:S),w(c=>c.id=n),pe());z([i.pipe(m(({active:c})=>c)),s.pipe(v(c=>Ht(c,250)),Q(!1))]).pipe(m(c=>c.some(l=>l))).subscribe(a);let p=a.pipe(b(c=>c),re(s,o),m(([c,l,{size:f}])=>{let u=e.getBoundingClientRect(),d=u.width/2;if(l.role==="tooltip")return{x:d,y:8+u.height};if(u.y>=f.height/2){let{height:y}=ce(l);return{x:d,y:-16-y}}else return{x:d,y:16+u.height}}));return z([s,i,p]).subscribe(([c,{offset:l},f])=>{c.style.setProperty("--md-tooltip-host-x",`${l.x}px`),c.style.setProperty("--md-tooltip-host-y",`${l.y}px`),c.style.setProperty("--md-tooltip-x",`${f.x}px`),c.style.setProperty("--md-tooltip-y",`${f.y}px`),c.classList.toggle("md-tooltip2--top",f.y<0),c.classList.toggle("md-tooltip2--bottom",f.y>=0)}),a.pipe(b(c=>c),re(s,(c,l)=>l),b(c=>c.role==="tooltip")).subscribe(c=>{let l=ce(R(":scope > *",c));c.style.setProperty("--md-tooltip-width",`${l.width}px`),c.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(K(),ve(me),re(s)).subscribe(([c,l])=>{l.classList.toggle("md-tooltip2--active",c)}),z([a.pipe(b(c=>c)),s]).subscribe(([c,l])=>{l.role==="dialog"?(e.setAttribute("aria-controls",n),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",n)}),a.pipe(b(c=>!c)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),ja(e).pipe(w(c=>i.next(c)),_(()=>i.complete()),m(c=>$({ref:e},c)))})}function mt(e,{viewport$:t},r=document.body){return Fa(e,{content$:new j(o=>{let n=e.title,i=wn(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t})}function Ua(e,t){let r=C(()=>z([tn(e),Ne(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:a,height:s}=ce(e);return{x:o-i.x+a/2,y:n-i.y+s/2}}));return et(e).pipe(v(o=>r.pipe(m(n=>({active:o,offset:n})),Te(+!o||1/0))))}function kn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return C(()=>{let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),tt(e).pipe(W(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),O(i.pipe(b(({active:s})=>s)),i.pipe(_e(250),b(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Me(16,me)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(a),b(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),h(n,"mousedown").pipe(W(a),re(i)).subscribe(([s,{active:p}])=>{var c;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(p){s.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(c=Ie())==null||c.blur()}}),r.pipe(W(a),b(s=>s===o),Ge(125)).subscribe(()=>e.focus()),Ua(e,t).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function Wa(e){return e.tagName==="CODE"?P(".c, .c1, .cm",e):[e]}function Va(e){let t=[];for(let r of Wa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,p]=a;if(typeof p=="undefined"){let c=i.splitText(a.index);i=c.splitText(s.length),t.push(c)}else{i.textContent=s,t.push(i);break}}}}return t}function Hn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,a=new Map;for(let s of Va(t)){let[,p]=s.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${p})`,e)&&(a.set(p,Tn(p,i)),s.replaceWith(a.get(p)))}return a.size===0?S:C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=[];for(let[l,f]of a)c.push([R(".md-typeset",f),R(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(p)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of c)l?Hn(f,u):Hn(u,f)}),O(...[...a].map(([,l])=>kn(l,t,{target$:r}))).pipe(_(()=>s.complete()),pe())})}function $n(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return $n(t)}}function Pn(e,t){return C(()=>{let r=$n(e);return typeof r!="undefined"?fr(r,e,t):S})}var Rn=Lt(Br());var Da=0;function In(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return In(t)}}function Na(e){return ge(e).pipe(m(({width:t})=>({scrollable:Tt(e).width>t})),te("scrollable"))}function jn(e,t){let{matches:r}=matchMedia("(hover)"),o=C(()=>{let n=new g,i=n.pipe(jr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[];if(Rn.default.isSupported()&&(e.closest(".copy")||B("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Da++}`;let l=Sn(c.id);c.insertBefore(l,e),B("content.tooltips")&&a.push(mt(l,{viewport$}))}let s=e.closest(".highlight");if(s instanceof HTMLElement){let c=In(s);if(typeof c!="undefined"&&(s.classList.contains("annotate")||B("content.code.annotate"))){let l=fr(c,e,t);a.push(ge(s).pipe(W(i),m(({width:f,height:u})=>f&&u),K(),v(f=>f?l:S)))}}return P(":scope > span[id]",e).length&&e.classList.add("md-code__content"),Na(e).pipe(w(c=>n.next(c)),_(()=>n.complete()),m(c=>$({ref:e},c)),Re(...a))});return B("content.lazy")?tt(e).pipe(b(n=>n),Te(1),v(()=>o)):o}function za(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),b(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(b(n=>n||!o),w(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Fn(e,t){return C(()=>{let r=new g;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),za(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}var Un=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.flowchartTitleText{fill:var(--md-mermaid-label-fg-color)}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}.classDiagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs marker.marker.composition.class path,defs marker.marker.dependency.class path,defs marker.marker.extension.class path{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs marker.marker.aggregation.class path{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}.statediagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.entityTitleText{fill:var(--md-mermaid-label-fg-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}text:not([class]):last-child{fill:var(--md-mermaid-label-fg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Gr,Qa=0;function Ka(){return typeof mermaid=="undefined"||mermaid instanceof Element?wt("https://unpkg.com/mermaid@11/dist/mermaid.min.js"):I(void 0)}function Wn(e){return e.classList.remove("mermaid"),Gr||(Gr=Ka().pipe(w(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Un,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),G(1))),Gr.subscribe(()=>co(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Qa++}`,r=x("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),a=r.attachShadow({mode:"closed"});a.innerHTML=n,e.replaceWith(r),i==null||i(a)})),Gr.pipe(m(()=>({ref:e})))}var Vn=x("table");function Dn(e){return e.replaceWith(Vn),Vn.replaceWith(An(e)),I({ref:e})}function Ya(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>R(`label[for="${r.id}"]`))))).pipe(Q(R(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Nn(e,{viewport$:t,target$:r}){let o=R(".tabbed-labels",e),n=P(":scope > input",e),i=Kr("prev");e.append(i);let a=Kr("next");return e.append(a),C(()=>{let s=new g,p=s.pipe(Z(),ie(!0));z([s,ge(e),tt(e)]).pipe(W(p),Me(1,me)).subscribe({next([{active:c},l]){let f=De(c),{width:u}=ce(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=pr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),z([Ne(o),ge(o)]).pipe(W(p)).subscribe(([c,l])=>{let f=Tt(o);i.hidden=c.x<16,a.hidden=c.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(a,"click").pipe(m(()=>1))).pipe(W(p)).subscribe(c=>{let{width:l}=ce(o);o.scrollBy({left:l*c,behavior:"smooth"})}),r.pipe(W(p),b(c=>n.includes(c))).subscribe(c=>c.click()),o.classList.add("tabbed-labels--linked");for(let c of n){let l=R(`label[for="${c.id}"]`);l.replaceChildren(x("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(p),b(f=>!(f.metaKey||f.ctrlKey)),w(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return B("content.tabs.link")&&s.pipe(Ce(1),re(t)).subscribe(([{active:c},{offset:l}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of P("[data-tabs]"))for(let L of P(":scope > input",y)){let X=R(`label[for="${L.id}"]`);if(X!==c&&X.innerText.trim()===f){X.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),s.pipe(W(p)).subscribe(()=>{for(let c of P("audio, video",e))c.pause()}),Ya(n).pipe(w(c=>s.next(c)),_(()=>s.complete()),m(c=>$({ref:e},c)))}).pipe(Ke(se))}function zn(e,{viewport$:t,target$:r,print$:o}){return O(...P(".annotate:not(.highlight)",e).map(n=>Pn(n,{target$:r,print$:o})),...P("pre:not(.mermaid) > code",e).map(n=>jn(n,{target$:r,print$:o})),...P("pre.mermaid",e).map(n=>Wn(n)),...P("table:not([class])",e).map(n=>Dn(n)),...P("details",e).map(n=>Fn(n,{target$:r,print$:o})),...P("[data-tabs]",e).map(n=>Nn(n,{viewport$:t,target$:r})),...P("[title]",e).filter(()=>B("content.tooltips")).map(n=>mt(n,{viewport$:t})))}function Ba(e,{alert$:t}){return t.pipe(v(r=>O(I(!0),I(!1).pipe(Ge(2e3))).pipe(m(o=>({message:r,active:o})))))}function qn(e,t){let r=R(".md-typeset",e);return C(()=>{let o=new g;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ba(e,t).pipe(w(n=>o.next(n)),_(()=>o.complete()),m(n=>$({ref:e},n)))})}var Ga=0;function Ja(e,t){document.body.append(e);let{width:r}=ce(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=cr(t),n=typeof o!="undefined"?Ne(o):I({x:0,y:0}),i=O(et(t),Ht(t)).pipe(K());return z([i,n]).pipe(m(([a,s])=>{let{x:p,y:c}=De(t),l=ce(t),f=t.closest("table");return f&&t.parentElement&&(p+=f.offsetLeft+t.parentElement.offsetLeft,c+=f.offsetTop+t.parentElement.offsetTop),{active:a,offset:{x:p-s.x+l.width/2-r/2,y:c-s.y+l.height+8}}}))}function Qn(e){let t=e.title;if(!t.length)return S;let r=`__tooltip_${Ga++}`,o=Pt(r,"inline"),n=R(".md-typeset",o);return n.innerHTML=t,C(()=>{let i=new g;return i.subscribe({next({offset:a}){o.style.setProperty("--md-tooltip-x",`${a.x}px`),o.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(b(({active:a})=>a)),i.pipe(_e(250),b(({active:a})=>!a))).subscribe({next({active:a}){a?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Me(16,me)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?o.style.setProperty("--md-tooltip-0",`${-a}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ja(o,e).pipe(w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))}).pipe(Ke(se))}function Xa({viewport$:e}){if(!B("header.autohide"))return I(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Be(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),K()),o=ze("search");return z([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),K(),v(n=>n?r:I(!1)),Q(!1))}function Kn(e,t){return C(()=>z([ge(e),Xa(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),K((r,o)=>r.height===o.height&&r.hidden===o.hidden),G(1))}function Yn(e,{header$:t,main$:r}){return C(()=>{let o=new g,n=o.pipe(Z(),ie(!0));o.pipe(te("active"),He(t)).subscribe(([{active:a},{hidden:s}])=>{e.classList.toggle("md-header--shadow",a&&!s),e.hidden=s});let i=ue(P("[title]",e)).pipe(b(()=>B("content.tooltips")),ne(a=>Qn(a)));return r.subscribe(o),t.pipe(W(n),m(a=>$({ref:e},a)),Re(i.pipe(W(n))))})}function Za(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ce(e);return{active:o>=n}}),te("active"))}function Bn(e,t){return C(()=>{let r=new g;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?S:Za(o,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))})}function Gn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),K()),n=o.pipe(v(()=>ge(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),te("bottom"))));return z([o,n,t]).pipe(m(([i,{top:a,bottom:s},{offset:{y:p},size:{height:c}}])=>(c=Math.max(0,c-Math.max(0,a-p,i)-Math.max(0,c+p-s)),{offset:a-i,height:c,active:a-i<=p})),K((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function es(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return I(...e).pipe(ne(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),G(1))}function Jn(e){let t=P("input",e),r=x("meta",{name:"theme-color"});document.head.appendChild(r);let o=x("meta",{name:"color-scheme"});document.head.appendChild(o);let n=$t("(prefers-color-scheme: light)");return C(()=>{let i=new g;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),p=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=p.getAttribute("data-md-color-scheme"),a.color.primary=p.getAttribute("data-md-color-primary"),a.color.accent=p.getAttribute("data-md-color-accent")}for(let[s,p]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,p);for(let s=0;sa.key==="Enter"),re(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(m(()=>{let a=Se("header"),s=window.getComputedStyle(a);return o.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(p=>(+p).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(ve(se)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),es(t).pipe(W(n.pipe(Ce(1))),ct(),w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))})}function Xn(e,{progress$:t}){return C(()=>{let r=new g;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(w(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Jr=Lt(Br());function ts(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Zn({alert$:e}){Jr.default.isSupported()&&new j(t=>{new Jr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ts(R(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(w(t=>{t.trigger.focus()}),m(()=>Ee("clipboard.copied"))).subscribe(e)}function ei(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function rs(e,t){let r=new Map;for(let o of P("url",e)){let n=R("loc",o),i=[ei(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let a of P("[rel=alternate]",o)){let s=a.getAttribute("href");s!=null&&i.push(ei(new URL(s),t))}}return r}function ur(e){return un(new URL("sitemap.xml",e)).pipe(m(t=>rs(t,new URL(e))),de(()=>I(new Map)))}function os(e,t){if(!(e.target instanceof Element))return S;let r=e.target.closest("a");if(r===null)return S;if(r.target||e.metaKey||e.ctrlKey)return S;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),I(new URL(r.href))):S}function ti(e){let t=new Map;for(let r of P(":scope > *",e.head))t.set(r.outerHTML,r);return t}function ri(e){for(let t of P("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return I(e)}function ns(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...B("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=ti(document);for(let[o,n]of ti(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Se("container");return We(P("script",r)).pipe(v(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new j(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),S}),Z(),ie(document))}function oi({location$:e,viewport$:t,progress$:r}){let o=xe();if(location.protocol==="file:")return S;let n=ur(o.base);I(document).subscribe(ri);let i=h(document.body,"click").pipe(He(n),v(([p,c])=>os(p,c)),pe()),a=h(window,"popstate").pipe(m(ye),pe());i.pipe(re(t)).subscribe(([p,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",p)}),O(i,a).subscribe(e);let s=e.pipe(te("pathname"),v(p=>fn(p,{progress$:r}).pipe(de(()=>(lt(p,!0),S)))),v(ri),v(ns),pe());return O(s.pipe(re(e,(p,c)=>c)),s.pipe(v(()=>e),te("hash")),e.pipe(K((p,c)=>p.pathname===c.pathname&&p.hash===c.hash),v(()=>i),w(()=>history.back()))).subscribe(p=>{var c,l;history.state!==null||!p.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",pn(p.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(te("offset"),_e(100)).subscribe(({offset:p})=>{history.replaceState(p,"")}),s}var ni=Lt(qr());function ii(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(0,ni.default)(a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function It(e){return e.type===1}function dr(e){return e.type===3}function ai(e,t){let r=yn(e);return O(I(location.protocol!=="file:"),ze("search")).pipe(Ae(o=>o),v(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:B("search.suggest")}}})),r}function si(e){var l;let{selectedVersionSitemap:t,selectedVersionBaseURL:r,currentLocation:o,currentBaseURL:n}=e,i=(l=Xr(n))==null?void 0:l.pathname;if(i===void 0)return;let a=ss(o.pathname,i);if(a===void 0)return;let s=ps(t.keys());if(!t.has(s))return;let p=Xr(a,s);if(!p||!t.has(p.href))return;let c=Xr(a,r);if(c)return c.hash=o.hash,c.search=o.search,c}function Xr(e,t){try{return new URL(e,t)}catch(r){return}}function ss(e,t){if(e.startsWith(t))return e.slice(t.length)}function cs(e,t){let r=Math.min(e.length,t.length),o;for(o=0;oS)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:a,aliases:s})=>a===i||s.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),v(n=>h(document.body,"click").pipe(b(i=>!i.metaKey&&!i.ctrlKey),re(o),v(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&n.has(s.href)){let p=s.href;return!i.target.closest(".md-version")&&n.get(p)===a?S:(i.preventDefault(),I(new URL(p)))}}return S}),v(i=>ur(i).pipe(m(a=>{var s;return(s=si({selectedVersionSitemap:a,selectedVersionBaseURL:i,currentLocation:ye(),currentBaseURL:t.base}))!=null?s:i})))))).subscribe(n=>lt(n,!0)),z([r,o]).subscribe(([n,i])=>{R(".md-header__topic").appendChild(Cn(n,i))}),e.pipe(v(()=>o)).subscribe(n=>{var s;let i=new URL(t.base),a=__md_get("__outdated",sessionStorage,i);if(a===null){a=!0;let p=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(p)||(p=[p]);e:for(let c of p)for(let l of n.aliases.concat(n.version))if(new RegExp(c,"i").test(l)){a=!1;break e}__md_set("__outdated",a,sessionStorage,i)}if(a)for(let p of ae("outdated"))p.hidden=!1})}function ls(e,{worker$:t}){let{searchParams:r}=ye();r.has("q")&&(Je("search",!0),e.value=r.get("q"),e.focus(),ze("search").pipe(Ae(i=>!i)).subscribe(()=>{let i=ye();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=et(e),n=O(t.pipe(Ae(It)),h(e,"keyup"),o).pipe(m(()=>e.value),K());return z([n,o]).pipe(m(([i,a])=>({value:i,focus:a})),G(1))}function pi(e,{worker$:t}){let r=new g,o=r.pipe(Z(),ie(!0));z([t.pipe(Ae(It)),r],(i,a)=>a).pipe(te("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(te("focus")).subscribe(({focus:i})=>{i&&Je("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=R("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),ls(e,{worker$:t}).pipe(w(i=>r.next(i)),_(()=>r.complete()),m(i=>$({ref:e},i)),G(1))}function li(e,{worker$:t,query$:r}){let o=new g,n=on(e.parentElement).pipe(b(Boolean)),i=e.parentElement,a=R(":scope > :first-child",e),s=R(":scope > :last-child",e);ze("search").subscribe(l=>s.setAttribute("role",l?"list":"presentation")),o.pipe(re(r),Wr(t.pipe(Ae(It)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:a.textContent=f.length?Ee("search.result.none"):Ee("search.result.placeholder");break;case 1:a.textContent=Ee("search.result.one");break;default:let u=sr(l.length);a.textContent=Ee("search.result.other",u)}});let p=o.pipe(w(()=>s.innerHTML=""),v(({items:l})=>O(I(...l.slice(0,10)),I(...l.slice(10)).pipe(Be(4),Dr(n),v(([f])=>f)))),m(Mn),pe());return p.subscribe(l=>s.appendChild(l)),p.pipe(ne(l=>{let f=fe("details",l);return typeof f=="undefined"?S:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(b(dr),m(({data:l})=>l)).pipe(w(l=>o.next(l)),_(()=>o.complete()),m(l=>$({ref:e},l)))}function ms(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=ye();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function mi(e,t){let r=new g,o=r.pipe(Z(),ie(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),ms(e,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))}function fi(e,{worker$:t,keyboard$:r}){let o=new g,n=Se("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(ve(se),m(()=>n.value),K());return o.pipe(He(i),m(([{suggest:s},p])=>{let c=p.split(/([\s-]+)/);if(s!=null&&s.length&&c[c.length-1]){let l=s[s.length-1];l.startsWith(c[c.length-1])&&(c[c.length-1]=l)}else c.length=0;return c})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(b(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(b(dr),m(({data:s})=>s)).pipe(w(s=>o.next(s)),_(()=>o.complete()),m(()=>({ref:e})))}function ui(e,{index$:t,keyboard$:r}){let o=xe();try{let n=ai(o.search,t),i=Se("search-query",e),a=Se("search-result",e);h(e,"click").pipe(b(({target:p})=>p instanceof Element&&!!p.closest("a"))).subscribe(()=>Je("search",!1)),r.pipe(b(({mode:p})=>p==="search")).subscribe(p=>{let c=Ie();switch(p.type){case"Enter":if(c===i){let l=new Map;for(let f of P(":first-child [href]",a)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}p.claim()}break;case"Escape":case"Tab":Je("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")i.focus();else{let l=[i,...P(":not(details) > [href], summary, details[open] [href]",a)],f=Math.max(0,(Math.max(0,l.indexOf(c))+l.length+(p.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}p.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(b(({mode:p})=>p==="global")).subscribe(p=>{switch(p.type){case"f":case"s":case"/":i.focus(),i.select(),p.claim();break}});let s=pi(i,{worker$:n});return O(s,li(a,{worker$:n,query$:s})).pipe(Re(...ae("search-share",e).map(p=>mi(p,{query$:s})),...ae("search-suggest",e).map(p=>fi(p,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ye}}function di(e,{index$:t,location$:r}){return z([t,r.pipe(Q(ye()),b(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>ii(o.config)(n.searchParams.get("h"))),m(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let p=s.textContent,c=o(p);c.length>p.length&&n.set(s,c)}for(let[s,p]of n){let{childNodes:c}=x("span",null,p);s.replaceWith(...Array.from(c))}return{ref:e,nodes:n}}))}function fs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return z([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(n,Math.max(0,s-i))-n,{height:a,locked:s>=i+n})),K((i,a)=>i.height===a.height&&i.locked===a.locked))}function Zr(e,o){var n=o,{header$:t}=n,r=so(n,["header$"]);let i=R(".md-sidebar__scrollwrap",e),{y:a}=De(i);return C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=s.pipe(Me(0,me));return c.pipe(re(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ae()).subscribe(()=>{for(let l of P(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2})}}}),ue(P("label[tabindex]",e)).pipe(ne(l=>h(l,"click").pipe(ve(se),m(()=>l),W(p)))).subscribe(l=>{let f=R(`[id="${l.htmlFor}"]`);R(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),fs(e,r).pipe(w(l=>s.next(l)),_(()=>s.complete()),m(l=>$({ref:e},l)))})}function hi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return st(je(`${r}/releases/latest`).pipe(de(()=>S),m(o=>({version:o.tag_name})),Ve({})),je(r).pipe(de(()=>S),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),Ve({}))).pipe(m(([o,n])=>$($({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return je(r).pipe(m(o=>({repositories:o.public_repos})),Ve({}))}}function bi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return st(je(`${r}/releases/permalink/latest`).pipe(de(()=>S),m(({tag_name:o})=>({version:o})),Ve({})),je(r).pipe(de(()=>S),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Ve({}))).pipe(m(([o,n])=>$($({},o),n)))}function vi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return hi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return bi(r,o)}return S}var us;function ds(e){return us||(us=C(()=>{let t=__md_get("__source",sessionStorage);if(t)return I(t);if(ae("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return S}return vi(e.href).pipe(w(o=>__md_set("__source",o,sessionStorage)))}).pipe(de(()=>S),b(t=>Object.keys(t).length>0),m(t=>({facts:t})),G(1)))}function gi(e){let t=R(":scope > :last-child",e);return C(()=>{let r=new g;return r.subscribe(({facts:o})=>{t.appendChild(_n(o)),t.classList.add("md-source__repository--active")}),ds(e).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function hs(e,{viewport$:t,header$:r}){return ge(document.body).pipe(v(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),te("hidden"))}function yi(e,t){return C(()=>{let r=new g;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(B("navigation.tabs.sticky")?I({hidden:!1}):hs(e,t)).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function bs(e,{viewport$:t,header$:r}){let o=new Map,n=P(".md-nav__link",e);for(let s of n){let p=decodeURIComponent(s.hash.substring(1)),c=fe(`[id="${p}"]`);typeof c!="undefined"&&o.set(s,c)}let i=r.pipe(te("height"),m(({height:s})=>{let p=Se("main"),c=R(":scope > :first-child",p);return s+.8*(c.offsetTop-p.offsetTop)}),pe());return ge(document.body).pipe(te("height"),v(s=>C(()=>{let p=[];return I([...o].reduce((c,[l,f])=>{for(;p.length&&o.get(p[p.length-1]).tagName>=f.tagName;)p.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return c.set([...p=[...p,l]].reverse(),u)},new Map))}).pipe(m(p=>new Map([...p].sort(([,c],[,l])=>c-l))),He(i),v(([p,c])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(s.height);for(;f.length;){let[,L]=f[0];if(L-c=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...p]]),K((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([s,p])=>({prev:s.map(([c])=>c),next:p.map(([c])=>c)})),Q({prev:[],next:[]}),Be(2,1),m(([s,p])=>s.prev.length{let i=new g,a=i.pipe(Z(),ie(!0));if(i.subscribe(({prev:s,next:p})=>{for(let[c]of p)c.classList.remove("md-nav__link--passed"),c.classList.remove("md-nav__link--active");for(let[c,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",c===s.length-1)}),B("toc.follow")){let s=O(t.pipe(_e(1),m(()=>{})),t.pipe(_e(250),m(()=>"smooth")));i.pipe(b(({prev:p})=>p.length>0),He(o.pipe(ve(se))),re(s)).subscribe(([[{prev:p}],c])=>{let[l]=p[p.length-1];if(l.offsetHeight){let f=cr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2,behavior:c})}}})}return B("navigation.tracking")&&t.pipe(W(a),te("offset"),_e(250),Ce(1),W(n.pipe(Ce(1))),ct({delay:250}),re(i)).subscribe(([,{prev:s}])=>{let p=ye(),c=s[s.length-1];if(c&&c.length){let[l]=c,{hash:f}=new URL(l.href);p.hash!==f&&(p.hash=f,history.replaceState({},"",`${p}`))}else p.hash="",history.replaceState({},"",`${p}`)}),bs(e,{viewport$:t,header$:r}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function vs(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:a}})=>a),Be(2,1),m(([a,s])=>a>s&&s>0),K()),i=r.pipe(m(({active:a})=>a));return z([i,n]).pipe(m(([a,s])=>!(a&&s)),K(),W(o.pipe(Ce(1))),ie(!0),ct({delay:250}),m(a=>({hidden:a})))}function Ei(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(a),te("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),h(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),vs(e,{viewport$:t,main$:o,target$:n}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))}function wi({document$:e,viewport$:t}){e.pipe(v(()=>P(".md-ellipsis")),ne(r=>tt(r).pipe(W(e.pipe(Ce(1))),b(o=>o),m(()=>r),Te(1))),b(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,B("content.tooltips")?mt(n,{viewport$:t}).pipe(W(e.pipe(Ce(1))),_(()=>n.removeAttribute("title"))):S})).subscribe(),B("content.tooltips")&&e.pipe(v(()=>P(".md-status")),ne(r=>mt(r,{viewport$:t}))).subscribe()}function Ti({document$:e,tablet$:t}){e.pipe(v(()=>P(".md-toggle--indeterminate")),w(r=>{r.indeterminate=!0,r.checked=!1}),ne(r=>h(r,"change").pipe(Vr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),re(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function gs(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Si({document$:e}){e.pipe(v(()=>P("[data-md-scrollfix]")),w(t=>t.removeAttribute("data-md-scrollfix")),b(gs),ne(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Oi({viewport$:e,tablet$:t}){z([ze("search"),t]).pipe(m(([r,o])=>r&&!o),v(r=>I(r).pipe(Ge(r?400:100))),re(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function ys(){return location.protocol==="file:"?wt(`${new URL("search/search_index.js",eo.base)}`).pipe(m(()=>__index),G(1)):je(new URL("search/search_index.json",eo.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ot=Go(),Ft=sn(),Ot=ln(Ft),to=an(),Oe=gn(),hr=$t("(min-width: 960px)"),Mi=$t("(min-width: 1220px)"),_i=mn(),eo=xe(),Ai=document.forms.namedItem("search")?ys():Ye,ro=new g;Zn({alert$:ro});var oo=new g;B("navigation.instant")&&oi({location$:Ft,viewport$:Oe,progress$:oo}).subscribe(ot);var Li;((Li=eo.version)==null?void 0:Li.provider)==="mike"&&ci({document$:ot});O(Ft,Ot).pipe(Ge(125)).subscribe(()=>{Je("drawer",!1),Je("search",!1)});to.pipe(b(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&<(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&<(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});wi({viewport$:Oe,document$:ot});Ti({document$:ot,tablet$:hr});Si({document$:ot});Oi({viewport$:Oe,tablet$:hr});var rt=Kn(Se("header"),{viewport$:Oe}),jt=ot.pipe(m(()=>Se("main")),v(e=>Gn(e,{viewport$:Oe,header$:rt})),G(1)),xs=O(...ae("consent").map(e=>En(e,{target$:Ot})),...ae("dialog").map(e=>qn(e,{alert$:ro})),...ae("palette").map(e=>Jn(e)),...ae("progress").map(e=>Xn(e,{progress$:oo})),...ae("search").map(e=>ui(e,{index$:Ai,keyboard$:to})),...ae("source").map(e=>gi(e))),Es=C(()=>O(...ae("announce").map(e=>xn(e)),...ae("content").map(e=>zn(e,{viewport$:Oe,target$:Ot,print$:_i})),...ae("content").map(e=>B("search.highlight")?di(e,{index$:Ai,location$:Ft}):S),...ae("header").map(e=>Yn(e,{viewport$:Oe,header$:rt,main$:jt})),...ae("header-title").map(e=>Bn(e,{viewport$:Oe,header$:rt})),...ae("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Nr(Mi,()=>Zr(e,{viewport$:Oe,header$:rt,main$:jt})):Nr(hr,()=>Zr(e,{viewport$:Oe,header$:rt,main$:jt}))),...ae("tabs").map(e=>yi(e,{viewport$:Oe,header$:rt})),...ae("toc").map(e=>xi(e,{viewport$:Oe,header$:rt,main$:jt,target$:Ot})),...ae("top").map(e=>Ei(e,{viewport$:Oe,header$:rt,main$:jt,target$:Ot})))),Ci=ot.pipe(v(()=>Es),Re(xs),G(1));Ci.subscribe();window.document$=ot;window.location$=Ft;window.target$=Ot;window.keyboard$=to;window.viewport$=Oe;window.tablet$=hr;window.screen$=Mi;window.print$=_i;window.alert$=ro;window.progress$=oo;window.component$=Ci;})(); +//# sourceMappingURL=bundle.c8b220af.min.js.map + diff --git a/assets/javascripts/bundle.c8b220af.min.js.map b/assets/javascripts/bundle.c8b220af.min.js.map new file mode 100644 index 0000000..d835be5 --- /dev/null +++ b/assets/javascripts/bundle.c8b220af.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/escape-html/index.js", "node_modules/clipboard/dist/clipboard.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/tslib/tslib.es6.mjs", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/BehaviorSubject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/QueueAction.ts", "node_modules/rxjs/src/internal/scheduler/QueueScheduler.ts", "node_modules/rxjs/src/internal/scheduler/queue.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounce.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip2/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/findurl/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*\n * Copyright (c) 2016-2025 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ viewport$, document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\n\nvar extendStatics = function(d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n};\n\nexport function __extends(d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\n\nexport var __assign = function() {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n }\n return __assign.apply(this, arguments);\n}\n\nexport function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nexport function __decorate(decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\n\nexport function __param(paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n}\n\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n var _, done = false;\n for (var i = decorators.length - 1; i >= 0; i--) {\n var context = {};\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n if (kind === \"accessor\") {\n if (result === void 0) continue;\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n if (_ = accept(result.get)) descriptor.get = _;\n if (_ = accept(result.set)) descriptor.set = _;\n if (_ = accept(result.init)) initializers.unshift(_);\n }\n else if (_ = accept(result)) {\n if (kind === \"field\") initializers.unshift(_);\n else descriptor[key] = _;\n }\n }\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\n done = true;\n};\n\nexport function __runInitializers(thisArg, initializers, value) {\n var useValue = arguments.length > 2;\n for (var i = 0; i < initializers.length; i++) {\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n }\n return useValue ? value : void 0;\n};\n\nexport function __propKey(x) {\n return typeof x === \"symbol\" ? x : \"\".concat(x);\n};\n\nexport function __setFunctionName(f, name, prefix) {\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n};\n\nexport function __metadata(metadataKey, metadataValue) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\n\nexport function __awaiter(thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n}\n\nexport function __generator(thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n}\n\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n});\n\nexport function __exportStar(m, o) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\n\nexport function __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\n\nexport function __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o), r, ar = [], e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n }\n catch (error) { e = { error: error }; }\n finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n }\n finally { if (e) throw e.error; }\n }\n return ar;\n}\n\n/** @deprecated */\nexport function __spread() {\n for (var ar = [], i = 0; i < arguments.length; i++)\n ar = ar.concat(__read(arguments[i]));\n return ar;\n}\n\n/** @deprecated */\nexport function __spreadArrays() {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n}\n\nexport function __spreadArray(to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n}\n\nexport function __await(v) {\n return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\n\nexport function __asyncGenerator(thisArg, _arguments, generator) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\n function fulfill(value) { resume(\"next\", value); }\n function reject(value) { resume(\"throw\", value); }\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\n}\n\nexport function __asyncDelegator(o) {\n var i, p;\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\n}\n\nexport function __asyncValues(o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n}\n\nexport function __makeTemplateObject(cooked, raw) {\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\n return cooked;\n};\n\nvar __setModuleDefault = Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n};\n\nexport function __importStar(mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n}\n\nexport function __importDefault(mod) {\n return (mod && mod.__esModule) ? mod : { default: mod };\n}\n\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\n\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n}\n\nexport function __classPrivateFieldIn(state, receiver) {\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\n\nexport function __addDisposableResource(env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n}\n\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nexport function __disposeResources(env) {\n function fail(e) {\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n}\n\nexport default {\n __extends,\n __assign,\n __rest,\n __decorate,\n __param,\n __metadata,\n __awaiter,\n __generator,\n __createBinding,\n __exportStar,\n __values,\n __read,\n __spread,\n __spreadArrays,\n __spreadArray,\n __await,\n __asyncGenerator,\n __asyncDelegator,\n __asyncValues,\n __makeTemplateObject,\n __importStar,\n __importDefault,\n __classPrivateFieldGet,\n __classPrivateFieldSet,\n __classPrivateFieldIn,\n __addDisposableResource,\n __disposeResources,\n};\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n */\nexport class Subscription implements SubscriptionLike {\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param value The `next` value.\n */\n next(value: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param err The `error` exception.\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as ((value: T) => void) | undefined,\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent.\n * @param subscriber The stopped subscriber.\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @param subscribe The function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @param subscribe the subscriber function to be passed to the Observable constructor\n * @return A new observable.\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @param operator the operator defining the operation to take on the observable\n * @return A new observable with the Operator applied.\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param observerOrNext Either an {@link Observer} with some or all callback methods,\n * or the `next` handler that is called for each value emitted from the subscribed Observable.\n * @param error A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param complete A handler for a terminal event resulting from successful completion.\n * @return A subscription reference to the registered handlers.\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next A handler for each value emitted by the observable.\n * @return A promise that either resolves on observable completion or\n * rejects with the handled error.\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @return This instance of the observable.\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n *\n * @return The Observable result of all the operators having been called\n * in the order they were passed in.\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return Observable that this Subject casts to.\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { Subject } from './Subject';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\n\n/**\n * A variant of Subject that requires an initial value and emits its current\n * value whenever it is subscribed to.\n */\nexport class BehaviorSubject extends Subject {\n constructor(private _value: T) {\n super();\n }\n\n get value(): T {\n return this.getValue();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n const subscription = super._subscribe(subscriber);\n !subscription.closed && subscriber.next(this._value);\n return subscription;\n }\n\n getValue(): T {\n const { hasError, thrownError, _value } = this;\n if (hasError) {\n throw thrownError;\n }\n this._throwIfClosed();\n return _value;\n }\n\n next(value: T): void {\n super.next((this._value = value));\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param _bufferSize The size of the buffer to replay on subscription\n * @param _windowTime The amount of time the buffered items will stay buffered\n * @param _timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param state Some contextual data that the `work` function uses when called by the\n * Scheduler.\n * @param delay Time to wait before executing the work, where the time unit is implicit\n * and defined by the Scheduler.\n * @return A subscription in order to be able to unsubscribe the scheduled work.\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param work A function representing a task, or some unit of work to be\n * executed by the Scheduler.\n * @param delay Time to wait before executing the work, where the time unit is\n * implicit and defined by the Scheduler itself.\n * @param state Some contextual data that the `work` function uses when called\n * by the Scheduler.\n * @return A subscription in order to be able to unsubscribe the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { Subscription } from '../Subscription';\nimport { QueueScheduler } from './QueueScheduler';\nimport { SchedulerAction } from '../types';\nimport { TimerHandle } from './timerHandle';\n\nexport class QueueAction extends AsyncAction {\n constructor(protected scheduler: QueueScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (delay > 0) {\n return super.schedule(state, delay);\n }\n this.delay = delay;\n this.state = state;\n this.scheduler.flush(this);\n return this;\n }\n\n public execute(state: T, delay: number): any {\n return delay > 0 || this.closed ? super.execute(state, delay) : this._execute(state, delay);\n }\n\n protected requestAsyncId(scheduler: QueueScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n\n if ((delay != null && delay > 0) || (delay == null && this.delay > 0)) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n\n // Otherwise flush the scheduler starting with this action.\n scheduler.flush(this);\n\n // HACK: In the past, this was returning `void`. However, `void` isn't a valid\n // `TimerHandle`, and generally the return value here isn't really used. So the\n // compromise is to return `0` which is both \"falsy\" and a valid `TimerHandle`,\n // as opposed to refactoring every other instanceo of `requestAsyncId`.\n return 0;\n }\n}\n", "import { AsyncScheduler } from './AsyncScheduler';\n\nexport class QueueScheduler extends AsyncScheduler {\n}\n", "import { QueueAction } from './QueueAction';\nimport { QueueScheduler } from './QueueScheduler';\n\n/**\n *\n * Queue Scheduler\n *\n * Put every next task on a queue, instead of executing it immediately\n *\n * `queue` scheduler, when used with delay, behaves the same as {@link asyncScheduler} scheduler.\n *\n * When used without delay, it schedules given task synchronously - executes it right when\n * it is scheduled. However when called recursively, that is when inside the scheduled task,\n * another task is scheduled with queue scheduler, instead of executing immediately as well,\n * that task will be put on a queue and wait for current one to finish.\n *\n * This means that when you execute task with `queue` scheduler, you are sure it will end\n * before any other task scheduled with that scheduler will start.\n *\n * ## Examples\n * Schedule recursively first, then do something\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(() => {\n * queueScheduler.schedule(() => console.log('second')); // will not happen now, but will be put on a queue\n *\n * console.log('first');\n * });\n *\n * // Logs:\n * // \"first\"\n * // \"second\"\n * ```\n *\n * Reschedule itself recursively\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(function(state) {\n * if (state !== 0) {\n * console.log('before', state);\n * this.schedule(state - 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * console.log('after', state);\n * }\n * }, 0, 3);\n *\n * // In scheduler that runs recursively, you would expect:\n * // \"before\", 3\n * // \"before\", 2\n * // \"before\", 1\n * // \"after\", 1\n * // \"after\", 2\n * // \"after\", 3\n *\n * // But with queue it logs:\n * // \"before\", 3\n * // \"after\", 3\n * // \"before\", 2\n * // \"after\", 2\n * // \"before\", 1\n * // \"after\", 1\n * ```\n */\n\nexport const queueScheduler = new QueueScheduler(QueueAction);\n\n/**\n * @deprecated Renamed to {@link queueScheduler}. Will be removed in v8.\n */\nexport const queue = queueScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && id === scheduler._scheduled && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n let flushId;\n if (action) {\n flushId = action.id;\n } else {\n flushId = this._scheduled;\n this._scheduled = undefined;\n }\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an + +
+
    +
  • Lectures can be found by topics at the navigation bar. The sub topics can be found at those pages. Search bar is also available for finding pages by terms.
  • +
  • In each lecture related problems and training sets from algoleague.com are mentioned. Practicing those is highly recommended.
  • +
+

How to Contribute

+

In order to contribute (adding new lecture, fixing any type of errors) below steps should be followed:

+
    +
  1. Create an issue and briefly explain the purpose of your contribution.
  2. +
  3. Fork the repository with your personal account and apply your changes.
  4. +
  5. Create a pull request to master branch and add the link of pull request to issue.
  6. +
  7. After reviewing your pull request and discussion, your pull request will be merged. Thank you for your contribution!
  8. +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/introduction/index.html b/introduction/index.html new file mode 100644 index 0000000..42ad086 --- /dev/null +++ b/introduction/index.html @@ -0,0 +1,1859 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Introduction - Algorithm Program + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + +

+ + Introduction + +

+ +
+ + +

Editor: Muhammed Burak Buğrul

+

Reviewers: Kadir Emre Oto & Yusuf Hakan Kalaycı

+

Introduction

+

First of all, this is an intensive algorithm programme prepared by inzva, which includes lectures, contests, problem-solvings and a variety of practises. "Competitive Programming" term will be mentioned frequently in this programme, especially for it's community, help in progress in algorithms and data structures etc.

+

Just for a quick cover up we will have a look at what happens when you compile and run a program, basic data types and functions. After that, we will examine C++ Standard Template Library(STL), time complexity and memory space.

+

Command Line

+

A lot of people don't use command line if they can use an alternative. There are powerful IDEs (Integrated Development Environments) and they really make programming easier in some aspects. However, knowing how to use command line is important, especially for competitive programming. Firstly, it gives a low level knowledge and full control; secondly, every computer and environment has command line interface.

+

In this document, you will find only a basic introduction to the command line, which is no more than the basic usage of a file system, compiler, and programs.

+

There are a lot of differences between command line of Windows and Linux. But the differences between those of Mac and Linux are less.

+

Linux and Mac

+

Mac users can use the built-in Terminal. You can find it by searching from Spotlight. Linux users can use gnome-terminal or any other installed one. Again, you can find them by using the built-in search tab.

+

Some basic commands:

+
    +
  • ls list files in current directory. Usage: ls
  • +
  • cd change directory. Usage: cd ~/Desktop
  • +
  • mkdir make a new directory. Usage: mkdir directory_name
  • +
  • mv move command (cut). Usage: mv source_path destination_path
  • +
  • cp copy command. Usage: cp source_path destination_path
  • +
  • rm remove command. Usage: rm file_path
  • +
+

You can read more about the unix command line at: http://linuxcommand.org

+

Compiling and Executing Programs

+

G++

+

G++ is installed in Linux environments but in Mac, you should install Xcode first.

+

You can compile your cpp souce file by typing g++ source.cpp. Default output of this command is a.out.

+

Running Executable Files

+

For Linux and Mac, the command to run a program is ./program_name. If you use default g++ command, the name of your program will be a.out, so you should type ./a.out in order to run it.

+

Closing a Program

+

When you want to kill a program in running step, you can simply hit Control + C.

+

When you want to suspend a program in running step, you can simply hit Control + Z.

+

When you want to register EOF on standart input, you can simply hit Control + D.

+

Input/Output Redirection

+

You can redirect input and output streams of a program by using command line and it is surprisingly easy.

+

Saving Output to a File

+

The only thing you need is > symbol. Just add it at the end of your run command with the output file name: ./a.out > output.txt

+

Note: This redirection process creates output.txt if it doesn't exist; otherwise deletes all content in it, then writes into it. If you want to use > in appending mode you should use >> instead.

+

Reading Input from a File

+

It is almost the same as output file redirection. The symbol is < now. Usage: ./a.out < input.txt

+

This will make your job easier than copying and pasting input to test your program, especially in the contests.

+

Using Both at the Same Time

+

One of the wonderful things about these redirections is that they can be used at the same time. You can simply add both to the end of your run command: ./a.out < input.txt > output.txt

+

pipe

+

Sometimes, you may want to redirect the output of a program to another program as input. You can use the | symbol for this. Usage: ./program1 | ./program2

+

diff

+

As the name denotes, it can check two files line by line if they are the same or not. If not, it outputs different lines. Usage: diff file1.txt file2.txt

+

It is very useful for comparing output of brute force solution and real solution.

+

Structs and Classes

+

In almost every programming language, you can define your own data type. C++ has structs, classes; Python has dictionaries, classes etc. You can think of them as packets that store more than one different data and implement functions at the simplest level. They have a lot more abilities than these two (You can check OOP out).

+

Let us examine a fraction struct written in C++.

+

We need to store two values for a fraction, numerator and denominator.

+
1
+2
+3
struct Fraction {
+  int numerator, denominator;
+};
+
+

This is the simplest definition of a struct. Fraction struct contains two int variables. We call them members. So, Fraction struct has two members called numerator and denominator.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
#include <cstdio>
+
+struct Fraction {
+    int numerator, denominator;
+};
+
+Fraction bigFraction(Fraction a, Fraction b) {
+
+    if( a.numerator * b.denominator > a.denominator * b.numerator )
+        return a;
+
+    return b;
+}
+
+int main() {
+    // Create two Fractions in order to compare them
+    Fraction a, b;
+
+    a.numerator = 15;
+    a.denominator = 20;
+
+    b.numerator = 12;
+    b.denominator = 18;
+
+    // Create a new Fraction in order to store biggest of Fraction a and Fraction b.
+    fraction biggest = bigFraction(a, b);
+
+    printf("The biggest fraction is %d / %d\n", biggest.numerator, biggest.denominator);
+    return 0;
+}
+
+

Let us do the same in Python3:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
class Fraction:
+
+    def __init__(self, numerator, denominator):
+        self.numerator, self.denominator = numerator, denominator
+
+def bigFraction(a, b):
+
+    if a.numerator * b.denominator > a.denominator * b.numerator:
+        return a
+
+    return b
+
+a, b = Fraction(15, 20), Fraction(12, 18)  # Create two Fractions in order to compare them
+biggest = bigFraction(a, b)
+
+print(biggest.numerator, biggest.denominator)
+
+

In the sample codes above, a, b and biggest are called objects of Fraction. Also, the word instance can be used instead of object.

+

The Arrow Operator (C++)

+

Sometimes, usage of struct can change in C++. When you have a pointer to a struct, you should use -> to access its members instead of . operator. If you still want to use . operator, you should do in this way: (*ptr).member. But arrow operator is simpler: ptr->member.

+

Big O Notation

+

When dealing with algorithms or coming up with a solution, we need to calculate how fast our algorithm or solution is. We can calculate this in terms of number of operations. Big \(\mathcal{O}\) notation moves in exactly at this point. Big \(\mathcal{O}\) notation gives an upper limit to these number of operations. The formal definition of Big \(\mathcal{O}\) is [1].

+

Let \(f\) be a real or complex valued function and \(g\) a real valued function, both defined on some unbounded subset of the real positive numbers, such that \(g(x)\) is strictly positive for all large enough values of \(x\). One writes:

+

\[f(x) = \mathcal{O}{(g(x))} \ as\ x \rightarrow \infty\]

+

If and only if for all sufficiently large values of x, the absolute value of \(f(x)\) is at most a positive constant multiple of \(g(x)\). That is, \(f(x)\) = \(\mathcal{O}{(g(x))}\) if and only if there exists a positive real number \(M\) and a real number \(x_0\) such that:

+

\[|f(x)| \leq Mg(x)\ for \ all\ x\ such\ that\ x_0 \leq x\]

+

In many contexts, the assumption that we are interested in the growth rate as the variable \(x\) goes to infinity is left unstated, and one writes more simply that:

+

\[f(x) = \mathcal{O}(g(x))\]

+

Almost every case for competitive programming, basic understanding of Big \(\mathcal{O}\) notation is enough to decide whether to implement a solution or not.

+

Note: Big \(\mathcal{O}\) notation can be used for calculating both the run time complexity and the memory space used.

+

Recursion

+

Recursion occurs when functions repeat themselves in order to create repeated applications or solve a problem by handling smaller situations first. There are thousands of examples in mathematics. One of the simple ones is factorial of \(n\). It can be shown by \(n!\) in mathematics and it gives the product of all positive integers from \(1\) to \(n\), for example, \(4! = 1\cdot 2\cdot 3\cdot 4 = 24\). If we write factorial in a mathematical way, it will be:

+

\[ +\begin{align*} + f(n) &= \begin{cases} + 1 & \text{if $n = 0$\,\, } \\ + n \cdot f(n - 1) & \text{if $n > 0$\,\,} + \end{cases} +\end{align*} +\]

+

The reason why we didn't simply write it as \(f(n) = n \cdot f(n-1)\) is that it doesn't give sufficient information about function. We should know where to end the function calls, otherwise it can call itself infinitely. Ending condition is \(n = 0\) here. We call it base case. Every recursive function needs at least one base case.

+

So if we write every step of \(f(4)\), it will be:

+

\[ +\begin{align*} + 4! + &= 4\cdot f(3) && \text{recursive step} \\ + &= 4\cdot 3\cdot f(2) && \text{recursive step} \\ + &= 4\cdot 3\cdot 2\cdot f(1) && \text{recursive step} \\ + &= 4\cdot 3\cdot 2\cdot 1\cdot f(0) && \text{recursive step} \\ + &= 4\cdot 3\cdot 2\cdot 1\cdot 1 && \text{base case} \\ + &= 24 && \text{arithmetic} +\end{align*} +\]

+

Basically, we can apply this recursive logic into programming:

+
1
+2
+3
+4
+5
+6
int factorial(int n) {
+    int result = 1;
+    for(int i = 1; i <= n; i++)
+        res *= i;
+    return result;
+}
+
+

We can say a function is a recursive if it calls itself. Let us change this iterative factorial function into a recursive one. When you imagine how the recursive code will look like, you will notice it will look like the mathematical one:

+
1
+2
+3
+4
+5
int factorial(int n) {
+    if(n == 0)
+        return 1;
+    return n * factorial(n - 1);
+}
+
+

Note that we didn't forget to put our base case into the recursive function implementation.

+

Time Complexity

+

In case above, it can be seen that both recursive and iterative implementations of factorial function runs in \(\mathcal{O}{(n)}\) time. But this equality doesn't occur always. Let us examine fibonacci function, it is mathematically defines as:

+

\[ +\begin{align*} + f(n) &= \begin{cases} + 1 & \text{if $n = 0$ or $n = 1$\,\, } \\ + f(n - 1) + f(n - 2) & \text{if $n > 1$\,\,} + \end{cases} +\end{align*} +\]

+

We can implement this function with just one for loop:

+
1
+2
+3
+4
+5
+6
+7
+8
+9
int fibonacci(int n) {
+    int result = 1, previous = 1;
+    for (int i = 2; i <= n; i++) {
+        int tmp = result;
+        result += previous;
+        previous = tmp;
+    }
+    return result;
+}
+
+

Again, we can implement recursive one according to the mathematical formula:

+
1
+2
+3
+4
+5
int fibonacci(int n) {
+    if( n == 0 || n == 1 )
+        return 1;
+    return fibonacci(n - 1) + fibonacci(n - 2);
+}
+
+

Let us calculate time complexity of iterative one. There are three basic operations inside a for loop that repeats \(n-2\) times. So time complexity is \(\mathcal{O}(n)\). But what about the recursive one? Let us examine its recursion tree(diagram of function calls) for \(n = 5\) on visualgo.

+

\(f\) function called more than one for some values of n. Actually in every level, number of function calls doubles. So time complexity of the recursive implementation is \(\mathcal{O}{(2^n)}\). It is far away worse than the iterative one. Recursive one can be optimized by techniques like memoization, but it is another topic to learn in further weeks.

+

Mutual Recursion

+

Mutual recursion occurs when functions call each other. For example function f calls another function g, which also somehow calls f again.

+

Note: When using mutual recursions in C++, don't forget to declare one of the functions so that the other function can know first one from its' prototype.

+

Note 2: You can chain more than two functions and it will be still a mutual recursion.

+

Enumeration and Brute-Force

+

Enumeration is numbering method on a set.

+

For example, permutation is one of enumeration techniques. First permutation of numbers in range \(1\) and \(n\) is:

+

\[1, 2, 3... n-1, n\]

+

And second one is:

+

\[1, 2, 3... n, n-1\]

+

Finally, the last one is:

+

\[n, n-1... 3, 2, 1\]

+

Additionally, we can try to enumerate all possible distributions of \(n\) elements into 3 different sets. An example of a distribution of 5 elements can be represented as:

+

\[1, 1, 2, 1, 3\]

+

In this distribution the first, the second and the fourth elements goes into the first set; third element goes into second set and the last element goes into the third set.

+

Enumerations can be done with recursive functions easily. We will provide example implementations of 3-set one. But before examining recursive implementation, let us try to implement iterative one:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
#include <cstdio>
+
+int main(){
+
+    for( int i=1 ; i<=3 ; i++ )
+        for( int j=1 ; j<=3 ; j++ )
+            for( int k=1 ; k<=3 ; k++ )
+                for( int l=1 ; l<=3 ; l++ )
+                    for( int m=1 ; m<=3 ; m++ )
+                        printf("%d %d %d %d %d\n", i, j, k, l, m);
+
+    return 0;
+}
+
+

It will print all possible distributions of 5 elements into 3 sets. But what if we had 6 elements? Yes, we should have added another for loop. What if we had \(n\) elements? We can not add infinite number of for loops. But we can apply same logic with recursive functions easily:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
#include <cstdio>
+
+int ar[100];
+
+void enumerate( int element, int n ){
+
+    if( element > n ){ // Base case
+
+        for( int i=1 ; i<=n ; i++ )
+            printf("%d ", ar[i]);
+
+        printf("\n");
+        return;
+    }
+
+    for( int i=1 ; i<=3 ; i++ ){
+        ar[element] = i;
+        enumerate(element + 1, n);
+    }
+}
+
+int main(){
+    enumerate(1, 5);
+    return 0;
+}
+
+

Brute-Force is trying all cases in order to achieve something(searching best, shortest, cheapest etc.).

+

One of the simplest examples of brute-forces approaches is primality checking. We know that for a prime \(P\) there is no positive integer in range \([2, P-1]\) that evenly divides \(P\). We can simply check all integers in this range to decide if it is prime:

+
1
+2
+3
+4
+5
+6
bool isPrime(int N) {
+    for( int i=2 ; i<N ; i++ )
+        if( N % i == 0 )
+            return false;
+    return true;
+}
+
+

It is a simple function, but its' time complexity is \(\mathcal{O}(N)\). Instead we can benefit from the fact if there is a positive integer \(x\) that evenly divides \(N\), there is a positive integer \(\frac{N}{x}\) as well. As we know this fact, we can only check the integer in range \([2, \sqrt{N}]\):

+
1
+2
+3
+4
+5
+6
bool isPrime(int N) {
+    for( int i=2 ; i*i <= N ; i++ )
+        if( N % i == 0 )
+            return false;
+    return true;
+}
+
+

Now, its' time complexity is \(\mathcal{O}{(\sqrt{N})}\). It is far away better than \(\mathcal{O}{(N)}\).

+

Built-In Data Structures and Functions

+

There is no need to reinvent the wheel. Every language has its' own built in data structures, functions etc. After this point, the document will be C++ centered. But Python alternatives will be given.

+

The C++ Standard Template Library (STL)

+

The STL is a well known library for C++ that includes variety of data structures and algorithms.

+

Note: Third party libraries generally not allowed in contests.

+

Pairs

+

C++: Sometimes you may need to store two elements for an object. We can do this by creating a struct/class or two dimensional array. They will all work well but using pairs will be much more easier. You can think of pair as a class that has two variables named first and second. That's all for the basic. The good part is, you can decide their types(int, double, your own struct/class etc.). An example for pairs in C++:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
#include <iostream>
+
+using namespace std;
+
+int main(){
+
+    pair<int, int> p(1, 2);
+    pair<int, string> p2;
+
+    p2.first = 3;
+    p2.second = "Hey there!";
+
+    pair<pair<int, string>, string> nested;
+
+    nested.first = p2;
+    nested.second = "This is a nested one";
+
+    cout << "Info of p -> " << p.first << " " << p.second << endl;
+    cout << "Info of p2 -> " << p2.first << " " << p2.second << endl;
+    cout << "Info of nested -> " << nested.first.first << " " << nested.first.second
+            << " " << nested.second << endl;
+
+    return 0;
+}
+
+

Python: You can simply create a tuple or an array:

+
1
+2
+3
+4
+5
+6
+7
+8
p = (1, 2)
+p2 = [1, "Hey there!"]
+nested = ((3, "inner?"), "outer", "this is a tuple you can add more")
+
+p2[0] = 3
+# nested[0] = "don't"  # In python you can't change tuples, but you can change arrays
+
+print(p, p2, nested)
+
+

Vectors

+

C++: When using array, we should decide its size. What if we don't have to do this, what if we could add elements into it without considering the current size? Well, all these ideas take us to vectors.

+

C++ has this structure. Its name is vector. It is a dynamic array but you don't have to think about its size. You can simply add elements into it. Like pairs, you can use it with any type (int, double, another vector, your struct/class etc.). Usage of a vector is very similar to classic array:

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
#include <iostream>
+#include <vector>
+
+using namespace std;
+
+int main(){
+
+    vector<int> ar;
+
+    for( int i=0 ; i<10 ; i++ )
+        ar.push_back(i);
+
+    for( int i=0 ; i<(int)ar.size() ; i++ )
+        cout << ar[i] << " ";
+
+    cout << endl;
+    return 0;
+}
+
+

Python: Python lists already behave like vectors:

+
1
+2
+3
+4
+5
+6
ar = []
+
+for i in range(10):
+    ar.append(i)
+
+print(ar)
+
+

Stacks, Queues, and Deques

+

C++: They are no different than stack, queue and deque we already know. It provides the implementation, you can simply include the libraries and use them. See queue, stack, deque.

+

Priority Queues

+

It is basically a built-in heap structure. You can add an element in \(\mathcal{O}(logN)\) time, get the first item in \(O(logN)\) time. The first item will be decided according to your choice of priority. This priority can be magnitude of value, enterence time etc.

+

C++: The different thing for priority queue is you should add #include <queue>, not <priority_queue>. You can find samples here. Again, you can define a priority queue with any type you want.

+

Note: Default priority_queue prioritizes elements by highest value first. Here is three ways of defining priority.

+

Python: You can use heapq in python.

+

Sets and Maps

+

C++: Now that we mentioned binary trees (heap above), we can continue on built-in self balanced binary trees. Sets are key collections, and maps are key-value collections. Sets are useful when you want to add/remove elements in \(\mathcal{O}(logN)\) time and also check existence of an item(key) in \(O(logN)\) time. Maps basically do the same but you can change value associated to a key without changing the position of the key in the tree. You can check c++ references for set and map. You can define them with any type you want. If you want to use them with your own struct/class, you must implement a compare function.

+

Python: You can use dictionaries for map and sets for set in python without importing any other libraries.

+

Iterators

+

C++: You can use iterators for every built-in data structure in C++ for pointing their objects.

+

Python: You can iterate through any iterable in python by using in. You can check this example.

+

Sorting

+

C++: In almost every language, there is a built-in sort function. C++ has one as well. It runs in \(\mathcal{O}(N log N)\) time. You can pass your own compare function into sort function of C++.

+

Python: You can use sort function for any list or list like collection in order to sort them or if you don't want to change the original collection, you can use sorted() function instead. You can pass your own compare function into sort function of python by using key variable.

+

Suggested Readings

+

C++

+ +

Python

+ +

References

+
    +
  1. Landau, Edmund (1909). Handbuch der Lehre von der Verteilung der Primzahlen [Handbook on the theory of the distribution of the primes] (in German). Leipzig: B. G. Teubner. p. 31.
  2. +
+ + + + +
+
+ + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/overrides/partials/content.html b/overrides/partials/content.html new file mode 100644 index 0000000..0472270 --- /dev/null +++ b/overrides/partials/content.html @@ -0,0 +1,24 @@ + +

+ {% if page.meta.title %} + {{ page.meta.title }} + {% else %} + {{ page.title }} + {% endif %} +

+ +
+ + +{{ page.content }} + + +{% if page.meta.editors|length or page.meta.reviewers|length %} +
+ {% if page.meta.editors|length %} +

Editors: {{page.meta.editors|join(", ")}}

+ {% endif %} + {% if page.meta.reviewers|length %} +

Reviewers: {{page.meta.reviewers|join(", ")}}

+ {% endif %} +{% endif %} \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..3634b7a --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Algorithm Program","text":"

Algoritm Program contains lectures about algorithms and data structures which are prepared by inzva community, aimed at teaching advanced knowledge of algorithms to university students, spreading algorithmic thinking and providing training which will help them in international contests as well as in their professional lives.

There is also a video playlist in Turkish about some of the algorithms and data structures in YouTube:

"},{"location":"#how-to-use-this-site","title":"How to Use This Site","text":"
  • Lectures can be found by topics at the navigation bar. The sub topics can be found at those pages. Search bar is also available for finding pages by terms.
  • In each lecture related problems and training sets from algoleague.com are mentioned. Practicing those is highly recommended.
"},{"location":"#how-to-contribute","title":"How to Contribute","text":"

In order to contribute (adding new lecture, fixing any type of errors) below steps should be followed:

  1. Create an issue and briefly explain the purpose of your contribution.
  2. Fork the repository with your personal account and apply your changes.
  3. Create a pull request to master branch and add the link of pull request to issue.
  4. After reviewing your pull request and discussion, your pull request will be merged. Thank you for your contribution!
"},{"location":"algorithms/","title":"Algorithms","text":"

Editor: Kadir Emre Oto

Reviewers: Muhammed Burak Bu\u011frul, Tahsin Enes Kuru

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#search-algorithms","title":"Search Algorithms","text":"

It may be necessary to determine if an array or solution set contains a specific data, and we call this finding proccess searching. In this article, three most common search algorithms will be discussed: linear search, binary search, and ternary search.

This visualization may help you understand how the search algorithms work.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#linear-search","title":"Linear Search","text":"

Simplest search algorithm is linear search, also know as sequential search. In this technique, all elements in the collection of the data is checked one by one, if any element matches, algorithm returns the index; otherwise, it returns \\(-1\\).

Its time complexity is \\(\\mathcal{O}(N)\\).

Example for linear search
int linearSearch(int *array, int size, int key) {\n    for (int i = 0; i < size; i++)\n        if (array[i] == key)\n            return i;\n    return -1;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#binary-search","title":"Binary Search","text":"

We know linear search is quite a slow algorithm because it compares each element of the set with search key, and there is a high-speed searching technique for sorted data instead of linear search, which is binary search. After each comparison, the algorithm eliminates half of the data using the sorting property.

We can also use binary search on increasing functions in the same way.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure","title":"Procedure","text":"
  1. Compare the key with the middle element of the array,
  2. If it is a match, return the index of middle.
  3. If the key is bigger than the middle, it means that the key must be in the right side of the middle. We can eliminate the left side.
  4. If the key is smaller, it should be on the left side. The right side can be ignored.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= T\\left(\\tfrac{N}{2}\\right) + \\mathcal{O}(1) \\\\ T(N) &= \\mathcal{O}(\\log N) \\end{align*} \\]

Example for binary search
int binarySearch(int *array, int size, int key) {\n    int left = 0, right = size, mid;\n\n    while (left < right) {\n        mid = (left + right) / 2;\n\n        if (array[mid] >= key)\n            right = mid;\n        else\n            left = mid + 1;\n    }\n    return array[left] == key ? left : -1;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#ternary-search","title":"Ternary Search","text":"

Suppose that we have a unimodal function, \\(f(x)\\), on an interval \\([l, r]\\), and we are asked to find the local minimum or the local maximum value of the function according to the behavior of it.

There are two types of unimodal functions:

  1. The function, \\(f(x)\\) strictly increases for \\(x \\leq m\\), reaches a global maximum at \\(x = m\\), and then strictly decreases for \\(m \\leq x\\). There are no other local maxima.

  2. The function, \\(f(x)\\) strictly decreases for \\(x \\leq m\\), reaches a global minimum at \\(x = m\\), and then strictly increases for \\(m \\leq x\\). There are no other local minima.

In this document, we will implement the first type of unimodal function, and the second one can be solved using the same logic.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_1","title":"Procedure","text":"
  1. Choose any two points \\(m_1\\), and \\(m_2\\) on the interval \\([l, r]\\), where \\(l < m_1 < m_2 < r\\).
  2. If \\(f(m_1) < f(m_2)\\), it means the maxima should be in the interval \\([m_1, r]\\), so we can ignore the interval \\([l, m_1]\\), move \\(l\\) to \\(m_1\\)
  3. Otherwise, \\(f(m_1) \\geq f(m_2)\\), the maxima have to be in the interval \\([l, m_2]\\), move \\(r\\) to \\(m_2\\)
  4. If \\(r - l < \\epsilon\\), where \\(\\epsilon\\) is a negligible value, stop the algorithm, return \\(l\\). Otherwise turn to the step 1.

\\(m_1\\) and \\(m_2\\) can be selected by \\(m_1 = l + \\frac{r-l}{3}\\) and \\(m_2 = r - \\frac{r-l}{3}\\) to avoid increasing the time complexity.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_1","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= T\\left(2 \\cdot \\tfrac{N}{3}\\right) + \\mathcal{O}(1) \\\\ T(N) &= \\mathcal{O}(\\log N) \\end{align*} \\]

Example for ternary search
double f(double x);\n\ndouble ternarySearch(double left, double right, double eps = 1e-7) {\n    while (right - left > eps) {\n        double mid1 = left + (right - left) / 3;\n        double mid2 = right - (right - left) / 3;\n\n        if (f(mid1) < f(mid2))\n            left = mid1;\n        else\n            right = mid2;\n    }\n    return f(left);\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#sorting-algorithms","title":"Sorting Algorithms","text":"

Sorting algorithms are used to put the elements of an array in a certain order according to the comparison operator. Numerical order or lexicographical orders are the most common ones, and there are a large number of sorting algorithms, but we discuss four of them:

  • Insertion Sort
  • Merge Sort
  • Quick Sort
  • Radix Sort

For a better understanding, you are strongly recommended to go into this visualization site after reading the topics.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#insertion-sort","title":"Insertion Sort","text":"

Think that you are playing a card game and want to sort them before the game. Your sorting strategy is simple: you have already sorted some part and every time you pick up the next card from unsorted part, you insert it into the correct place in sorted part. After you apply this process to all cards, the whole deck would be sorted.

This is the basic idea for sorting an array. We assume that the first element of the array is the sorted part, and other elements are in the unsorted part. Now, we choose the leftmost element of the unsorted part, and put it into the sorted part. In this way the left part of the array always remains sorted after every iteration, and when no element is left in the unsorted part, the array will be sorted.

void insertionSort(int *ar, int size) {\n    for (int i = 1; i < size; i++)\n        for (int j = i - 1; 0 <= j and ar[j] > ar[j + 1]; j--)\n            swap(ar[j], ar[j + 1]);\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#merge-sort","title":"Merge Sort","text":"

Merge Sort is one of the fastest sorting algorithms that uses Divide and Conquer paradigm. The algorithm divides the array into two halves, solves each part recursively using same sorting function and combines them in linear time by selecting the smallest value of the arrays every time.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_2","title":"Procedure","text":"
  1. If the size of the array is 1, it is sorted already, stop the algorithm (base case),
  2. Find the middle point of the array, and split it in two,
  3. Do the algorithm for these parts separately from the first step,
  4. After the two halves got sorted, merge them in linear time and the array will be sorted.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_2","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= T\\left(\\tfrac{N}{2}\\right) + \\mathcal{O}(N) \\\\ T(N) &= \\mathcal{O}(N \\cdot \\log N) \\end{align*} \\]

void mergeSort(int *ar, int size) {\n    if (size <= 1) // base case\n        return;\n\n    mergeSort(ar, size / 2); // divide the array into two almost equal parts\n    mergeSort(ar + size / 2, size - size / 2);\n\n    int index = 0, left = 0, right = size / 2; // merge them\n    int *temp = new int[size];\n\n    while (left < size / 2 or right < size) {\n        if (right == size or (left < size / 2 and ar[left] < ar[right]))\n            temp[index++] = ar[left++];\n        else\n            temp[index++] = ar[right++];\n    }\n    for (int i = 0; i < size; i++)\n        ar[i] = temp[i];\n    delete[] temp;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#quick-sort","title":"Quick Sort","text":"

Quick Sort is also a Divide and Conquer algorithm. The algorithm chooses an element from the array as a pivot and partitions the array around it. Partitioning is arranging the array that satisfies those: the pivot should be put to its correct place, all smaller values should be placed before the pivot, and all greater values should be placed after the pivot. The partitioning can be done in linear time, and after the partitioning, we can use the same sorting function to solve the left part of the pivot and the right part of the pivot recursively.

If the sellected pivot cannot divide the array uniformly after the partitioning, the time complexity can reach \\(\\mathcal{O}(n ^ 2)\\) like insertion sort. To avoid this, the pivot can generally be picked randomly.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_3","title":"Procedure","text":"
  1. If the size of the array is \\(1\\), it is sorted already, stop the algorithm (base case),
  2. Choose a pivot randomly,
  3. For all values in the array, collect smaller values in the left of the array and greater values in the right of array,
  4. Move the pivot to the correct place,
  5. Repeat the same algorithm for the left partition and the right partition.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_3","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= T\\left(\\tfrac{N}{10}\\right) + T\\left(9 \\cdot \\tfrac{N}{10}\\right) + \\mathcal{O}(N) \\\\ T(N) &= \\mathcal{O}(N \\cdot \\log N) \\end{align*} \\]

void quickSort(int *ar, int size) {\n    if (size <= 1) // base case\n        return;\n\n    int position = 1; // find the correct place of pivot\n    swap(ar[0], ar[rand() % size]);\n\n    for (int i = 1; i < size; i++)\n        if (ar[0] > ar[i])\n            swap(ar[i], ar[position++]);\n    swap(ar[0], ar[position - 1]);\n\n    quickSort(ar, position - 1);\n    quickSort(ar + position, size - position);\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#radix-sort","title":"Radix Sort","text":"

Quick Sort and Merge Sort are comparison-based sorting algorithms and cannot run better than \\(\\mathcal{O}(N \\log N)\\). However, Radix Sort works in linear time (\\(\\mathcal{O}(N + K)\\), where \\(K\\) is \\(\\log(\\max(ar))\\)).

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_4","title":"Procedure","text":"
  1. For each digit from the least significant to the most, sort the array using Counting Sort according to corresponding digit. Counting Sort is used for keys between specific range, and it counts the number of elements which have different key values. After counting the number of distict key values, we can determine the position of elements in the array.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_4","title":"Complexity","text":"

\\[ \\begin{align*} T(N) &= \\mathcal{O}(N) \\end{align*} \\]

void radixSort(int *ar, int size, int base = 10) {\n    int *temp = new int[size];\n    int *count = new int[base]();\n\n    // Find the maximum value.\n    int maxx = ar[0];\n    for (int i = 1; i < size; i++) {\n        if (ar[i] > maxx) {\n            maxx = ar[i];\n        }\n    }\n\n    for (int e = 1; maxx / e > 0; e *= base) {\n        memset(count, 0, sizeof(int) * base);\n\n        for (int i = 0; i < size; i++)\n            count[(ar[i] / e) % base]++;\n\n        for (int i = 1; i < base; i++)\n            count[i] += count[i - 1];\n\n        for (int i = size - 1; 0 <= i; i--)\n            temp[--count[(ar[i] / e) % base]] = ar[i];\n\n        for (int i = 0; i < size; i++)\n            ar[i] = temp[i];\n    }\n\n    delete[] temp;\n    delete[] count;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#quickselect-algorithm","title":"Quickselect Algorithm","text":"

Quickselect is a selection algorithm that finds the \\(k^{th}\\) smallest element in an unordered list. The algorithm is closely related to QuickSort in partitioning stage; however, instead of recurring for both sides, it recurs only for the part that contains the \\(k^{th}\\) smallest element.

","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#procedure_5","title":"Procedure","text":"
  1. Choose a pivot randomly,
  2. For all values in the array, collect smaller values in the left of the array and greater values in the right of the array,
  3. Move the pivot to the correct place,
  4. If the current position is equal to \\(k\\), return the value at the position.
  5. If the current position is more than \\(k\\), repeat the same algorithm for the left partition.
  6. Else, update \\(k\\) and repeat the same algorithm for the right partition.
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#complexity_5","title":"Complexity","text":"
  • In average: \\(\\mathcal{O}(N)\\)
  • Worst-case: \\(\\mathcal{O}(N^2)\\)

Note that this algorithm is fast in practice, but has poor worst-case performance, like quicksort. However, it still performs better on average than other algorithms that find the \\(k^{th}\\) smallest element in \\(\\mathcal{O}(n)\\) in the worst case.

// This function finds the k-th smallest element in arr within size si.\nint QuickSelect(int *arr, int si, int k) {\n    // Check if k is valid and if arr has no less elements than k.\n    if (0 < k && k <= si) {\n        // The quicksort-like partitioning. It is same until we find the index of the pivot.\n        int ind = 0;\n\n        // Get a random pivot to decrease the chance of getting worst-case scenario.\n        swap(arr[si - 1], arr[rand() % si]);\n        for (int j = 0; j < si - 1; j++) {\n            if (arr[j] <= arr[si - 1]) {\n                swap(arr[j], arr[ind]);\n                ind++;\n            }\n        }\n        swap(arr[si - 1], arr[ind]);\n\n        // Now check and recur to appropriate situation.\n        // If the index is equal with k-1 (as our array is 0-indexed) return the value.\n        if (ind == k - 1) {\n            return arr[ind];\n        }\n        // Else check if index is greater than k-1. If it is, recur to the left part.\n        else if (ind > k - 1) {\n            return QuickSelect(arr, ind, k);\n        }\n        // Else, recur to the right part.\n        else {\n            return QuickSelect(arr + ind + 1, si - ind - 1, k - ind - 1);\n        }\n    }\n    // If invalid values is given\n    return INT_MAX;\n}\n
","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"algorithms/#divide-and-conquer","title":"Divide and Conquer","text":"

Divide and Conquer is a well-known paradigm that breaks up the problem into several parts, solves each part independently, and finally combines the solutions to the subproblems into the overall solution. Because each subproblem is solved recursively, they should be the smaller versions of the original problem; and the problem must have a base case to end the recursion.

Some example algorithms that use divide and conquer technique:

  • Merge Sort
  • Count Inversions
  • Finding the Closest Pair of Points
  • Others
The Flow of Divide and Conquer","tags":["Algorithms","Linear Search","Binary Search","Ternary Search","Sorting Algorithms","Insertion Sort","Merge Sort","Quick Sort","Radix Sort","Quickselect Algorithm","Divide and Conquer"]},{"location":"data-structures/","title":"Data Structures","text":"

Editor: Tahsin Enes Kuru

Reviewers: Baha Eren Yald\u0131z, Burak Bu\u011frul

Contributors: Kerim Kochekov

","tags":["Data Structures"]},{"location":"data-structures/#giris","title":"Giri\u015f","text":"

Bilgisayar biliminde veri yap\u0131lar\u0131, belirli bir eleman k\u00fcmesi \u00fczerinde verimli bir \u015feklide bilgi edinmemize ayn\u0131 zamanda bu elemanlar \u00fczerinde de\u011fi\u015fiklikler yapabilmemize olanak sa\u011flayan yap\u0131lard\u0131r. \u00c7al\u0131\u015fma prensipleri genellikle elemanlar\u0131n de\u011ferlerini belirli bir kurala g\u00f6re saklamak daha sonra bu yap\u0131lar\u0131 kullanarak elemanlar hakk\u0131nda sorulara (mesela, bir dizinin belirli bir aral\u0131\u011f\u0131ndaki en k\u00fc\u00e7\u00fck say\u0131y\u0131 bulmak gibi) cevap aramakt\u0131r.

","tags":["Data Structures"]},{"location":"data-structures/#dinamik-veri-yaplar","title":"Dinamik Veri Yap\u0131lar\u0131","text":"","tags":["Data Structures"]},{"location":"data-structures/#linked-list","title":"Linked List","text":"","tags":["Data Structures"]},{"location":"data-structures/#stack","title":"Stack","text":"","tags":["Data Structures"]},{"location":"data-structures/#queue","title":"Queue","text":"","tags":["Data Structures"]},{"location":"data-structures/#deque","title":"Deque","text":"","tags":["Data Structures"]},{"location":"data-structures/#fenwick-tree","title":"Fenwick Tree","text":"","tags":["Data Structures"]},{"location":"data-structures/#segment-tree","title":"Segment Tree","text":"","tags":["Data Structures"]},{"location":"data-structures/#trie","title":"Trie","text":"","tags":["Data Structures"]},{"location":"data-structures/#statik-veri-yaplar","title":"Statik Veri Yap\u0131lar\u0131","text":"","tags":["Data Structures"]},{"location":"data-structures/#prefix-sum","title":"Prefix Sum","text":"","tags":["Data Structures"]},{"location":"data-structures/#sparse-table","title":"Sparse Table","text":"","tags":["Data Structures"]},{"location":"data-structures/#sqrt-decomposition","title":"SQRT Decomposition","text":"","tags":["Data Structures"]},{"location":"data-structures/#mos-algorithm","title":"Mo's Algorithm","text":"","tags":["Data Structures"]},{"location":"data-structures/#common-problems","title":"Common Problems","text":"","tags":["Data Structures"]},{"location":"data-structures/#lca","title":"LCA","text":"","tags":["Data Structures"]},{"location":"data-structures/#ornek-problemler","title":"\u00d6rnek Problemler","text":"

Veri yap\u0131lar\u0131 \u00fczerinde pratik yapabilmeniz i\u00e7in \u00f6nerilen problemler:

  1. Link
  2. Link
  3. Link
  4. Link
  5. Link
","tags":["Data Structures"]},{"location":"data-structures/#faydal-baglantlar","title":"Faydal\u0131 Ba\u011flant\u0131lar","text":"
  1. https://en.wikipedia.org/wiki/Data_structure
  2. https://cp-algorithms.com/data_structures/sparse-table.html
  3. https://cp-algorithms.com/data_structures/segment_tree.html
  4. https://cp-algorithms.com/data_structures/fenwick.html
  5. https://cp-algorithms.com/data_structures/sqrt_decomposition.html
  6. https://cses.fi/book/book.pdf
  7. https://visualgo.net/en/segmenttree
  8. https://visualgo.net/en/fenwicktree
  9. https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2
  10. http://www.cs.ukzn.ac.za/~hughm/ds/slides/20-stacks-queues-deques.pdf
  11. https://www.geeksforgeeks.org/stack-data-structure
  12. https://www.geeksforgeeks.org/queue-data-structure
  13. https://www.geeksforgeeks.org/deque-set-1-introduction-applications
  14. https://www.geeksforgeeks.org/linked-list-set-1-introduction
  15. https://www.geeksforgeeks.org/binary-indexed-tree-range-updates-point-queries
  16. https://visualgo.net/en/list
  17. https://cp-algorithms.com/data_structures/fenwick.html
","tags":["Data Structures"]},{"location":"data-structures/deque/","title":"Deque","text":"

Deque veri yap\u0131s\u0131 stack ve queue veri yap\u0131lar\u0131na g\u00f6re daha kapsaml\u0131d\u0131r. Bu veri yap\u0131s\u0131nda yap\u0131n\u0131n en \u00fcst\u00fcne eleman eklenebilirken ayn\u0131 zamanda en alt\u0131na da eklenebilir. Ayn\u0131 \u015fekilde yap\u0131n\u0131n hem en \u00fcst\u00fcndeki eleman\u0131na hem de en alttaki eleman\u0131na eri\u015fim ve silme i\u015flemleri uygulanabilir. Bu veri yap\u0131s\u0131nda uyguluyabildi\u011fimiz i\u015flemler:

  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcne eleman ekleme.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131na eleman ekleme.
  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcndeki eleman\u0131na eri\u015fim.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131ndaki eleman\u0131na eri\u015fim.
  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcndeki eleman\u0131 silme.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131ndaki eleman\u0131 silme.

C++ dilindeki STL k\u00fct\u00fcphanesinde bulunan haz\u0131r deque yap\u0131s\u0131n\u0131n kullan\u0131m\u0131 a\u015fa\u011f\u0131daki gibidir:

int main() {\n    deque<int> q;\n    q.push_front(5);   // deque'nin en altina 5'i ekler.\n    q.push_back(6);    // deque'nin en ustune 6'yi ekler.\n    int x = q.front(); // deque'nin en altindaki elemanina erisim.\n    int y = q.back();  // deque'nin en ustundeki elemanina erisim.\n    q.pop_front();     // deque'nin en altindaki elemanini silme.\n    q.pop_back();      // deque'nin en ustundeki elemanini silme.\n}\n

P.S. deque veri yap\u0131s\u0131 stack ve queue veri yap\u0131lar\u0131na g\u00f6re daha kapsaml\u0131 oldu\u011fundan \u00f6t\u00fcr\u00fc stack ve queue veri yap\u0131lar\u0131na g\u00f6re 2 kat fazla memory kulland\u0131\u011f\u0131n\u0131 a\u00e7\u0131kl\u0131kla s\u00f6yleyebiliriz.

","tags":["Data Structures","Deque"]},{"location":"data-structures/fenwick-tree/","title":"Fenwick Tree","text":"

Binary Indexed Tree olarak da bilinen Fenwick Tree, Prefix Sum ve Sparse Table yap\u0131lar\u0131na benzer bir yap\u0131da olup dizi \u00fczerinde de\u011fi\u015fiklik yapabilmemize olanak sa\u011flayan bir veri yap\u0131s\u0131d\u0131r. Fenwick Tree'nin di\u011fer veri yap\u0131lar\u0131na g\u00f6re en b\u00fcy\u00fck avantaj\u0131 pratikte daha h\u0131zl\u0131 olmas\u0131 ve haf\u0131za karma\u015f\u0131kl\u0131\u011f\u0131n\u0131n \\(\\mathcal{O}(N)\\) olmas\u0131d\u0131r. Ancak Fenwick Tree'de sadece prefix cevaplar\u0131 (veya suffix cevaplar\u0131) saklayabildi\u011fimizden aral\u0131klarda minimum, maksimum ve EBOB gibi baz\u0131 sorgular\u0131n cevaplar\u0131n\u0131 elde edemeyiz.

","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#yaps-ve-kurulusu","title":"Yap\u0131s\u0131 ve Kurulu\u015fu","text":"

\\(g(x)\\), \\(x\\) say\u0131s\u0131n\u0131n bit g\u00f6steriminde yaln\u0131zca en sa\u011fdaki bitin 1 oldu\u011fu tam say\u0131 olsun. \u00d6rne\u011fin \\(20\\)'nin bit g\u00f6sterimi \\((10100)_2\\) oldu\u011fundan \\(g(20)=4\\)'t\u00fcr. \u00c7\u00fcnk\u00fc ilk kez sa\u011fdan \\(3.\\) bit \\(1\\)'dir ve \\((00100)_2=4\\)'t\u00fcr. Fenwick Tree'nin \\(x\\) indeksli d\u00fc\u011f\u00fcm\u00fcnde, \\(x - g(x) + 1\\) indeksli elemandan \\(x\\) indeksli elemana kadar olan aral\u0131\u011f\u0131n cevab\u0131n\u0131 saklayacak \u015fekilde kurulur.

$8$ uzunlu\u011fundaki bir dizi i\u00e7in kurulmu\u015f Fenwick Tree yap\u0131s\u0131","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#sorgu-algoritmas","title":"Sorgu Algoritmas\u0131","text":"

Herhangi bir \\([1,x]\\) aral\u0131\u011f\u0131 i\u00e7in sorgu algoritmas\u0131 s\u0131ras\u0131 ile \u015fu \u015feklide \u00e7al\u0131\u015f\u0131r:

  1. Arad\u0131\u011f\u0131m\u0131z cevaba \\([x - g(x) + 1,x]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 ekle.
  2. \\(x\\)'in de\u011ferini \\(x - g(x)\\) yap. E\u011fer \\(x\\)'in yeni de\u011feri \\(0\\)'dan b\u00fcy\u00fck ise \\(1.\\) i\u015flemden hesaplamaya devam et.

\\([1,x]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 hesaplamak i\u00e7in yap\u0131lan i\u015flem say\u0131s\u0131 \\(x\\) say\u0131s\u0131n\u0131n \\(2\\)'lik tabandaki yaz\u0131l\u0131\u015f\u0131ndaki \\(1\\) say\u0131s\u0131na e\u015fittir. \u00c7\u00fcnk\u00fc her d\u00f6ng\u00fcde \\(x\\)'ten \\(2\\)'lik tabandaki yaz\u0131l\u0131\u015f\u0131ndaki en sa\u011fdaki \\(1\\) bitini \u00e7\u0131kart\u0131yoruz. Dolay\u0131s\u0131yla sorgu i\u015flemimiz \\(\\mathcal{O}(\\log N)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda \u00e7al\u0131\u015f\u0131r. \\([l,r]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 da \\([1,r]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131ndan \\([1,l - 1]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 \u00e7\u0131kararak kolay bir \u015fekilde elde edebiliriz.

NOT: \\(g(x)\\) de\u011ferini bitwise operat\u00f6rlerini kullanarak a\u015fa\u011f\u0131daki e\u015fitlikle kolay bir \u015fekilde hesaplayabiliriz: \\[g(x) = x \\ \\& \\ (-x)\\]

","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#eleman-guncelleme-algoritmas","title":"Eleman G\u00fcncelleme Algoritmas\u0131","text":"

Dizideki \\(x\\) indeksli eleman\u0131n\u0131n de\u011ferini g\u00fcncellemek i\u00e7in kullan\u0131lan algoritma \u015fu \u015feklide \u00e7al\u0131\u015f\u0131r:

  • A\u011fa\u00e7ta \\(x\\) indeksli eleman\u0131 i\u00e7eren t\u00fcm d\u00fc\u011f\u00fcmlerin de\u011ferlerini g\u00fcncelle.

Fenwick Tree'de \\(x\\) indeksli eleman\u0131 i\u00e7eren maksimum \\(\\log(N)\\) tane aral\u0131k oldu\u011fundan g\u00fcncelleme algoritmas\u0131 \\(\\mathcal{O}(\\log N)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda \u00e7al\u0131\u015f\u0131r.

","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#ornek-kod-parcalar","title":"\u00d6rnek Kod Par\u00e7alar\u0131","text":"
const int n;\nint tree[n + 1], a[n + 1];\n\nvoid add(int val, int x) { // x indeksli elemanin degerini val degeri kadar artirir.\n    // x indeksinin etkiledigi butun dugumleri val degeri kadar artirir.\n    while (x <= n) {\n        tree[x] += val;\n        x += x & (-x);\n    }\n}\n\nint sum(int x) { // 1 indeksli elemandan x indeksli elemana\n    int res = 0; // kadar olan sayilarin toplamini verir.\n    while (x >= 1) {\n        res += tree[x];\n        x -= x & (-x);\n    }\n    return res;\n}\n\nint query(int l, int r) { // [l,r] araligindaki elemanlarin toplamini verir.\n    return sum(r) - sum(l - 1);\n}\n\nvoid build() { // a dizisi uzerine fenwick tree yapisini kuruyoruz.\n    for (int i = 1; i <= n; i++)\n        add(a[i], i);\n}\n

Fenwick Tree veri yap\u0131s\u0131 ile ilgili \u00f6rnek bir probleme buradan ula\u015fabilirsiniz.

","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#aralk-guncelleme-ve-eleman-sorgu","title":"Aral\u0131k G\u00fcncelleme ve Eleman Sorgu","text":"

Bir \\(a\\) dizisi \u00fczerinde i\u015flemler yapaca\u011f\u0131m\u0131z\u0131 varsayal\u0131m daha sonra \\(a\\) dizisi \\(b\\) dizisinin prefix sum dizisi olacak \u015fekilde bir \\(b\\) dizisi tan\u0131mlayal\u0131m. Ba\u015fka bir deyi\u015fle $a_i = \\displaystyle\\sum_{j=1}^{i} {b_j} $ olmal\u0131d\u0131r. Sonradan olu\u015fturdu\u011fumuz \\(b\\) dizisi \u00fczerine Fenwick Tree yap\u0131s\u0131n\u0131 kural\u0131m. \\([l,r]\\) aral\u0131\u011f\u0131ndaki her elemana \\(x\\) de\u011ferini eklememiz i\u00e7in uygulamam\u0131z gereken i\u015flemler:

  • \\(b_l\\) de\u011ferini \\(x\\) kadar art\u0131r. B\u00f6ylelikle \\(l\\) indeksli elemandan dizinin sonuna kadar t\u00fcm elemanlar\u0131n de\u011feri \\(x\\) kadar artm\u0131\u015f olur.
  • \\(b_{r + 1}\\) de\u011ferini \\(x\\) kadar azalt. B\u00f6ylelikle \\(r + 1\\) indeksli elemandan dizinin sonuna kadar t\u00fcm elemanlar\u0131n de\u011feri \\(x\\) kadar azalm\u0131\u015f olur. Bu i\u015flemelerin sonucunda sadece \\([l,r]\\) aral\u0131\u011f\u0131ndaki elemanlar\u0131n de\u011feri \\(x\\) kadar artm\u0131\u015f olur.
","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/fenwick-tree/#ornek-kod-parcalar_1","title":"\u00d6rnek Kod Par\u00e7alar\u0131","text":"
const int n;\nint a[n + 1], b[n + 1];\n\nvoid add(int val, int x) { // x indeksli elemanin degerini val degeri kadar artirir.\n    while (x <= n) {\n        tree[x] += val;\n        x += x & (-x);\n    }\n}\n\nint sum(int x) { // 1 indeksli elemandan x indeksli elemana\n    int res = 0; // kadar olan sayilarin toplamini verir.\n    while (x >= 1) {\n        res += tree[x];\n        x -= x & (-x);\n    }\n    return res;\n}\nvoid build() {\n    for (int i = 1; i <= n; i++)\n        b[i] = a[i] - a[i - 1]; // b dizisini olusturuyoruz.\n\n    for (int i = 1; i <= n; i++)\n        add(b[i], i); // b dizisi uzerine fenwick tree kuruyoruz.\n}\n\nvoid update(int l, int r, int x) {\n    add(x, l);\n    add(-x, r + 1);\n}\n\nvoid query(int x) { return sum(x); }\n
","tags":["Data Structures","Fenwick Tree","Binary Indexed Tree","BIT"]},{"location":"data-structures/linked-list/","title":"Linked List","text":"

Linked List veri yap\u0131s\u0131nda elemanlar, her eleman kendi de\u011ferini ve bir sonraki eleman\u0131n adresini tutacak \u015fekilde saklan\u0131r. Yap\u0131daki elemanlar ba\u015f elemandan (head) ba\u015flanarak son elemana (tail) gidecek \u015fekilde gezilebilir. Diziye kar\u015f\u0131n avantaj\u0131 haf\u0131zan\u0131n dinamik bir \u015fekilde kullan\u0131lmas\u0131d\u0131r. Bu veri yap\u0131s\u0131nda uygulanabilecek i\u015flemler:

  • Veri yap\u0131s\u0131n\u0131n sonuna eleman ekleme.
  • Anl\u0131k veri yap\u0131s\u0131n\u0131 ba\u015ftan (head) sona (tail) gezme.
\u00d6rnek bir Linked List yap\u0131s\u0131
// Her bir elemani (burada sayilari, yani int) tutacak struct olusturuyoruz.\nstruct node {\n    int data;\n    node *next;\n};\nnode *head, *tail;\n\nvoid push_back(int x) {\n    // Yeni elemanimizi hafizada olusturuyoruz.\n    node *t = (node *)malloc(sizeof(node));\n    t->data = x;    // Elemanin verisini atiyoruz.\n    t->next = NULL; // Sona ekledigimizden sonraki elemanina NULL atiyoruz.\n\n    // Eger veri yapimiza hic eleman eklenmediyse head\n    // ve tail elemanlarini olusturuyoruz.\n    if (head == NULL && tail == NULL) {\n        head = t;\n        tail = t;\n    }\n    // Eklenmisse yeni tail elemanimizi guncelliyoruz.\n    else {\n        tail->next = t;\n        tail = t;\n    }\n}\n\nvoid print() {\n    // Dizideki tum elemanlari geziyoruz.\n    node *t = head;\n    while (t != NULL) {\n        printf(\"%d \", t->data);\n        t = t->next;\n    }\n}\n
","tags":["Data Structures","Linked List"]},{"location":"data-structures/lowest-common-ancestor/","title":"Lowest Common Ancestors","text":"

This problem consists of queries, LCA(x, y), and asks for the ancestor of both x and y whose depth is maximum. We will use a similar algorithm to the jump pointer algorithm with implementation.

","tags":["Tree","LCA","Lowest Common Ancestors","Binary Lifting"]},{"location":"data-structures/lowest-common-ancestor/#initialization","title":"Initialization","text":"

As we did in Jump Pointer Method, we will calculate node's all \\(2^i\\). ancestors if they exist. L[x][y] corresponds to x's \\(2^y\\). ancestors. Hence L[x][0] is basically the parent of x.

void init() {\n    for(int x=1 ; x<=n ; x++)\n        L[x][0] = parent[x];\n\n    for(int y=1 ; y<=logN ; y++)\n        for(int x=1 ; x<=n ; x++)\n            L[x][y] = L[L[x][y-1]][y-1];\n}\n
Note that we have used the fact that x's \\(2^y\\). ancestor is x's \\(2^{y\u22121}\\). ancestor's \\(2^{y\u22121}\\). ancestor.

","tags":["Tree","LCA","Lowest Common Ancestors","Binary Lifting"]},{"location":"data-structures/lowest-common-ancestor/#queries-binary-lifting","title":"Queries-Binary Lifting","text":"

Given LCA(x, y), we calculate answer by following:

Firstly, ensure that both x and y are in same depth. If it is not take the deepest one to the other one's depth. Then control whether x and y is equal. If they are equal, that means the lowest common ancestor is x. After that, from i = log(N), check that if x's \\(2^i\\). ancestor is equal to y's \\(2^i\\). ancestor. If they are not equal that means LCA is somewhere above the \\(2^i\\). ancestors of x and y. Then we continue to search LCA of y and x\u2019s ancestors as LCA(L[x][i], L[y][i]) is the same as LCA(x, y). Please notice that we have ensured that depth di\ufb00erence between LCA and both x and y are no longer larger than \\(2^i\\). If we apply this producure until i = 0, we would left with x and y such that parent of x is LCA. Of course, the parent of y would also be LCA.

","tags":["Tree","LCA","Lowest Common Ancestors","Binary Lifting"]},{"location":"data-structures/mo-algorithm/","title":"Mo's Algorithm","text":"

This method will be a key for solving offline range queries on an array. By offline, we mean we can find the answers of these queries in any order we want and there are no updates. Let\u2019s introduce a problem and construct an efficient solution for it.

You have an array a with \\(N\\) elements such that it\u2019s elements ranges from \\(1\\) to \\(M\\). You have to answer \\(Q\\) queries. Each is in the same type. You will be given a range \\([l, r]\\) for each query, you have to print how many different values are there in the subarray \\([a_l , a_{l+1}..a_{r\u22121}, a_r]\\).

First let\u2019s find a naive solution and improve it. Remember the frequency array we mentioned before. We will keep a frequency array that contains only given subarray\u2019s values. Number of values in this frequency array bigger than 0 will be our answer for given query. Then we have to update frequency array for next query. We will use \\(\\mathcal{O}(N)\\) time for each query, so total complexity will be \\(\\mathcal{O}(Q \\times N)\\). Look at the code below for implementation.

class Query {\n   public:\n    int l, r, ind;\n    Query(int l, int r, int ind) {\n        this->l = l, this->r = r, this->ind = ind;\n    }\n};\n\nvoid del(int ind, vector<int> &a, vector<int> &F, int &num) {\n    if (F[a[ind]] == 1) num--;\n    F[a[ind]]--;\n}\n\nvoid add(int ind, vector<int> &a, vector<int> &F, int &num) {\n    if (F[a[ind]] == 0) num++;\n    F[a[ind]]++;\n}\n\nvector<int> solve(vector<int> &a, vector<Query> &q) {\n    int Q = q.size(), N = a.size();\n    int M = *max_element(a.begin(), a.end());\n    vector<int> F(M + 1, 0);  // This is frequency array we mentioned before\n    vector<int> ans(Q, 0);\n    int l = 0, r = -1, num = 0;\n    for (int i = 0; i < Q; i++) {\n        int nl = q[i].l, nr = q[i].r;\n        while (l < nl) del(l++, a, F, num);\n        while (l > nl) add(--l, a, F, num);\n        while (r > nr) del(r--, a, F, num);\n        while (r < nr) add(++r, a, F, num);\n        ans[q[i].ind] = num;\n    }\n    return ans;\n}\n

Time complexity for each query here is \\(\\mathcal{O}(N)\\). So total complexity is \\(\\mathcal{O}(Q \\times N)\\). Just by changing the order of queries we will reduce this complexity to \\(\\mathcal{O}((Q + N) \\times \\sqrt N)\\).

","tags":["Data Structures","Mo's Algorithm"]},{"location":"data-structures/mo-algorithm/#mos-algorithm","title":"Mo's Algorithm","text":"

We will change the order of answering the queries such that overall complexity will be reduced drastically. We will use following cmp function to sort our queries and will answer them in this sorted order. Block size here is \\(\\mathcal{O}(\\sqrt N)\\).

bool operator<(Query other) const {\n    return make_pair(l / block_size, r) <\n        make_pair(other.l / block_size, other.r);\n}\n

Why does that work? Let\u2019s examine what we do here first then find the complexity. We divide \\(l\\)'s of queries into blocks. Block number of a given \\(l\\) is \\(l\\) blocksize (integer division). We sort the queries first by their block numbers then for same block numbers, we sort them by their \\(r\\)'s. Sorting all queries will take \\(\\mathcal{O}(Q \\times log{Q})\\) time. Let\u2019s look at how many times we will call add and del operations to change current \\(r\\). For the same block \\(r\\)'s always increases. So for same block it is \\(\\mathcal{O}(N)\\) since it can only increase. Since there are \\(N\\) blocksize blocks in total, it will be \\(\\mathcal{O}(N \\times N / \\text{block\\_size})\\) operations in total. For same block, add and del operations that changes \\(l\\) will be called at most \\(\\mathcal{O}(\\text{block\\_size})\\) times for each query, since if block number is same then their \\(l\\)'s must differ at most by \\(\\mathcal{O}(\\text{block\\_size})\\). So overall it is \\(\\mathcal{O}(Q \\times \\text{block\\_size})\\). Also when consecutive queries has different block numbers we will perform at most \\(\\mathcal{O}(N)\\) operations, but notice that there are at most \\(\\mathcal{O}(N \\div \\text{block\\_size})\\) such consecutive queries, so it doesn't change the overall time complexity. If we pick \\(block\\_size = \\sqrt N\\) overall complexity will be \\(\\mathcal{O}((Q + N) \\times \\sqrt N)\\). Full code is given below.

Example for the Algorithm
int block_size;\n\nclass Query {\n   public:\n    int l, r, ind;\n    Query(int l, int r, int ind) {\n        this->l = l, this->r = r, this->ind = ind;\n    }\n    bool operator<(Query other) const {\n        return make_pair(l / block_size, r) <\n               make_pair(other.l / block_size, other.r);\n    }\n};\n\nvoid del(int ind, vector<int> &a, vector<int> &F, int &num) {\n    if (F[a[ind]] == 1) num--;\n    F[a[ind]]--;\n}\n\nvoid add(int ind, vector<int> &a, vector<int> &F, int &num) {\n    if (F[a[ind]] == 0) num++;\n    F[a[ind]]++;\n}\n\nvector<int> solve(vector<int> &a, vector<Query> &q) {\n    int Q = q.size(), N = a.size();\n    int M = *max_element(a.begin(), a.end());\n    block_size = sqrt(N);\n    sort(q.begin(), q.end());\n    vector<int> F(M + 1, 0);  // This is frequency array we mentioned before\n    vector<int> ans(Q, 0);\n    int l = 0, r = -1, num = 0;\n    for (int i = 0; i < Q; i++) {\n        int nl = q[i].l, nr = q[i].r;\n        while (l < nl) del(l++, a, F, num);\n        while (l > nl) add(--l, a, F, num);\n        while (r > nr) del(r--, a, F, num);\n        while (r < nr) add(++r, a, F, num);\n        ans[q[i].ind] = num;\n    }\n    return ans;\n}\n
","tags":["Data Structures","Mo's Algorithm"]},{"location":"data-structures/prefix-sum/","title":"Prefix Sum","text":"

Prefix Sum dizisi bir dizinin prefixlerinin toplamlar\u0131yla olu\u015fturulan bir veri yap\u0131s\u0131d\u0131r. Prefix sum dizisinin \\(i\\) indeksli eleman\u0131 girdi dizisindeki \\(1\\) indeksli elemandan \\(i\\) indeksli elemana kadar olan elemanlar\u0131n toplam\u0131na e\u015fit olacak \u015fekilde kurulur. Ba\u015fka bir deyi\u015fle:

\\[sum_i = \\sum_{j=1}^{i} {a_j}\\]

\u00d6rnek bir \\(A\\) dizisi i\u00e7in prefix sum dizisi \u015fu \u015fekilde kurulmal\u0131d\u0131r:

A Dizisi \\(4\\) \\(6\\) \\(3\\) \\(12\\) \\(1\\) Prefix Sum Dizisi \\(4\\) \\(10\\) \\(13\\) \\(25\\) \\(26\\) \\(4\\) \\(4+6\\) \\(4+6+3\\) \\(4+6+3+12\\) \\(4+6+3+12+1\\)

Prefix sum dizisini kullanarak herhangi bir \\([l,r]\\) aral\u0131\u011f\u0131ndaki elemanlar\u0131n toplam\u0131n\u0131 \u015fu \u015fekilde kolayl\u0131kla elde edebiliriz:

\\[sum_r = \\sum_{j=1}^{r} {a_j}\\]

\\[sum_{l - 1} = \\sum_{j=1}^{l - 1} {a_j}\\]

\\[sum_r - sum_{l-1} = \\sum_{j=l}^{r} {a_j}\\]

","tags":["Data Structures","Prefix Sum"]},{"location":"data-structures/prefix-sum/#ornek-kod-parcalar","title":"\u00d6rnek Kod Par\u00e7alar\u0131","text":"

Prefix Sum dizisini kurarken \\(sum_i = sum_{i - 1} + a_i\\) e\u015fitli\u011fi kolayca g\u00f6r\u00fclebilir ve bu e\u015fitli\u011fi kullanarak \\(sum[]\\) dizisini girdi dizisindeki elemanlar\u0131 s\u0131rayla gezerek kurabiliriz:

const int n;\nint sum[n + 1], a[n + 1];\n// a dizisi girdi dizimiz, sum dizisi de prefix sum dizimiz olsun.\n\nvoid build() {\n    for (int i = 1; i <= n; i++)\n        sum[i] = sum[i - 1] + a[i];\n    return;\n}\n\nint query(int l, int r) {\n    return sum[r] - sum[l - 1];\n}\n
","tags":["Data Structures","Prefix Sum"]},{"location":"data-structures/prefix-sum/#zaman-karmasklg","title":"Zaman Karma\u015f\u0131kl\u0131\u011f\u0131","text":"

Prefix sum dizisini kurma i\u015flemimizin zaman ve haf\u0131za karma\u015f\u0131kl\u0131\u011f\u0131 \\(\\mathcal{O}(N)\\). Her sorguya da \\(\\mathcal{O}(1)\\) karma\u015f\u0131kl\u0131kta cevap verebiliyoruz.

Prefix sum veri yap\u0131s\u0131 ile ilgili \u00f6rnek bir probleme buradan ula\u015fabilirsiniz.

","tags":["Data Structures","Prefix Sum"]},{"location":"data-structures/queue/","title":"Queue","text":"

Queue veri yap\u0131s\u0131nda elemanlar yap\u0131ya ilk giren ilk \u00e7\u0131kar (FIFO) kural\u0131na uygun olacak \u015fekilde saklan\u0131r. Bu veri yap\u0131s\u0131nda uygulayabildigimiz i\u015flemler:

  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcne eleman ekleme.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131ndaki eleman\u0131na eri\u015fim.
  • Veri yap\u0131s\u0131n\u0131n en alt\u0131ndaki eleman\u0131 silme.
  • Veri yap\u0131s\u0131n\u0131n bo\u015f olup olmad\u0131\u011f\u0131n\u0131n kontr\u00f6l\u00fc.

C++ dilindeki STL k\u00fct\u00fcphanesinde bulunan haz\u0131r queue yap\u0131s\u0131n\u0131n kullan\u0131m\u0131 a\u015fa\u011f\u0131daki gibidir:

int main() {\n    queue<int> q;\n    cout << q.empty() << endl; // Ilk bashta Queue bosh oldugu icin burada True donecektir.\n    q.push(5);                 // Queue'in en ustune 5'i ekler. Queue'in yeni hali: {5}\n    q.push(7);                 // Queue'in en ustune 7'yi ekler. Queue'in yeni hali: {7, 5}\n    q.push(6);                 // Queue'in en ustune 6'yi ekler. Queue'in yeni hali : {6, 7, 5}\n    q.pop();                   // Queue'in en altindaki elemani siler. Queue'in yeni hali : {6, 7}\n    q.push(1);                 // Queue'in en ustune 1'i ekler. Queue'in yeni hali : {1, 6, 7}\n    cout << Q.front() << endl; // Queue'in en ustundeki elemana erisir. Ekrana 7 yazdirir.\n}\n
","tags":["Data Structures","Queue"]},{"location":"data-structures/segment-tree/","title":"Segment Tree","text":"

Segment Tree is a data structure that enables us to answer queries like minimum, maximum, sum etc. for any \\([l,r]\\) interval in \\(\\mathcal{O}(\\log N)\\) time complexity and update these intervals.

Segment Tree is more useful than Fenwick Tree and Sparse Table structures because it allows updates on elements and provides the possibility to answer queries like minimum, maximum etc. for any \\([l,r]\\) interval. Also, the memory complexity of Segment Tree is \\(\\mathcal{O}(N)\\) while the memory complexity of the Sparse Table structure is \\(\\mathcal{O}(N \\log N)\\).

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#structure-and-construction","title":"Structure and Construction","text":"

Segment Tree has a \"Complete Binary Tree\" structure. The leaf nodes of the Segment Tree store the elements of the array, and each internal node's value is calculated with a function that takes its children's values as inputs. Thus, the answers of certain intervals are stored in each node, and the answer of the whole array is stored in the root node. For example, for a Segment Tree structure built for the sum query, the value of each node is equal to the sum of its children's values.

segment tree structure to query sum on array $a = [41,67,6,30,85,43,39]$
void build(int ind, int l, int r) {\n    // tree[ind] stores the answer of the interval [l,r]\n    if (l == r) {         // leaf node reached\n        tree[ind] = a[l]; // store the value of the leaf node\n    } else {\n        int mid = (l + r) / 2;\n        build(ind * 2, l, mid);\n        build(ind * 2 + 1, mid + 1, r);\n        // the answer of the interval [l,mid] and [mid + 1,r] is the sum of their answers\n        tree[ind] = tree[ind * 2] + tree[ind * 2 + 1];\n    }\n}\n
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#query-and-update-algorithms","title":"Query and Update Algorithms","text":"","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#query-algorithm","title":"Query Algorithm","text":"

For any \\([l,r]\\) interval, the query algorithm works as follows: - Divide the \\([l,r]\\) interval into the widest intervals that are stored in the tree. - Merge the answers of these intervals to calculate the desired answer.

There are at most \\(2\\) intervals that are needed to calculate the answer at each depth of the tree. Therefore, the query algorithm works in \\(\\mathcal{O}(\\log N)\\) time complexity.

on array $a = [41,67,6,30,85,43,39]$ query at $[2,6]$ interval

On array \\(a = [41,67,6,30,85,43,39]\\), the answer of the \\([2,6]\\) interval is obtained by merging the answers of the \\([2,3]\\) and \\([4,6]\\) intervals. The answer for the sum query is calculated as \\(36+167=203\\).

// [lw,rw] is the interval we are looking for the answer\n// [l,r] is the interval that the current node stores the answer\nint query(int ind, int l, int r, int lw, int rw) {\n    if (l > rw or r < lw) //current interval does not contain the interval we are looking for\n        return 0;\n    if (l >= lw and r <= rw) //current interval is completely inside the interval we are looking for\n        return tree[ind];\n\n    int mid = (l + r) / 2;\n\n    // recursively calculate the answers of all intervals containing the x index\n    return query(ind * 2, l, mid, lw, rw) + query(ind * 2 + 1, mid + 1, r, lw, rw);\n}\n
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#update-algorithm","title":"Update Algorithm","text":"

Update the value of every node that contains \\(x\\) indexed element.

It is sufficient to update the values of at most \\(\\log(N)\\) nodes from the leaf node containing the \\(x\\) indexed element to the root node. Therefore, the time complexity of updating the value of any element is \\(\\mathcal{O}(\\log N)\\).

the nodes that should be updated when updating the $5^{th}$ index of the array $a = [41,67,6,30,85,43,39]$ are as follows:
void update(int ind, int l, int r, int x, int val) {\n    if (l > x || r < x) // x index is not in the current interval\n        return;\n    if (l == x and r == x) {\n        tree[ind] = val; // update the value of the leaf node\n        return;\n    }\n\n    int mid = (l + r) / 2;\n\n    // recursively update the values of all nodes containing the x index\n    update(ind * 2, l, mid, x, val);\n    update(ind * 2 + 1, mid + 1, r, x, val);\n    tree[ind] = tree[ind * 2] + tree[ind * 2 + 1];\n}\n

A sample problem related to the Segment Tree data structure can be found here.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#segment-tree-with-lazy-propagation","title":"Segment Tree with Lazy Propagation","text":"

Previously, update function was called to update only a single value in array. Please note that a single value update in array may cause changes in multiple nodes in Segment Tree as there may be many segment tree nodes that have this changed single element in it\u2019s range.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#lazy-propogation-algorithm","title":"Lazy Propogation Algorithm","text":"

We need a structure that can perform following operations on an array \\([1,N]\\).

  • Add inc to all elements in the given range \\([l, r]\\).
  • Return the sum of all elements in the given range \\([l, r]\\).

Notice that if update was for single element, we could use the segment tree we have learned before. Trivial structure comes to mind is to use an array and do the operations by traversing and increasing the elements one by one. Both operations would take \\(\\mathcal{O}(L)\\) time complexity in this structure where \\(L\\) is the number of elements in the given range.

Let\u2019s use segment tree\u2019s we have learned. Second operation is easy, We can do it in \\(\\mathcal{O}(\\log N)\\). What about the first operation. Since we can do only single element update in the regular segment tree, we have to update all elements in the given range one by one. Thus we have to perform update operation \\(L\\) times. This works in \\(\\mathcal{O}(L \\times \\log N)\\) for each range update. This looks bad, even worse than just using an array in a lot of cases.

So we need a better structure. People developed a trick called lazy propagation to perform range updates on a structure that can perform single update (This trick can be used in segment trees, treaps, k-d trees ...).

Trick is to be lazy i.e, do work only when needed. Do the updates only when you have to. Using Lazy Propagation we can do range updates in \\(\\mathcal{O}(\\log N)\\) on standart segment tree. This is definitely fast enough.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#updates-using-lazy-propogation","title":"Updates Using Lazy Propogation","text":"

Let\u2019s be lazy as told, when we need to update an interval, we will update a node and mark its children that it needs to be updated and update them when needed. For this we need an array \\(lazy[]\\) of the same size as that of segment tree. Initially all the elements of the \\(lazy[]\\) array will be \\(0\\) representing that there is no pending update. If there is non-zero element \\(lazy[k]\\) then this element needs to update node k in the segment tree before making any query operation, then \\(lazy[2\\cdot k]\\) and \\(lazy[2 \\cdot k + 1]\\) must be also updated correspondingly.

To update an interval we will keep 3 things in mind.

  • If current segment tree node has any pending update, then first add that pending update to current node and push the update to it\u2019s children.
  • If the interval represented by current node lies completely in the interval to update, then update the current node and update the \\(lazy[]\\) array for children nodes.
  • If the interval represented by current node overlaps with the interval to update, then update the nodes as the earlier update function.
void update(int node, int start, int end, int l, int r, int val) {\n    // If there's a pending update on the current node, apply it\n    if (lazy[node] != 0) {\n        tree[node] += (end - start + 1) * lazy[node]; // Apply the pending update\n        // If not a leaf node, propagate the lazy update to the children\n        if (start != end) {\n            lazy[2 * node] += lazy[node];\n            lazy[2 * node + 1] += lazy[node];\n        }\n        lazy[node] = 0; // Clear the pending update\n    }\n\n    // If the current interval [start, end] does not intersect with [l, r], return\n    if (start > r || end < l) {\n        return;\n    }\n\n    // If the current interval [start, end] is completely within [l, r], apply the update\n    if (l <= start && end <= r) {\n        tree[node] += (end - start + 1) * val; // Update the segment\n        // If not a leaf node, propagate the update to the children\n        if (start != end) {\n            lazy[2 * node] += val;\n            lazy[2 * node + 1] += val;\n        }\n        return;\n    }\n\n    // Otherwise, split the interval and update both halves\n    int mid = (start + end) / 2;\n    update(2 * node, start, mid, l, r, val);\n    update(2 * node + 1, mid + 1, end, l, r, val);\n\n    // After updating the children, recalculate the current node's value\n    tree[node] = tree[2 * node] + tree[2 * node + 1];\n}\n

This is the update function for given problem. Notice that when we arrive a node, all the updates that we postponed that would effect this node will be performed since we are pushing them downwards as we go to this node. Thus this node will keep the exact values when the range updates are done without lazy. So it\u2019s seems like it is working. How about queries?

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#queries-using-lazy-propogation","title":"Queries Using Lazy Propogation","text":"

Since we have changed the update function to postpone the update operation, we will have to change the query function as well. The only change we need to make is to check if there is any pending update operation on that node. If there is a pending update, first update the node and then proceed the same way as the earlier query function. As mentioned in the previous subsection, all the postponed updates that would affect this node will be performed before we reach it. Therefore, the sum value we look for will be correct.

int query(int node, int start, int end, int l, int r) {\n    // If the current interval [start, end] does not intersect with [l, r], return 0\n    if (start > r || end < l) {\n        return 0;\n    }\n\n    // If there's a pending update on the current node, apply it\n    if (lazy[node] != 0) {\n        tree[node] += (end - start + 1) * lazy[node]; // Apply the pending update\n        // If not a leaf node, propagate the lazy update to the children\n        if (start != end) {\n            lazy[2 * node] += lazy[node];\n            lazy[2 * node + 1] += lazy[node];\n        }\n        lazy[node] = 0; // Clear the pending update\n    }\n\n    // If the current interval [start, end] is completely within [l, r], return the value\n    if (l <= start && end <= r) {\n        return tree[node];\n    }\n\n    // Otherwise, split the interval and query both halves\n    int mid = (start + end) / 2;\n    int p1 = query(2 * node, start, mid, l, r);       // Query the left child\n    int p2 = query(2 * node + 1, mid + 1, end, l, r); // Query the right child\n\n    // Combine the results from the left and right child nodes\n    return (p1 + p2);\n}\n
Notice that the only difference with the regular query function is pushing the lazy values downwards as we traverse. This is a widely used trick applicable to various problems, though not all range problems. You may notice that we leveraged properties of addition here. The associative property of addition allows merging multiple updates in the lazy array without considering their order. This assumption is crucial for lazy propagation. Other necessary properties are left as an exercise to the reader.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#binary-search-on-segment-tree","title":"Binary Search on Segment Tree","text":"

Assume we have an array A that contains elements between 1 and \\(M\\). We have to perform 2 kinds of operations.

  • Change the value of the element in given index i by x.
  • Return the value of the kth element on the array when sorted.
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#how-to-solve-it-naively","title":"How to Solve It Naively","text":"

Let\u2019s construct a frequency array, \\(F[i]\\) will keep how many times number i occurs in our original array. So we want to find smallest \\(i\\) such that \\(\\sum_{j=1}^{i} F[i] \\geq k\\). Then the number \\(i\\) will be our answer for the query. And for updates we just have to change \\(F\\) array accordingly.

A naive update example

This is the naive algorithm. Update is O(1) and query is O(M).

void update(int i, int x) {\n    F[A[i]]--;\n    F[A[i] = x]++;\n}\n\nint query(int k) {\n    int sum = 0, ans = 0;\n    // Iterate through the frequency array F to find the smallest value\n    // for which the cumulative frequency is at least k\n    for (int i = 1; i <= M; i++) {\n        sum += F[i]; // Add the frequency of F[i] to the cumulative sum\n        if (sum >= k) {\n            return i;\n        }\n    }\n}\n
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#how-to-solve-it-with-segment-tree","title":"How to Solve It With Segment Tree","text":"

This is of course, slow. Let\u2019s use segment tree\u2019s to improve it. First we will construct a segment tree on \\(F\\) array. Segment tree will perform single element updates and range sum queries. We will use binary search to find corresponding \\(i\\) for \\(k^{th}\\) element queries.

Segment Tree After First Update
void update(int i, int x) {\n    update(1, 1, M, A[i], --F[A[i]]); // Decrement frequency of old value\n    A[i] = x;                        // Update A[i] to new value\n    update(1, 1, M, A[i], ++F[A[i]]); // Increment frequency of new value\n}\n\nint query(int k) {\n    int l = 1, r = m; // Initialize binary search range\n    while (l < r) {\n        int mid = (l + r) / 2; \n        if (query(1, 1, M, 1, mid) < k)\n            l = mid + 1; // Move lower bound up\n        else\n            r = mid; // Move upper bound down\n    }\n    return l; // Return index where cumulative frequency is at least k\n}\n

If you look at the code above you can notice that each update takes \\(\\mathcal{O}(\\log M)\\) time and each query takes \\(\\mathcal{O}(\\log^{2} M)\\) time, but we can do better.

","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/segment-tree/#how-to-speed-up","title":"How To Speed Up?","text":"

If you look at the segment tree solution on preceding subsection you can see that queries are performed in \\(\\mathcal{O}(\\log^{2} M)\\) time. We can make is faster, actually we can reduce the time complexity to \\(\\mathcal{O}(\\log M)\\) which is same with the time complexity for updates. We will do the binary search when we are traversing the segment tree. We first will start from the root and look at its left child\u2019s sum value, if this value is greater than k, this means our answer is somewhere in the left child\u2019s subtree. Otherwise it is somewhere in the right child\u2019s subtree. We will follow a path using this rule until we reach a leaf, then this will be our answer. Since we just traversed \\(\\mathcal{O}(\\log M)\\) nodes (one node at each level), time complexity will be \\(\\mathcal{O}(\\log M)\\). Look at the code below for better understanding.

Solution of First Query
void update(int i, int x) {\n    update(1, 1, M, A[i], --F[A[i]]); // Decrement frequency of old value\n    A[i] = x;                         // Update A[i] to new value\n    update(1, 1, M, A[i], ++F[A[i]]); // Increment frequency of new value\n}\n\nint query(int node, int start, int end, int k) {\n    if (start == end) return start; // Leaf node, return the index\n    int mid = (start + end) / 2; \n    if (tree[2 * node] >= k)\n        return query(2 * node, start, mid, k); // Search in left child\n    return query(2 * node + 1, mid + 1, end, k - tree[2 * node]); // Search in right child\n}\n\nint query(int k) {\n    return query(1, 1, M, k); // Public interface for querying\n}\n
","tags":["Data Structures","Segment Tree"]},{"location":"data-structures/sparse-table/","title":"Sparse Table","text":"

Sparse table aral\u0131klardaki elemanlar\u0131n toplam\u0131, minimumu, maksimumu ve EBOB'lar\u0131 gibi sorgulara \\(\\mathcal{O}(\\log N)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda cevap alabilmemizi sa\u011flayan bir veri yap\u0131s\u0131d\u0131r. Baz\u0131 tip sorgular (aral\u0131ktaki minimum, maksimum say\u0131y\u0131 bulma gibi) ise \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda yapmaya uygundur.

Bu veri yap\u0131s\u0131 durumu de\u011fi\u015fmeyen, sabit bir veri \u00fczerinde \u00f6n i\u015flemler yaparak kurulur. Dinamik veriler i\u00e7in kullan\u0131\u015fl\u0131 de\u011fildir. Veri \u00fczerinde herhangi bir de\u011fi\u015fiklik durumda Sparse table tekrardan kurulmal\u0131d\u0131r. Bu da maliyetli bir durumdur.

","tags":["Data Structures","Sparse Table"]},{"location":"data-structures/sparse-table/#yaps-ve-kurulusu","title":"Yap\u0131s\u0131 ve Kurulu\u015fu","text":"

Sparse table iki bouyutlu bir dizi \u015feklinde, \\(\\mathcal{O}(N\\log N)\\) haf\u0131za karma\u015f\u0131kl\u0131\u011f\u0131na sahip bir veri yap\u0131s\u0131d\u0131r. Dizinin her eleman\u0131ndan \\(2\\)'nin kuvvetleri uzakl\u0131ktaki elemanlara kadar olan cevaplar Sparse table'da saklan\u0131r. \\(ST_{x,i}\\), \\(x\\) indeksli elemandan \\(x + 2^i - 1\\) indeksli elemana kadar olan aral\u0131\u011f\u0131n cevab\u0131n\u0131 saklayacak \u015fekilde sparse table kurulur.

// Toplam sorgusu icin kurulmus Sparse Table Yapisi\nconst int n;\nconst int LOG = log2(n);\nint a[n + 1], ST[2 * n][LOG + 1];\n\nvoid build() {\n    for (int i = 1; i <= n; i++) {\n        // [i,i] araliginin cevabi dizinin i indeksli elemanina esittir.\n        ST[i][0] = a[i];\n    }\n\n    for (int i = 1; i <= LOG; i++)\n        for (int j = 1; j <= n; j++) {\n            // [i,i+2^(j)-1] araliginin cevabi\n            // [i,i+2^(j - 1) - 1] araligi ile [i+2^(j - 1),i+2^j-1] araliginin\n            // cevaplarinin birlesmesiyle elde edilir\n            ST[i][j] = ST[i][j - 1] + ST[i + (1 << (j - 1))][j - 1];\n        }\n\n    return;\n}\n
","tags":["Data Structures","Sparse Table"]},{"location":"data-structures/sparse-table/#sorgu-algoritmas","title":"Sorgu Algoritmas\u0131","text":"

Herhangi bir \\([l,r]\\) aral\u0131\u011f\u0131 i\u00e7in sorgu algoritmas\u0131 s\u0131ras\u0131yla \u015fu \u015fekilde \u00e7al\u0131\u015f\u0131r:

  • \\([l,r]\\) aral\u0131\u011f\u0131n\u0131 cevaplar\u0131n\u0131 \u00f6nceden hesaplad\u0131\u011f\u0131m\u0131z aral\u0131klara par\u00e7ala.
    • Sadece \\(2\\)'nin kuvveti uzunlu\u011funda par\u00e7alar\u0131n cevaplar\u0131n\u0131 saklad\u0131\u011f\u0131m\u0131z i\u00e7in aral\u0131\u011f\u0131m\u0131z\u0131 \\(2\\)'nin kuvveti uzunlu\u011funda aral\u0131klara ay\u0131rmal\u0131y\u0131z. \\([l,r]\\) aral\u0131\u011f\u0131n\u0131n uzunlu\u011funun ikilik tabanda yazd\u0131\u011f\u0131m\u0131zda hangi aral\u0131klara par\u00e7alamam\u0131z gerekti\u011fini bulmu\u015f oluruz.
  • Bu aral\u0131klardan gelen cevaplar\u0131 birle\u015ftirerek \\([l,r]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 hesapla.

Herhangi bir aral\u0131\u011f\u0131n uzunlu\u011funun ikilik tabandaki yaz\u0131l\u0131\u015f\u0131ndaki \\(1\\) rakamlar\u0131n\u0131n say\u0131s\u0131 en fazla \\(\\log(N)\\) olabilece\u011finden par\u00e7alayaca\u011f\u0131m\u0131z aral\u0131k say\u0131s\u0131 da en fazla \\(\\log(N)\\) olur. Dolay\u0131s\u0131yla sorgu i\u015flemimiz \\(\\mathcal{O}(\\log N)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda \u00e7al\u0131\u015f\u0131r.

\u00d6rne\u011fin: \\([4,17]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 hesaplamak i\u00e7in algoritmam\u0131z \\([4,17]\\) aral\u0131\u011f\u0131n\u0131 \\([4,11]\\), \\([12,15]\\) ve \\([16,17]\\) aral\u0131klar\u0131na ay\u0131r\u0131r ve bu \\(3\\) aral\u0131ktan gelen cevaplar\u0131 birle\u015ftirerek istenilen cevab\u0131 hesaplar.

// toplam sorgusu\nint query(int l, int r) {\n    int res = 0;\n\n    for (int i = LOG; i >= 0; i--) {\n        // her seferinde uzunlugu r - l + 1 gecmeyecek\n        // en buyuk araligin cevabi ekleyip l'i o araligin sonuna cekiyoruz.\n        if (l + (1 << i) <= r) {\n            res += ST[l][i];\n            l += (1 << i);\n        }\n    }\n\n    return res;\n}\n
","tags":["Data Structures","Sparse Table"]},{"location":"data-structures/sparse-table/#minimum-ve-maksimum-sorgu","title":"Minimum ve Maksimum Sorgu","text":"

Sparse Table veri yap\u0131s\u0131n\u0131n di\u011fer veri yap\u0131lar\u0131ndan farkl\u0131 olarak \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda aral\u0131klarda minimum veya maksimum sorgusu yapabilmesi en avantajl\u0131 \u00f6zelli\u011fidir.

Herhangi bir aral\u0131\u011f\u0131n cevab\u0131n\u0131 hesaplarken bu aral\u0131ktaki herhangi bir eleman\u0131 birden fazla kez de\u011ferlendirmemiz cevab\u0131 etkilemez. Bu durum aral\u0131\u011f\u0131m\u0131z\u0131 \\(2\\)'nin kuvveti uzunlu\u011funda maksimum \\(2\\) adet aral\u0131\u011fa b\u00f6lebilmemize ve bu aral\u0131klar\u0131n cevaplar\u0131n\u0131 \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda birle\u015ftirebilmemize olanak sa\u011flar.

int RMQ(int l, int r) {\n    // log[] dizisinde her sayinin onceden hesapadigimiz log2 degerleri saklidir.\n    int j = log[r - l + 1];\n    return min(ST[l][j], ST[r - (1 << j) + 1][j]);\n}\n

Sparse Table veri yap\u0131s\u0131 ile ilgili \u00f6rnek bir probleme buradan ula\u015fabilirsiniz.

","tags":["Data Structures","Sparse Table"]},{"location":"data-structures/sqrt-decomposition/","title":"SQRT Decomposition","text":"

Square Root Decomposition algoritmas\u0131 dizi \u00fczerinde \\(\\mathcal{O}(\\sqrt{N})\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda sorgu yapabilmemize ve \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda ise de\u011fi\u015fiklik yapabilmemize olanak sa\u011flayan bir veri yaps\u0131d\u0131r.

","tags":["Data Structures","SQRT Decomposition","Square Root Decomposition"]},{"location":"data-structures/sqrt-decomposition/#yaps-ve-kurulusu","title":"Yap\u0131s\u0131 ve Kurulu\u015fu","text":"

Dizinin elemanlar\u0131 her biri yakla\u015f\u0131k \\(\\mathcal{O}(\\sqrt{N})\\) uzunlu\u011funda bloklar halinde par\u00e7alan\u0131r. Her bir blokun cevab\u0131 ayr\u0131 ayr\u0131 hesaplan\u0131r ve bir dizide saklan\u0131r.

Bloklar\u0131n Cevaplar\u0131 \\(21\\) \\(13\\) \\(50\\) \\(32\\) Dizideki Elemanlar \\(3\\) \\(6\\) \\(2\\) \\(10\\) \\(3\\) \\(1\\) \\(4\\) \\(5\\) \\(2\\) \\(7\\) \\(37\\) \\(4\\) \\(11\\) \\(6\\) \\(8\\) \\(7\\) Elemanlar\u0131n \u0130ndeksleri \\(1\\) \\(2\\) \\(3\\) \\(4\\) \\(5\\) \\(6\\) \\(7\\) \\(8\\) \\(9\\) \\(10\\) \\(11\\) \\(12\\) \\(13\\) \\(14\\) \\(15\\) \\(16\\) \u00d6rnek bir dizi \u00fczerinde toplam sorgusu i\u00e7in kurulmu\u015f SQRT Decompostion veri yap\u0131s\u0131.
void build() {\n    for (int i = 1; i <= n; i++) {\n        if (i % sq == 1) { // sq = sqrt(n)\n            t++;           // yeni blok baslangici.\n            st[t] = i;     // t.blok i indisli elemanda baslar.\n        }\n        fn[t] = i;      // t.blokun bitisini i indisli eleman olarak guncelliyoruz.\n        wh[i] = t;      // i indeksli eleman t.blogun icinde.\n        sum[t] += a[i]; // t. blokun cevabina i indeksli elemani ekliyoruz.\n    }\n}\n
","tags":["Data Structures","SQRT Decomposition","Square Root Decomposition"]},{"location":"data-structures/sqrt-decomposition/#sorgu-algoritmas","title":"Sorgu Algoritmas\u0131","text":"

Herhangi bir \\([l,r]\\) aral\u0131\u011f\u0131 i\u00e7in sorgu algoritmas\u0131 s\u0131ras\u0131 ile \u015fu \u015fekilde \u00e7al\u0131\u015f\u0131r:

  1. Cevab\u0131n\u0131 arad\u0131\u011f\u0131m\u0131z aral\u0131\u011f\u0131n tamamen kaplad\u0131\u011f\u0131 bloklar\u0131n cevab\u0131n\u0131 cevab\u0131m\u0131za ekliyoruz.
  2. Tamamen kaplamad\u0131\u011f\u0131 bloklardaki aral\u0131\u011f\u0131m\u0131z\u0131n i\u00e7inde olan elemanlar\u0131 tek tek gezerek cevab\u0131m\u0131za ekliyoruz.

Cevab\u0131n\u0131 arad\u0131\u011f\u0131m\u0131z aral\u0131\u011f\u0131n kapsad\u0131\u011f\u0131 blok say\u0131s\u0131 en fazla \\(\\sqrt{N}\\) olabilece\u011finden \\(1.\\) i\u015flem en fazla \\(\\sqrt{N}\\) kez \u00e7al\u0131\u015f\u0131r. Tamamen kaplamad\u0131\u011f\u0131 ancak baz\u0131 elemanlar\u0131 i\u00e7eren en fazla \\(2\\) adet blok olabilir. (Biri en solda di\u011feri en sa\u011fda olacak \u015fekilde.) Bu \\(2\\) blok i\u00e7in de gezmemiz gereken eleman say\u0131s\u0131 maksimum \\(2\\sqrt{N}\\) oldu\u011fundan bir sorgu i\u015fleminde en fazla \\(3\\sqrt{N}\\) i\u015flem yap\u0131l\u0131r, dolay\u0131s\u0131yla sorgu i\u015flemimiz \\(\\mathcal{O}(\\sqrt{N})\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda cal\u0131\u015f\u0131r.

Bloklar\u0131n Cevaplar\u0131 \\(21\\) \\(13\\) \\(50\\) \\(32\\) Dizideki Elemanlar \\(3\\) \\(6\\) \\(2\\) \\(10\\) \\(3\\) \\(1\\) \\(4\\) \\(5\\) \\(2\\) \\(7\\) \\(37\\) \\(4\\) \\(11\\) \\(6\\) \\(8\\) \\(7\\) Elemanlar\u0131n \u0130ndeksleri \\(1\\) \\(2\\) \\(3\\) \\(4\\) \\(5\\) \\(6\\) \\(7\\) \\(8\\) \\(9\\) \\(10\\) \\(11\\) \\(12\\) \\(13\\) \\(14\\) \\(15\\) \\(16\\) \u00d6rnek dizideki \\([3,13]\\) aral\u0131\u011f\u0131n\u0131n cevab\u0131n\u0131 \\(2.\\) ve \\(3.\\) bloklar\u0131n cevaplar\u0131 ile \\(3,4\\) ve \\(11\\) indeksli elemanlar\u0131n toplanmas\u0131yla elde edilir.
// [l,r] araligindaki elemanlarin toplamini hesaplayan fonksiyon.\nint query(int l, int r) {\n    int res = 0;\n\n    if (wh[l] == wh[r]) { // l ve r ayni blogun icindeyse\n        for (int i = l; i <= r; i++)\n            res += a[i];\n    } else {\n        for (int i = wh[l] + 1; i <= wh[r] - 1; i++)\n            res += sum[i]; // tamamen kapladigimiz bloklarin cevaplarini ekliyoruz.\n\n        // tamamen kaplamadigimiz bloklardaki araligimiz icindeki\n        // elemanlarin cevaplarini ekliyoruz.\n\n        for (int i = st[wh[l]]; i <= fn[wh[l]]; i++)\n            if (i >= l && i <= r)\n                res += a[i];\n\n        for (int i = st[wh[r]]; i <= fn[wh[r]]; i++)\n            if (i >= l && i <= r)\n                res += a[i];\n    }\n\n    return res;\n}\n
","tags":["Data Structures","SQRT Decomposition","Square Root Decomposition"]},{"location":"data-structures/sqrt-decomposition/#eleman-guncelleme-algoritmas","title":"Eleman G\u00fcncelleme Algoritmas\u0131","text":"

Herhangi bir eleman\u0131n de\u011ferini g\u00fcncellerken o eleman\u0131 i\u00e7eren blokun de\u011ferini g\u00fcncellememiz yeterli olacakt\u0131r. Dolay\u0131s\u0131yla g\u00fcncelleme i\u015flemimimiz \\(\\mathcal{O}(1)\\) zaman karma\u015f\u0131kl\u0131\u011f\u0131nda \u00e7al\u0131\u015f\u0131r.

void update(int x, int val) {\n    // x indeksli elemanin yeni degerini val degerine esitliyoruz.\n    sum[wh[x]] -= a[x];\n    a[x] = val;\n    sum[wh[x]] += a[x];\n}\n

SQRT Decomposition veri yap\u0131s\u0131 ile ilgili \u00f6rnek bir probleme buradan ula\u015fabilirsiniz.

","tags":["Data Structures","SQRT Decomposition","Square Root Decomposition"]},{"location":"data-structures/stack/","title":"Stack","text":"

Stack veri yap\u0131s\u0131nda elemanlar yap\u0131ya son giren ilk \u00e7\u0131kar (LIFO) kural\u0131na uygun olacak \u015fekilde saklan\u0131r. Bu veri yap\u0131s\u0131nda uygulayabildi\u011fimiz i\u015flemler:

  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcne eleman ekleme.
  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcndeki elemana eri\u015fim.
  • Veri yap\u0131s\u0131n\u0131n en \u00fcst\u00fcndeki eleman\u0131 silme.
  • Veri yap\u0131s\u0131n\u0131n bo\u015f olup olmad\u0131\u011f\u0131n\u0131n kontr\u00f6l\u00fc.

C++ dilindeki STL k\u00fct\u00fcphanesinde bulunan haz\u0131r stack yap\u0131s\u0131n\u0131n kullan\u0131m\u0131 a\u015fa\u011f\u0131daki gibidir:

int main() {\n    stack<int> st;\n    cout << st.empty() << endl; // Ilk bashta Stack bosh oldugu icin burada True donecektir.\n    st.push(5);                 // Stack'in en ustune 5'i ekler. Stack'in yeni hali: {5}\n    st.push(7);                 // Stack'in en ustune 7'yi ekler. Stack'in yeni hali: {7, 5}\n    st.push(6);                 // Stack'in en ustune 6'yi ekler. Stack'in yeni hali : {6, 7, 5}\n    st.pop();                   // Stack'in en ustundeki elemani siler. Stack'in yeni hali : {7, 5}\n    st.push(1);                 // Stack'in en ustune 1'i ekler. Stack'in yeni hali : {1, 7, 5}\n    cout << st.top() << endl;   // Stack'in en ustundeki elemana erisir. Ekrana 1 yazirir.\n    cout << st.empty() << endl; // Burada Stack bosh olmadigindan oturu False donecektir.\n}\n
","tags":["Data Structures","Stack"]},{"location":"data-structures/trie/","title":"Trie","text":"

Trie is an efficient information reTrieval data structure. Using Trie, search complexities can be brought to optimal limit (key length). If we store keys in binary search tree, a well balanced BST will need time proportional to \\(M \\times log N\\), where \\(M\\) is maximum string length and \\(N\\) is number of keys in tree. Using Trie, we can search the key in \\(\\mathcal{O}(M)\\) time. However the penalty is on Trie storage requirements (Please refer Applications of Trie for more details)

Trie Structure. https://www.geeksforgeeks.org/wp-content/uploads/Trie.png

Every node of Trie consists of multiple branches. Each branch represents a possible character of keys. We need to mark the last node of every key as end of word node. A Trie node field isEndOfWord is used to distinguish the node as end of word node. A simple structure to represent nodes of English alphabet can be as following,

// Trie node\nclass TrieNode {\n   public:\n    TrieNode *children[ALPHABET_SIZE];\n    bool isEndOfWord;\n    TrieNode() {\n        isEndOfWord = false;\n        for (int i = 0; i < ALPHABET SIZE; i++)\n            children[i] = NULL;\n    }\n};\n
","tags":["Data Structures","Trie"]},{"location":"data-structures/trie/#insertion","title":"Insertion","text":"

Inserting a key into Trie is simple approach. Every character of input key is inserted as an individual Trie node. Note that the children is an array of pointers (or references) to next level Trie nodes. The key character acts as an index into the array children. If the input key is new or an extension of existing key, we need to construct non-existing nodes of the key, and mark end of word for last node. If the input key is prefix of existing key in Trie, we simply mark the last node of key as end of word. The key length determines Trie depth.

void insert(struct TrieNode *root, string key) {\n    struct TrieNode *pCrawl = root;\n    for (int i = 0; i < key.length(); i++) {\n        int index = key[i] - 'a';\n        if (!pCrawl->children[index])\n            pCrawl->children[index] = new TrieNode;\n        pCrawl = pCrawl->children[index];\n    }\n    pCrawl->isEndOfWord = true;\n}\n
","tags":["Data Structures","Trie"]},{"location":"data-structures/trie/#search","title":"Search","text":"

Searching for a key is similar to insert operation, however we only compare the characters and move down. The search can terminate due to end of string or lack of key in Trie. In the former case, if the isEndofWord field of last node is true, then the key exists in Trie. In the second case, the search terminates without examining all the characters of key, since the key is not present in Trie.

bool search(struct TrieNode *root, string key) {\n    TrieNode *pCrawl = root;\n    for (int i = 0; i < key.length(); i++) {\n        int index = key[i] - 'a';\n        if (!pCrawl->children[index])\n            return false;\n        pCrawl = pCrawl->children[index];\n    }\n    return (pCrawl != NULL && pCrawl->isEndOfWord);\n}\n

Insert and search costs \\(\\mathcal{O}(\\text{key\\_length})\\). However the memory requirements of Trie high. It is \\(\\mathcal{O}(\\text{ALPHABET SIZE} \\times \\text{key\\_length} \\times N)\\) where \\(N\\) is number of keys in Trie. There are efficient representation of trie nodes (e.g. compressed trie, ternary search tree, etc.) to minimize memory requirements of trie.

","tags":["Data Structures","Trie"]},{"location":"dynamic-programming/","title":"Dynamic Programming","text":"

Editor: Halil \u00c7etiner

Reviewers: Onur Y\u0131ld\u0131z

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#introduction","title":"Introduction","text":"

Next section is about the Greedy Algorithms and Dynamic Programming. It will be quite a generous introduction to the concepts and will be followed by some common problems.

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#greedy-algorithms","title":"Greedy Algorithms","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#dynamic-programming","title":"Dynamic Programming","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#common-dp-problems","title":"Common DP Problems","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#bitmask-dp","title":"Bitmask DP","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#dp-on-rooted-trees","title":"DP on Rooted Trees","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#dp-on-directed-acyclic-graphs","title":"DP on Directed Acyclic Graphs","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#digit-dp","title":"Digit DP","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#walk-counting-using-matrix-exponentiation","title":"Walk Counting using Matrix Exponentiation","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#tree-child-sibling-notation","title":"Tree Child-Sibling Notation","text":"","tags":["Dynamic Programming"]},{"location":"dynamic-programming/#references","title":"References","text":"
  1. \"Competitive Programmer\u2019s Handbook\" by Antti Laaksonen - Draft July 3, 2018
  2. Wikipedia - Dynamic Programming
  3. Topcoder - Competitive Programming Community / Dynamic Programming from Novice to Advanced
  4. Hacker Earth - Dynamic Programming
  5. Geeks for Geeks - Dynamic Programming
","tags":["Dynamic Programming"]},{"location":"dynamic-programming/bitmask-dp/","title":"Bitmask DP","text":"","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#what-is-bitmask","title":"What is Bitmask?","text":"

Let\u2019s say that we have a set of objects. How can we represent a subset of this set? One way is using a map and mapping each object with a Boolean value indicating whether the object is picked. Another way is, if the objects can be indexed by integers, we can use a Boolean array. However, this can be slow due to the operations of the map and array structures. If the size of the set is not too large (less than 64), a bitmask is much more useful and convenient.

An integer is a sequence of bits. Thus, we can use integers to represent a small set of Boolean values. We can perform all the set operations using bit operations. These bit operations are faster than map and array operations, and the time difference may be significant in some problems.

In a bitmask, the \\( i \\)-th bit from the right represents the \\( i \\)-th object. For example, let \\( A = \\{1, 2, 3, 4, 5\\} \\), we can represent \\( B = \\{1, 2, 4\\} \\) with the 11 (01011) bitmask.

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#bitmask-operations","title":"Bitmask Operations","text":"
  • Add the \\( i \\)-th object to the subset: Set the \\( i \\)-th bit to 1: \\( \\text{mask } = \\text{mask } | \\text{ } (1 << i) \\)

  • Remove the \\( i \\)-th object from the subset: Set the \\( i \\)-th bit to 0: \\( \\text{mask } = \\text{mask } \\& \\sim (1 << i) \\)

  • Check whether the \\( i \\)-th object is in the subset: Check if the \\( i \\)-th bit is set: \\( \\text{mask } \\& \\text{ } (1 << i) \\). If the expression is equal to 1, the \\( i \\)-th object is in the subset. If the expression is equal to 0, the \\( i \\)-th object is not in the subset.

  • Toggle the existence of the \\( i \\)-th object: XOR the \\( i \\)-th bit with 1, turning 1 into 0 and 0 into 1: \\( \\text{mask} = \\text{mask}\\) ^ \\( (1 << i) \\)

  • Count the number of objects in the subset: Use a built-in function to count the number of 1\u2019s in an integer variable: __builtin_popcount(mask) for integers or __builtin_popcountll(mask) for long longs.

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#iterating-over-subsets","title":"Iterating Over Subsets","text":"
  • Iterate through all subsets of a set with size \\( n \\): \\( \\text{for (int x = 0; x < (1 << n); ++x)} \\)

  • Iterate through all subsets of a subset with the mask \\( y \\): \\( \\text{for (int x = y; x > 0; x = (y \\& (x \u2212 1)))} \\)

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#task-assignment-problem","title":"Task Assignment Problem","text":"

There are \\( N \\) people and \\( N \\) tasks, and each task is going to be allocated to a single person. We are also given a matrix cost of size \\( N \\times N \\), where cost[i][j] denotes how much a person is going to charge for a task. We need to assign each task to a person such that the total cost is minimized. Note that each task is allocated to only one person, and each person is allocated only one task.

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#naive-approach","title":"Naive Approach:","text":"

Try \\( N! \\) possible assignments. Time complexity: \\( O(N!) \\).

","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#dp-approach","title":"DP Approach:","text":"

For every possible subset, find the new subsets that can be generated from it and update the DP array. Here, we use bitmasking to represent subsets and iterate over them. Time complexity: \\( O(2^N \\times N) \\).

Note: The Hungarian Algorithm solves this problem in \\( O(N^3) \\) time complexity.

Solution code for DP approach:

for (int mask = 0; mask < (1 << n); ++mask)\n{\n    for (int j = 0; j < n; ++j)\n    {\n        if((mask & (1 << j)) == 0) // jth task not assigned\n        {\n            dp[mask | (1 << j)] = min(dp[mask | (1 << j)], dp[mask] + cost[__builtin_popcount(mask)][j])\n        }\n    }\n}\n// after this operation our answer stored in dp[(1 << N) - 1]\n
","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/bitmask-dp/#references","title":"References","text":"
  • Bitmask Tutorial on HackerEarth
","tags":["Dynamic Programming","Bitmask DP"]},{"location":"dynamic-programming/common-dp-problems/","title":"Common Dynamic Programming Problems","text":"","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#coin-problem","title":"Coin Problem","text":"

As discussed earlier, the Greedy approach doesn\u2019t work all the time for the coin problem. For example, if the coins are {4, 3, 1} and the target sum is \\(6\\), the greedy algorithm produces the solution \\(4+1+1\\), while the optimal solution is \\(3+3\\). This is where Dynamic Programming (DP) helps.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#solution","title":"Solution","text":"","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#approach","title":"Approach:","text":"
  1. If \\( V == 0 \\), then 0 coins are required.
  2. If \\( V > 0 \\), compute \\( \\text{minCoins}(coins[0..m-1], V) = \\min \\{ 1 + \\text{minCoins}(V - \\text{coin}[i]) \\} \\) for all \\( i \\) where \\( \\text{coin}[i] \\leq V \\).
def minCoins(coins, target):\n    # base case\n    if (V == 0):\n        return 0\n\n    n = len(coins)\n    # Initialize result\n    res = sys.maxsize\n\n    # Try every coin that has smaller value than V\n    for i in range(0, n):\n        if (coins[i] <= target):\n            sub_res = minCoins(coins, target-coins[i])\n\n    # Check for INT_MAX to avoid overflow and see if\n    # result can minimized\n    if (sub_res != sys.maxsize and sub_res + 1 < res):\n        res = sub_res + 1\n\n    return res\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#knapsack-problem","title":"Knapsack Problem","text":"

We are given the weights and values of \\( n \\) items, and we are to put these items in a knapsack of capacity \\( W \\) to get the maximum total value. In other words, we are given two integer arrays val[0..n-1] and wt[0..n-1], which represent the values and weights associated with \\( n \\) items. We are also given an integer \\( W \\), which represents the knapsack's capacity. Our goal is to find out the maximum value subset of val[] such that the sum of the weights of this subset is smaller than or equal to \\( W \\). We cannot break an item; we must either pick the complete item or leave it.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#approach_1","title":"Approach:","text":"

There are two cases for every item: 1. The item is included in the optimal subset. 2. The item is not included in the optimal subset.

The maximum value that can be obtained from \\( n \\) items is the maximum of the following two values: 1. Maximum value obtained by \\( n-1 \\) items and \\( W \\) weight (excluding the \\( n \\)-th item). 2. Value of the \\( n \\)-th item plus the maximum value obtained by \\( n-1 \\) items and \\( W - \\text{weight of the } n \\)-th item (including the \\( n \\)-th item).

If the weight of the \\( n \\)-th item is greater than \\( W \\), then the \\( n \\)-th item cannot be included, and case 1 is the only possibility.

For example:

  • Knapsack max weight: \\( W = 8 \\) units
  • Weight of items: \\( \\text{wt} = \\{3, 1, 4, 5\\} \\)
  • Values of items: \\( \\text{val} = \\{10, 40, 30, 50\\} \\)
  • Total items: \\( n = 4 \\)

The sum \\( 8 \\) is possible with two combinations: {3, 5} with a total value of 60, and {1, 3, 4} with a total value of 80. However, a better solution is {1, 5}, which has a total weight of 6 and a total value of 90.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#recursive-solution","title":"Recursive Solution","text":"
def knapSack(W , wt , val , n):\n\n    # Base Case\n    if (n == 0 or W == 0):\n        return 0\n\n    # If weight of the nth item is more than Knapsack of capacity\n    # W, then this item cannot be included in the optimal solution\n    if (wt[n-1] > W):\n        return knapSack(W, wt, val, n - 1)\n\n    # return the maximum of two cases:\n    # (1) nth item included\n    # (2) not included\n    else:\n        return max(val[n-1] + knapSack(W - wt[n - 1], wt, val, n - 1), knapSack(W, wt, val, n - 1))\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#dynamic-programming-solution","title":"Dynamic Programming Solution","text":"

It should be noted that the above function computes the same subproblems again and again. Time complexity of this naive recursive solution is exponential \\(2^n\\). Since suproblems are evaluated again, this problem has Overlapping Subproblems property. Like other typical Dynamic Programming(DP) problems, recomputations of same subproblems can be avoided by constructing a temporary array \\(K[][]\\) in bottom up manner. Following is Dynamic Programming based implementation.

def knapSack(W, wt, val, n):\n    K = [[0 for x in range(W + 1)] for x in range(n + 1)]\n\n    # Build table K[][] in bottom up manner\n    for (i in range(n + 1)):\n        for (w in range(W + 1)):\n            if (i == 0 or w == 0):\n                K[i][w] = 0\n            elif (wt[i - 1] <= w):\n                K[i][w] = max(val[i - 1] + K[i - 1][w - wt[i - 1]], K[i - 1][w])\n            else:\n                K[i][w] = K[i - 1][w]\n\n    return K[n][W]\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#longest-common-substring-lcs-problem","title":"Longest Common Substring (LCS) Problem","text":"

We are given two strings \\( X \\) and \\( Y \\), and our task is to find the length of the longest common substring.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#sample-case","title":"Sample Case:","text":"
  • Input: \\( X = \"inzvahackerspace\" \\), \\( Y = \"spoilerspoiler\" \\)
  • Output: 4

The longest common substring is \"ersp\" and is of length 4.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#approach_2","title":"Approach:","text":"

Let \\( m \\) and \\( n \\) be the lengths of the first and second strings, respectively. A simple solution is to consider all substrings of the first string one by one and check if they are substrings of the second string. Keep track of the maximum-length substring. There will be \\( O(m^2) \\) substrings, and checking if one is a substring of the other will take \\( O(n) \\) time. Thus, the overall time complexity is \\( O(n \\cdot m^2) \\).

Dynamic programming can reduce this to \\( O(m \\cdot n) \\). The idea is to find the length of the longest common suffix for all substrings of both strings and store these lengths in a table. The longest common suffix has the following property:

[ LCSuff(X, Y, m, n) = LCSuff(X, Y, m-1, n-1) + 1 \\text{ if } X[m-1] = Y[n-1] ] Otherwise, \\( LCSuff(X, Y, m, n) = 0 \\).

The maximum length of the Longest Common Suffix is the Longest Common Substring.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#dp-iterative","title":"DP - Iterative","text":"
def LCSubStr(X, Y):\n    m = len(X)\n    n = len(Y)\n\n    # Create a table to store lengths of\n    # longest common suffixes of substrings.\n    # Note that LCSuff[i][j] contains the\n    # length of longest common suffix of\n    # X[0...i\u22121] and Y[0...j\u22121]. The first\n    # row and first column entries have no\n    # logical meaning, they are used only\n    # for simplicity of the program.\n\n    # LCSuff is the table with zero\n    # value initially in each cell\n    LCSuff = [[0 for k in range(n+1)] for l in range(m + 1)]\n\n    # To store the length of\n    # longest common substring\n    result = 0\n\n    # Following steps to build\n    # LCSuff[m+1][n+1] in bottom up fashion\n    for (i in range(m + 1)):\n        for (j in range(n + 1)):\n    if (i == 0 or j == 0):\n                LCSuff[i][j] = 0\n            elif (X[i - 1] == Y[j - 1]):\n                LCSuff[i][j] = LCSuff[i - 1][j - 1] + 1\n                result = max(result, LCSuff[i][j])\n            else:\n                LCSuff[i][j] = 0\n    return result\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#dp-recursive","title":"DP - Recursive","text":"
def lcs(int i, int j, int count):\n    if (i == 0 or j == 0):\n        return count\n\n    if (X[i - 1] == Y[j - 1]):\n        count = lcs(i - 1, j - 1, count + 1)\n\n    count = max(count, max(lcs(i, j - 1, 0), lcs(i - 1, j, 0)))\n    return count\n
","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#longest-increasing-subsequence-lis-problem","title":"Longest Increasing Subsequence (LIS) Problem","text":"

The Longest Increasing Subsequence (LIS) problem is to find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.

For example, given the array \\([0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]\\), the longest increasing subsequence has a length of 6, and it is {0, 2, 6, 9, 11, 15}.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/common-dp-problems/#solution_1","title":"Solution","text":"

A naive, brute-force approach is to generate every possible subsequence, check for monotonicity, and keep track of the longest one. However, this is prohibitively expensive, as generating each subsequence takes \\( O(2^N) \\) time.

Instead, we can use recursion to solve this problem and then optimize it with dynamic programming. We assume that we have a function that gives us the length of the longest increasing subsequence up to a certain index.

The base cases are: - The empty list, which returns 0. - A list with one element, which returns 1.

For every index \\( i \\), calculate the longest increasing subsequence up to that point. The result can only be extended with the last element if the last element is greater than \\( \\text{arr}[i] \\), as otherwise, the sequence wouldn\u2019t be increasing.

def longest_increasing_subsequence(arr):\n    if (not arr):\n        return 0\n    if (len(arr) == 1):\n        return 1\n\n    max_ending_here = 0\n    for (i in range(len(arr))):\n        ending_at_i = longest_increasing_subsequence(arr[:i])\n        if (arr[-1] > arr[i - 1] and ending_at_i + 1 > max_ending_here):\n            max_ending_here = ending_at_i + 1\n    return max_ending_here\n

This is really slow due to repeated subcomputations (exponential in time). So, let\u2019s use dynamic programming to store values to recompute them for later.

We\u2019ll keep an array A of length N, and A[i] will contain the length of the longest increasing subsequence ending at i. We can then use the same recurrence but look it up in the array instead:

def longest_increasing_subsequence(arr):\n    if (not arr):\n        return 0\n    cache = [1] * len(arr)\n    for (i in range(1, len(arr))):\n        for (j in range(i)):\n            if (arr[i] > arr[j]):\n                cache[i] = max(cache[i], cache[j] + 1)\n    return max(cache)\n

This now runs in \\( O(N^2) \\) time and \\( O(N) \\) space.

","tags":["Dynamic Programming","Common Dynamic Programming Problems"]},{"location":"dynamic-programming/digit-dp/","title":"Digit DP","text":"

Problems that require the calculation of how many numbers there are between two values (say, \\( A \\) and \\( B \\)) that satisfy a particular property can be solved using digit dynamic programming (Digit DP).

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#how-to-work-on-digits","title":"How to Work on Digits","text":"

While constructing our numbers recursively (from the left), we need a method to check if our number is still smaller than the given boundary number. To achieve this, we keep a variable called \"strict\" while branching, which limits our ability to select digits that are larger than the corresponding digit of the boundary number.

Let\u2019s suppose the boundary number is \\( A \\). We start filling the number from the left (most significant digit) and set strict to true, meaning we cannot select any digit larger than the corresponding digit of \\( A \\). As we branch:

  • Values less than the corresponding digit of \\( A \\) will now be non-strict (strict = false) because we guarantee that the number will be smaller than \\( A \\) after this point.
  • For values equal to the corresponding digit of \\( A \\), the strictness continues to be true.
","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#counting-problem-example","title":"Counting Problem Example","text":"

Problem: How many numbers \\( x \\) are there in the range \\( A \\) to \\( B \\), where the digit \\( d \\) occurs exactly \\( k \\) times in \\( x \\)?

Constraints: \\( A, B < 10^{60}, k < 60 \\).

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#brute-force-approach","title":"Brute Force Approach:","text":"

The brute-force solution would involve iterating over all the numbers in the range \\([A, B]\\) and counting the occurrences of the digit \\( d \\) one by one for each number. This has a time complexity of \\( O(N \\log_{10}(N)) \\), which is too large for such constraints, and we need a more efficient approach.

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#recursive-approach","title":"Recursive Approach:","text":"

We can recursively fill the digits of our number starting from the leftmost digit. At each step, we branch into 3 possibilities:

  1. Pick a number that is not \\( d \\) and smaller than the corresponding digit of the boundary number.
  2. Pick the digit \\( d \\).
  3. Pick a number that is equal to the corresponding digit of the boundary number.

The depth of recursion is equal to the number of digits in the decimal representation of the boundary number, leading to a time complexity of \\( O(3^{\\log_{10} N}) \\). Although this is better than brute force, it is still not efficient enough.

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#recursive-approach-with-memoization","title":"Recursive Approach with Memoization:","text":"

We can further optimize this approach using memoization. We represent a DP state by \\((\\text{current index}, \\text{current strictness}, \\text{number of } d's)\\), which denotes the number of possible configurations of the remaining digits after picking the current digit. We use a dp[\\log_{10} N][2][\\log_{10} N] array, where each value is computed at most once. Therefore, the worst-case time complexity is \\( O((\\log_{10} N)^2) \\).

Solution Code:

#include <bits/stdc++.h>\nusing namespace std;\n#define ll long long\nll A, B, d, k, dg; // dg: digit count\nvector <ll> v; // digit vector\nll dp[25][2][25];\nvoid setup(ll a)\n{\n    memset(dp,0,sizeof dp);\n    v.clear();\n    ll tmp = a;\n    while(tmp)\n    {\n        v.push_back(tmp%10);\n        tmp/=10;\n    }\n    dg = (ll)v.size();\n    reverse(v.begin(), v.end());\n}\n\nll rec(int idx, bool strict, int count)\n{\n    if(dp[idx][strict][count]) return dp[idx][strict][count];\n    if(idx == dg or count > k) return (count == k);\n    ll sum = 0;\n    if(strict)\n    {\n        // all <v[idx] if d is included -1\n        sum += rec(idx + 1, 0, count) * (v[idx] - (d < v[idx]));\n        // v[idx], if d==v[idx] send count+1\n        sum += rec(idx + 1, 1, count + (v[idx] == d) );\n        if(d < v[idx])\n        sum += rec(idx + 1, 0, count + 1); // d\n    }\n    else\n    {\n        sum += rec(idx + 1, 0, count) * (9); // other than d (10 - 1)\n        sum += rec(idx + 1, 0, count + 1); // d\n    }\n    return dp[idx][strict][count] = sum;\n}\n\nint main()\n{\n    cin >> A >> B >> d >> k;\n    setup(B);\n    ll countB = rec(0, 1, 0); //countB is answer of [0..B]\n    setup(A - 1);\n    ll countA = rec(0, 1, 0); //countA is answer of [0..A-1]\n    cout << fixed << countB - countA << endl; //difference gives us [A..B]\n}\n
","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/digit-dp/#references","title":"References","text":"
  • Digit DP on Codeforces

  • Digit DP on HackerRank

","tags":["Dynamic Programming","Digit DP"]},{"location":"dynamic-programming/dp-on-dags/","title":"DP on Directed Acyclic Graphs (DAGs)","text":"

As we know, the nodes of a directed acyclic graph (DAG) can be sorted topologically, and DP can be implemented efficiently using this topological order.

First, we can find the topological order with a topological sort in \\( O(N) \\) time complexity. Then, we can find the \\( dp(V) \\) values in topological order, where \\( V \\) is a node in the DAG and \\( dp(V) \\) is the answer for node \\( V \\). The answer and implementation will differ depending on the specific problem.

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#converting-a-dp-problem-into-a-directed-acyclic-graph","title":"Converting a DP Problem into a Directed Acyclic Graph","text":"

Many DP problems can be converted into a DAG. Let\u2019s explore why this is the case.

While solving a DP problem, when we process a state, we evaluate it by considering all possible previous states. To do this, all of the previous states must be processed before the current state. From this perspective, some states depend on other states, forming a DAG structure.

However, note that some DP problems cannot be converted into a DAG and may require hyper-graphs. (For more details, refer to Advanced Dynamic Programming in Semiring and Hypergraph Frameworks).

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#example-problem","title":"Example Problem:","text":"

There are \\( N \\) stones numbered \\( 1, 2, ..., N \\). For each \\( i \\) ( \\( 1 \\leq i \\leq N \\) ), the height of the \\( i \\)-th stone is \\( h_i \\). There is a frog initially on stone 1. The frog can jump to stone \\( i+1 \\) or stone \\( i+2 \\). The cost of a jump from stone \\( i \\) to stone \\( j \\) is \\( | h_i \u2212 h_j | \\). Find the minimum possible cost to reach stone \\( N \\).

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#solution","title":"Solution:","text":"

We define \\( dp[i] \\) as the minimum cost to reach the \\( i \\)-th stone. The answer will be \\( dp[N] \\). The recurrence relation is defined as:

\\[ dp[i] = \\min(dp[i\u22121] + |h_i \u2212 h_{i\u22121}|, dp[i\u22122] + |h_i \u2212 h_{i\u22122}|) \\]

For \\( N = 5 \\), we can see that to calculate \\( dp[5] \\), we need to calculate \\( dp[4] \\) and \\( dp[3] \\). Similarly:

  • \\( dp[4] \\) depends on \\( dp[3] \\) and \\( dp[2] \\),
  • \\( dp[3] \\) depends on \\( dp[2] \\) and \\( dp[1] \\),
  • \\( dp[2] \\) depends on \\( dp[1] \\).

These dependencies form a DAG, where the nodes represent the stones, and the edges represent the transitions between them based on the jumps.

graph LR\n    A(dp_1) --> B(dp_2);\n    A --> C(dp_3);\n    B --> D(dp_4);\n    B --> E(dp_5);\n    C --> D;\n    D --> E;
","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#dp-on-directed-acyclic-graph-problem","title":"DP on Directed Acyclic Graph Problem","text":"

Given a DAG with \\( N \\) nodes and \\( M \\) weighted edges, find the longest path in the DAG.

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#complexity","title":"Complexity:","text":"

The time complexity for this problem is \\( O(N + M) \\), where \\( N \\) is the number of nodes and \\( M \\) is the number of edges.

Solution Code:

// topological sort is not written here so we will take tp as it is already sorted\n// note that tp is reverse topologically sorted\n// vector <int> tp\n// n , m and vector <pair<int,int>> adj is given.Pair denotes {node,weight}.\n// flag[] denotes whether a node is processed or not.Initially all zero.\n// dp[] is DP array.Initially all zero.\n\nfor (int i = 0; i < (int)tp.size(); ++i)//processing in order\n{\n    int curNode = tp[i];\n\n    for (auto v : adj[curNode]) //iterate through all neighbours\n        if(flag[v.first]) //if a neighbour is already processed\n            dp[curNode] = max(dp[curNode] , dp[v.first] + v.second);\n\n    flag[curNode] = 1;\n}\n//answer is max(dp[1..n])\n
","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-dags/#references","title":"References","text":"
  • NOI IOI training week-5

  • DP on Graphs MIT

","tags":["Dynamic Programming","DP on Directed Acyclic Graphs (DAGs)"]},{"location":"dynamic-programming/dp-on-rooted-trees/","title":"DP on Rooted Trees","text":"

In dynamic programming (DP) on rooted trees, we define functions for the nodes of the tree, which are calculated recursively based on the children of each node. One common DP state is usually associated with a node \\(i\\), representing the sub-tree rooted at node \\(i\\).

","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#problem","title":"Problem","text":"

Given a tree \\( T \\) of \\( N \\) (1-indexed) nodes, where each node \\( i \\) has \\( C_i \\) coins attached to it, the task is to choose a subset of nodes such that no two adjacent nodes (nodes directly connected by an edge) are chosen, and the sum of coins attached to the chosen subset is maximized.

","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#approach","title":"Approach:","text":"

We define two functions, \\( dp1(V) \\) and \\( dp2(V) \\), as follows:

  • \\( dp1(V) \\): The optimal solution for the sub-tree of node \\( V \\) when node \\( V \\) is included in the answer.
  • \\( dp2(V) \\): The optimal solution for the sub-tree of node \\( V \\) when node \\( V \\) is not included in the answer.

The final answer is the maximum of these two cases:

\\[ \\text{max}(dp1(V), dp2(V)) \\]

","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#recursive-definitions","title":"Recursive Definitions:","text":"
  • \\( dp1(V) = C_V + \\sum_{i=1}^{n} dp2(v_i) \\), where \\( n \\) is the number of children of node \\( V \\), and \\( v_i \\) is the \\( i \\)-th child of node \\( V \\). This represents the scenario where node \\( V \\) is included in the chosen subset, so none of its children can be selected.

  • \\( dp2(V) = \\sum_{i=1}^{n} \\text{max}(dp1(v_i), dp2(v_i)) \\). This represents the scenario where node \\( V \\) is not included, so the optimal solution for each child \\( v_i \\) can either include or exclude that child.

","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#complexity","title":"Complexity:","text":"

The time complexity for this approach is \\( O(N) \\), where \\( N \\) is the number of nodes in the tree. This is because the solution involves a depth-first search (DFS) traversal of the tree, and each node is visited only once.

//pV is parent of V\nvoid dfs(int V, int pV)\n{\n    //base case:\n    //when dfs reaches a leaf it finds dp1 and dp2 and does not branch again.\n\n    //for storing sums of dp1 and max(dp1, dp2) for all children of V\n    int sum1 = 0, sum2 = 0;\n\n    //traverse over all children\n    for (auto v : adj[V])\n    {\n        if (v == pV)\n            continue;\n        dfs(v, V);\n        sum1 += dp2[v];\n        sum2 += max(dp1[v], dp2[v]);\n    }\n\n    dp1[V] = C[V] + sum1;\n    dp2[V] = sum2;\n}\n//Nodes are 1-indexed, therefore our answer stored in dp1[1] and dp2[1]\n//for the answer we take max(dp1[1],dp2[1]) after calling dfs(1,0).\n
","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dp-on-rooted-trees/#references","title":"References","text":"
  • DP on Tree on CodeForces
","tags":["Dynamic Programming","DP on Rooted Trees"]},{"location":"dynamic-programming/dynamic-programming/","title":"Dynamic Programming","text":"

Dynamic programming (DP) is a technique used to avoid computing the same sub-solution multiple times in a recursive algorithm. A sub-solution of the problem is constructed from the previously found ones. DP solutions have a polynomial complexity, which ensures a much faster running time than other techniques like backtracking or brute-force.

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#memoization-top-down","title":"Memoization - Top Down","text":"

Memoization ensures that a method doesn\u2019t run for the same inputs more than once by keeping a record of the results for the given inputs (usually in a hash map).

To avoid duplicate work caused by recursion, we can use a cache that maps inputs to outputs. The approach involves:

  • Checking the cache to see if we can avoid computing the answer for any given input.
  • Saving the results of any calculations to the cache.

Memoization is a common strategy for dynamic programming problems where the solution is composed of solutions to the same problem with smaller inputs, such as the Fibonacci problem.

Another strategy for dynamic programming is the bottom-up approach, which is often cleaner and more efficient.

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#bottom-up","title":"Bottom-Up","text":"

The bottom-up approach avoids recursion, saving the memory cost associated with building up the call stack. It \"starts from the beginning\" and works towards the final solution, whereas a recursive algorithm often \"starts from the end and works backwards.\"

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#an-example-fibonacci","title":"An Example - Fibonacci","text":"

Let\u2019s start with a well-known example: finding the \\(n\\)-th Fibonacci number. The Fibonacci sequence is defined as:

\\[ F_n = F_{n\u22121} + F_{n\u22122}, \\quad \\text{with } F_0 = 0 \\text{ and } F_1 = 1 \\]

There are several approaches to solving this problem:

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#recursion","title":"Recursion","text":"

In a recursive approach, the function calls itself to compute the previous two Fibonacci numbers until reaching the base cases.

def fibonacci(n):\n    if (n == 0):\n        return 0\n    if (n == 1):\n        return 1\n\n    return fibonacci(n - 1) + fibonacci(n - 2)\n
","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#dynamic-programming","title":"Dynamic Programming","text":"
  • Top-Down - Memoization: Recursion leads to unnecessary repeated calculations. Memoization solves this by caching the results of previously computed Fibonacci numbers, so they don't have to be recalculated.
cache = {}\n\ndef fibonacci(n):\n    if (n == 0):\n        return 0\n    if (n == 1):\n        return 1\n    if (n in cache):\n        return cache[n]\n\n    cache[n] = fibonacci(n - 1) + fibonacci(n - 2)\n\n    return cache[n]\n
Visualization of Recursive Memoization
  • Bottom-Up: The bottom-up approach eliminates recursion by computing the Fibonacci numbers in order, starting from the base cases and building up to the desired value.
cache = {}\n\ndef fibonacci(n):\n    cache[0] = 0\n    cache[1] = 1\n\n    for (i in range(2, n + 1)):\n        cache[i] = cache[i - 1] + cache[i - 2]\n\n    return cache[n]\n

Additionally, this approach can be optimized further by using constant space and only storing the necessary partial results along the way.

def fibonacci(n):\n    fib_minus_2 = 0\n    fib_minus_1 = 1\n\n    for (i in range(2, n + 1)):\n        fib = fib_minus_1 + fib_minus_2\n        fib_minus_1, fib_minus_2 = fib, fib_minus_1\n\n    return fib\n
","tags":["Dynamic Programming"]},{"location":"dynamic-programming/dynamic-programming/#how-to-apply-dynamic-programming","title":"How to Apply Dynamic Programming?","text":"

To apply dynamic programming, follow these steps:

  • Find the recursion in the problem: Identify how the problem can be broken down into smaller subproblems.
  • Top-down approach: Store the result of each subproblem in a table to avoid recomputation.
  • Bottom-up approach: Find the correct order to evaluate the results so that partial results are available when needed.

Dynamic programming generally works for problems that have an inherent left-to-right order, such as strings, trees, or integer sequences. If the naive recursive algorithm does not compute the same subproblem multiple times, dynamic programming won't be useful.

","tags":["Dynamic Programming"]},{"location":"dynamic-programming/greedy-algorithms/","title":"Greedy Algorithms","text":"

A greedy algorithm is an algorithm that follows the problem solving heuristic of making the locally optimal choice at each stage with the hope of finding a global optimum. A greedy algorithm never takes back its choices, but directly constructs the final solution. For this reason, greedy algorithms are usually very efficient.

The difficulty in designing greedy algorithms is to find a greedy strategy that always produces an optimal solution to the problem. The locally optimal choices in a greedy algorithm should also be globally optimal. It is often difficult to argue that a greedy algorithm works.

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#coin-problem","title":"Coin Problem","text":"

We are given a value \\( V \\). If we want to make change for \\( V \\) cents, and we have an infinite supply of each of the coins = { \\( C_1, C_2, \\dots, C_m \\) } valued coins (sorted in descending order), what is the minimum number of coins to make the change?

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#solution","title":"Solution","text":"","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#approach","title":"Approach:","text":"
  1. Initialize the result as empty.
  2. Find the largest denomination that is smaller than the amount.
  3. Add the found denomination to the result. Subtract the value of the found denomination from the amount.
  4. If the amount becomes 0, then print the result. Otherwise, repeat steps 2 and 3 for the new value of the amount.

def min_coins(coins, amount):\n    n = len(coins)\n    for i in range(n):\n        while amount >= coins[i]:\n            # while loop is needed since one coin can be used multiple times\n            amount -= coins[i]\n            print(coins[i])\n
For example, if the coins are the euro coins (in cents) \\({200, 100, 50, 20, 10, 5, 2, 1}\\) and the amount is 548, the optimal solution is to select coins \\(200+200+100+20+20+5+2+1\\), whose sum is \\(548\\).

Visualization of the Coin Change Problem

In the general case, the coin set can contain any kind of coins, and the greedy algorithm does not necessarily produce an optimal solution.

We can prove that a greedy algorithm does not work by showing a counterexample where the algorithm gives a wrong answer. In this problem, we can easily find a counterexample: if the coins are \\({6, 5, 2}\\) and the target sum is \\(10\\), the greedy algorithm produces the solution \\(6+2+2\\), while the optimal solution is \\(5+5\\).

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#scheduling","title":"Scheduling","text":"

Many scheduling problems can be solved using greedy algorithms. A classic problem is as follows:

We are given an array of jobs where every job has a deadline and associated profit if the job is finished before the deadline. It is also given that every job takes a single unit of time, thus the minimum possible deadline for any job is 1. How do we maximize total profit if only one job can be scheduled at a time?

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#solution_1","title":"Solution","text":"

A simple solution is to generate all subsets of the given set of jobs and check each subset for feasibility. Keep track of maximum profit among all feasible subsets. The time complexity of this solution is exponential. This is a standard Greedy Algorithm problem.

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#approach_1","title":"Approach:","text":"
  1. Sort all jobs in decreasing order of profit.
  2. Initialize the result sequence as the first job in sorted jobs.
  3. For the remaining \\(n-1\\) jobs:
  4. If the current job can fit in the current result sequence without missing the deadline, add the current job to the result.
  5. Else ignore the current job.
# sample job : ['x', 4, 25] \u2212> [job_id, deadline, profit]\n# jobs: array of 'job's\ndef print_job_scheduling(jobs, t):\n    n = len(jobs)\n\n    # Sort all jobs according to decreasing order of profit\n    for i in range(n):\n        for j in range(n - 1 - i):\n            if jobs[j][2] < jobs[j + 1][2]:\n                jobs[j], jobs[j + 1] = jobs[j + 1], jobs[j]\n\n    # To keep track of free time slots\n    result = [False] * t\n    # To store result (Sequence of jobs)\n    job = ['-1'] * t\n\n    # Iterate through all given jobs\n    for i in range(len(jobs)):\n        # Find a free slot for this job\n        # (Note that we start from the last possible slot)\n        for j in range(min(t - 1, jobs[i][1] - 1), -1, -1):\n            # Free slot found\n            if result[j] is False:\n                result[j] = True\n                job[j] = jobs[i][0]\n                break\n    print(job)\n
","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#tasks-and-deadlines","title":"Tasks and Deadlines","text":"

Let us now consider a problem where we are given \\(n\\) tasks with durations and deadlines, and our task is to choose an order to perform the tasks. For each task, we earn \\(d - x\\) points, where \\(d\\) is the task\u2019s deadline and \\(x\\) is the moment when we finish the task. What is the largest possible total score we can obtain?

For example, suppose the tasks are as follows:

Task Duration Deadline A 4 2 B 3 5 C 2 7 D 4 5

An optimal schedule for the tasks is \\( C, B, A, D \\). In this solution, \\( C \\) yields 5 points, \\( B \\) yields 0 points, \\( A \\) yields -7 points, and \\( D \\) yields -8 points, so the total score is -10.

Interestingly, the optimal solution to the problem does not depend on the deadlines, but a correct greedy strategy is to simply perform the tasks sorted by their durations in increasing order.

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#solution_2","title":"Solution","text":"
  1. Sort all tasks according to increasing order of duration.
  2. Calculate the total points by iterating through all tasks, summing up the difference between the deadlines and the time at which the task is finished.
def order_tasks(tasks):\n    n = len(tasks)\n\n    # Sort all task according to increasing order of duration\n    for (i in range(n)):\n        for (j in range(n - 1 - i)):\n            if (tasks[j][1] > tasks[j + 1][1]):\n                tasks[j], tasks[j + 1] = tasks[j + 1], tasks[j]\n\n    point = 0\n    current_time = 0\n    # Iterate through all given tasks and calculate point\n    for (i in range(len(tasks))):\n        current_time = current_time + tasks[i][1]\n        point = point + (tasks[i][2] - current_time)\n\n    print(point)\n
","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#minimizing-sums","title":"Minimizing Sums","text":"

We are given \\(n\\) numbers and our task is to find a value \\(x\\) that minimizes the sum:

\\[ |a_1 \u2212 x|^c + |a_2 \u2212 x|^c + ... + |a_n \u2212 x|^c \\]

We focus on the cases \\(c = 1\\) and \\(c = 2\\).

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#case-c-1","title":"Case \\(c = 1\\)","text":"

In this case, we should minimize the sum:

\\[ |a_1 \u2212 x| + |a_2 \u2212 x| + ... + |a_n \u2212 x| \\]

For example, if the numbers are \\([1, 2, 9, 2, 6]\\), the best solution is to select \\(x = 2\\), which produces the sum:

\\[ |1 \u2212 2| + |2 \u2212 2| + |9 \u2212 2| + |2 \u2212 2| + |6 \u2212 2| = 12 \\]

In the general case, the best choice for \\(x\\) is the median of the numbers. For instance, the list \\([1, 2, 9, 2, 6]\\) becomes \\([1, 2, 2, 6, 9]\\) after sorting, so the median is 2. The median is an optimal choice because if \\(x\\) is smaller than the median, the sum decreases by increasing \\(x\\), and if \\(x\\) is larger, the sum decreases by lowering \\(x\\). Hence, the optimal solution is \\(x = \\text{median}\\).

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/greedy-algorithms/#case-c-2","title":"Case \\(c = 2\\)","text":"

In this case, we minimize the sum:

\\[ (a_1 \u2212 x)^2 + (a_2 \u2212 x)^2 + ... + (a_n \u2212 x)^2 \\]

For example, if the numbers are \\([1, 2, 9, 2, 6]\\), the best solution is to select \\(x = 4\\), which produces the sum:

\\[ (1 \u2212 4)^2 + (2 \u2212 4)^2 + (9 \u2212 4)^2 + (2 \u2212 4)^2 + (6 \u2212 4)^2 = 46 \\]

In the general case, the best choice for \\(x\\) is the average of the numbers. For the given example, the average is:

\\[ \\frac{(1 + 2 + 9 + 2 + 6)}{5} = 4 \\]

This result can be derived by expressing the sum as:

\\[ n x^2 \u2212 2x(a_1 + a_2 + ... + a_n) + (a_1^2 + a_2^2 + ... + a_n^2) \\]

The last part does not depend on \\(x\\), so we can ignore it. The remaining terms form a function with a parabola opening upwards, and the minimum value occurs at \\(x = \\frac{s}{n}\\), where \\(s\\) is the sum of the numbers, i.e., the average of the numbers.

","tags":["Dynamic Programming","Greedy Algorithms"]},{"location":"dynamic-programming/tree-child-sibling-notation/","title":"Tree Child-Sibling Notation","text":"

In this method, we change the structure of the tree. In a standard tree, each parent node is connected to all of its children. However, in the child-sibling notation, a node stores a pointer to only one of its children. Additionally, the node also stores a pointer to its immediate right sibling.

In this notation, every node has at most 2 children: - Left child (first child), - Right sibling (first sibling).

This structure is called the LCRS (Left Child-Right Sibling) notation. It effectively represents a binary tree, as every node has only two pointers (left and right).

a tree notated with child-sibling notation","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/tree-child-sibling-notation/#why-you-would-use-the-lcrs-notation","title":"Why You Would Use the LCRS Notation","text":"

The primary reason for using LCRS notation is to save memory. In the LCRS structure, less memory is used compared to the standard tree notation.

","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/tree-child-sibling-notation/#when-you-might-use-the-lcrs-notation","title":"When You Might Use the LCRS Notation:","text":"
  • Memory is extremely scarce.
  • Random access to a node\u2019s children is not required.
","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/tree-child-sibling-notation/#possible-cases-for-using-lcrs","title":"Possible Cases for Using LCRS:","text":"
  1. When storing a large multi-way tree in main memory: For example, the phylogenetic tree.

  2. In specialized data structures where the tree is used in specific ways: For example, in the heap data structure, the main operations are:

  3. Removing the root of the tree and processing each of its children,

  4. Joining two trees together by making one tree a child of the other.

These operations can be done efficiently using the LCRS structure, making it convenient for working with heap data structures.

","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/tree-child-sibling-notation/#references","title":"References","text":"
  • LCRS article on Wikipedia

  • Link to the Figure used

  • LCRS possible uses Stackoverflow

","tags":["Dynamic Programming","Tree Child-Sibling Notation"]},{"location":"dynamic-programming/walk-counting-with-matrix/","title":"Walk Counting using Matrix Exponentiation","text":"

Matrix exponentiation can be used to count the number of walks of a given length on a graph.

Let \\( l \\) be the desired walk length, and let \\( A \\) and \\( B \\) be nodes in a graph \\( G \\). If \\( D \\) is the adjacency matrix of \\( G \\), then \\( D^l[A][B] \\) represents the number of walks from node \\( A \\) to node \\( B \\) with length \\( l \\), where \\( D^k \\) denotes the \\( k \\)-th power of the matrix \\( D \\).

","tags":["Dynamic Programming","Walk Counting using Matrix Exponentiation"]},{"location":"dynamic-programming/walk-counting-with-matrix/#explanation","title":"Explanation:","text":"
  • Adjacency Matrix \\( D \\): In the adjacency matrix of a graph, each entry \\( D[i][j] \\) denotes whether there is a direct edge between node \\( i \\) and node \\( j \\). Specifically:
  • \\( D[i][j] = 1 \\) if there is an edge from \\( i \\) to \\( j \\),
  • \\( D[i][j] = 0 \\) otherwise.

  • Matrix Exponentiation: To find the number of walks of length \\( l \\) between nodes \\( A \\) and \\( B \\), we need to compute \\( D^l \\), which is the \\( l \\)-th power of the adjacency matrix \\( D \\). The entry \\( D^l[A][B] \\) will then give the number of walks of length \\( l \\) from node \\( A \\) to node \\( B \\).

graph LR\n    A(2) --> B(1);\n    B --> C(3);\n    C --> A;\n    C --> D(4);\n    D --> C;
D, adjacency matrix of G D^3, 3rd power of the matrix D

From the matrix \\( D^3 \\), we can see that there are 4 total walks of length 3.

Let \\( S \\) be the set of walks, and let \\( w \\) be a walk where \\( w = \\{n_1, n_2, ..., n_k\\} \\) and \\( n_i \\) is the \\( i \\)-th node of the walk. Then:

[ S = {{1, 3, 4, 3}, {3, 4, 3, 2}, {3, 4, 3, 4}, {4, 3, 4, 3}} ] and \\( |S| = 4 \\).

Using fast exponentiation on the adjacency matrix, we can efficiently find the number of walks of length \\( k \\) in \\( O(N^3 \\log k) \\) time, where \\( N \\) is the number of nodes in the graph.

","tags":["Dynamic Programming","Walk Counting using Matrix Exponentiation"]},{"location":"dynamic-programming/walk-counting-with-matrix/#time-complexity-breakdown","title":"Time Complexity Breakdown:","text":"
  • Matrix Multiplication: The \\( O(N^3) \\) time complexity comes from multiplying two \\( N \\times N \\) matrices.
  • Fast Exponentiation: Fast exponentiation reduces the number of multiplications to \\( \\log k \\), resulting in the overall time complexity of \\( O(N^3 \\log k) \\).

This method allows for efficiently calculating the number of walks with any length \\( k \\) in large graphs.

","tags":["Dynamic Programming","Walk Counting using Matrix Exponentiation"]},{"location":"dynamic-programming/walk-counting-with-matrix/#references","title":"References","text":"
  • Walk Counting on Sciencedirect
","tags":["Dynamic Programming","Walk Counting using Matrix Exponentiation"]},{"location":"graph/","title":"Graph","text":"

Editor: Kayacan Vesek

Reviewers: Yasin Kaya

"},{"location":"graph/#introduction","title":"Introduction","text":""},{"location":"graph/#definitions","title":"Definitions","text":""},{"location":"graph/#representing-graphs","title":"Representing Graphs","text":""},{"location":"graph/#tree-traversals","title":"Tree Traversals","text":""},{"location":"graph/#binary-search-tree","title":"Binary Search Tree","text":""},{"location":"graph/#heap","title":"Heap","text":""},{"location":"graph/#depth-first-search","title":"Depth First Search","text":""},{"location":"graph/#breadth-first-search","title":"Breadth First Search","text":""},{"location":"graph/#cycle-finding","title":"Cycle Finding","text":""},{"location":"graph/#bipartite-checking","title":"Bipartite Checking","text":""},{"location":"graph/#union-find","title":"Union Find","text":""},{"location":"graph/#shortest-path","title":"Shortest Path","text":""},{"location":"graph/#minimum-spanning-tree","title":"Minimum Spanning Tree","text":""},{"location":"graph/#topological-sort","title":"Topological Sort","text":""},{"location":"graph/#bridges-and-articulation-points","title":"Bridges and Articulation Points","text":""},{"location":"graph/#strong-connectivity-and-biconnectivity","title":"Strong Connectivity and Biconnectivity","text":""},{"location":"graph/#strongly-connected-components","title":"Strongly Connected Components","text":""},{"location":"graph/#max-flow","title":"Max Flow","text":""},{"location":"graph/#references","title":"References","text":"
  1. https://www.hackerearth.com/practice/algorithms/graphs/breadth-first-search/tutorial/
  2. https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/
  3. https://cp-algorithms.com/graph/depth-first-search.html
  4. https://www.hackerearth.com/practice/algorithms/graphs/depth-first-search/tutorial/
  5. Shortest Path. Wikipedia, the free online encyclopedia. Retrieved January 5, 2019
  6. Topological sort. Geeksforgeeks website. Retrieved January 5, 2019
  7. Topological Sort. Wikipedia, the free online encyclopedia. Retrieved January 5, 2019
  8. https://en.wikipedia.org/wiki/Graph_theory
"},{"location":"graph/binary-search-tree/","title":"Binary Search Tree","text":"

A Binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child.

For a binary tree to be a binary search tree, the values of all the nodes in the left sub-tree of the root node should be smaller than the root node's value. Also the values of all the nodes in the right sub-tree of the root node should be larger than the root node's value.

a simple binary search tree","tags":["Tree","Binary Search","BST"]},{"location":"graph/binary-search-tree/#insertion-algorithm","title":"Insertion Algorithm","text":"
  1. Compare values of the root node and the element to be inserted.
  2. If the value of the root node is larger, and if a left child exists, then repeat step 1 with root = current root's left child. Else, insert element as left child of current root.
  3. If the value of the root node is lesser, and if a right child exists, then repeat step 1 with root = current root's right child. Else, insert element as right child of current root.
","tags":["Tree","Binary Search","BST"]},{"location":"graph/binary-search-tree/#deletion-algorithm","title":"Deletion Algorithm","text":"
  • Deleting a node with no children: simply remove the node from the tree.
  • Deleting a node with one child: remove the node and replace it with its child.
  • Node to be deleted has two children: Find inorder successor of the node. Copy contents of the inorder successor to the node and delete the inorder successor.
  • Note that: inorder successor can be obtained by finding the minimum value in right child of the node.
","tags":["Tree","Binary Search","BST"]},{"location":"graph/binary-search-tree/#sample-code","title":"Sample Code","text":"
// C program to demonstrate delete operation in binary search tree \n#include<stdio.h>\n#include<stdlib.h>\n\nstruct node\n{\n    int key;\n    struct node *left, *right;\n};\n\n// A utility function to create a new BST node\nstruct node *newNode(int item)\n{\n    struct node *temp = (struct node *)malloc(sizeof(struct node));\n    temp->key = item;\n    temp->left = temp->right = NULL;\n    return temp;\n}\n\n// A utility function to do inorder traversal of BST\nvoid inorder(struct node *root)\n{\n    if (root != NULL)\n    {\n        inorder(root->left);\n        printf(\"%d \", root->key);\n        inorder(root->right);\n    }\n}\n\n/* A utility function to insert a new node with given key in BST */\nstruct node* insert(struct node* node, int key)\n{\n    /* If the tree is empty, return a new node */\n    if (node == NULL) return newNode(key);\n\n    /* Otherwise, recur down the tree */\n    if (key < node->key)\n        node->left = insert(node->left, key);\n    else\n        node->right = insert(node->right, key);\n\n    /* return the (unchanged) node pointer */\n    return node;\n}\n\n/* Given a non-empty binary search tree, return the node with minimum\n   key value found in that tree. Note that the entire tree does not\n   need to be searched. */\nstruct node * minValueNode(struct node* node)\n{\n    struct node* current = node;\n\n    /* loop down to find the leftmost leaf */\n    while (current->left != NULL)\n        current = current->left;\n\n    return current;\n}\n\n/* Given a binary search tree and a key, this function deletes the key\n   and returns the new root */\nstruct node* deleteNode(struct node* root, int key)\n{\n    // base case\n    if (root == NULL) return root;\n\n    // If the key to be deleted is smaller than the root's key,\n    // then it lies in left subtree\n    if (key < root->key)\n        root->left = deleteNode(root->left, key);\n\n    // If the key to be deleted is greater than the root's key,\n    // then it lies in right subtree\n    else if (key > root->key)\n        root->right = deleteNode(root->right, key);\n\n    // if key is same as root's key, then This is the node\n    // to be deleted\n    else\n    {\n        // node with only one child or no child\n        if (root->left == NULL)\n        {\n            struct node *temp = root->right;\n            free(root);\n            return temp;\n        }\n        else if (root->right == NULL)\n        {\n            struct node *temp = root->left;\n            free(root);\n            return temp;\n        }\n\n        // node with two children: Get the inorder successor (smallest\n        // in the right subtree)\n        struct node* temp = minValueNode(root->right);\n\n        // Copy the inorder successor's content to this node\n        root->key = temp->key;\n\n        // Delete the inorder successor\n        root->right = deleteNode(root->right, temp->key);\n    }\n    return root;\n}\n
","tags":["Tree","Binary Search","BST"]},{"location":"graph/binary-search-tree/#time-complexity","title":"Time Complexity","text":"

The worst case time complexity of search, insert, and deletion operations is \\(\\mathcal{O}(h)\\) where h is the height of Binary Search Tree. In the worst case, we may have to travel from root to the deepest leaf node. The height of a skewed tree may become \\(N\\) and the time complexity of search and insert operation may become \\(\\mathcal{O}(N)\\). So the time complexity of establishing \\(N\\) node unbalanced tree may become \\(\\mathcal{O}(N^2)\\) (for example the nodes are being inserted in a sorted way). But, with random input the expected time complexity is \\(\\mathcal{O}(NlogN)\\).

However, you can implement other data structures to establish Self-balancing binary search tree (which will be taught later), popular data structures that implementing this type of tree include:

  • 2-3 tree
  • AA tree
  • AVL tree
  • B-tree
  • Red-black tree
  • Scapegoat tree
  • Splay tree
  • Treap
  • Weight-balanced tree
","tags":["Tree","Binary Search","BST"]},{"location":"graph/bipartite-checking/","title":"Bipartite Checking","text":"

The question is in the title. Is the given graph bipartite? We can use BFS or DFS on graph. Lets first focus on BFS related algorithm. This procedure is very similar to BFS, we have an extra color array and we assign a color to each vertex when we are traversing the graph. Algorithm proof depends on fact that BFS explores the graph level by level. If the graph contains an odd cycle it means that there must be a edge between two vertices that are in same depth (layer, proof can be found on [1 - Algorithm Design, Kleinberg, Tardos]). Let's say the colors are red and black and we traverse the graph with BFS and assign red to odd layers and black to even layers. Then we check the edges to see if there exists an edge that its vertices are same color. If there is a such edge, the graph is not bipartite, else the graph is bipartite.

If two nodes x and y in the same layer are joined by an edge, then the cycle through x, y, and their lowest common ancestor z has odd length, demonstrating that the graph cannot be bipartite.
typedef vector<int> adjList;\ntypedef vector<adjList> graph;\ntypedef pair<int,int> ii;\nenum COLOR {RED, GREEN};\nbool bipartite_check(graph &g){\n    int root = 0; // Pick 0 indexed node as root.\n    vector<bool> visited(g.size(),false);\n    vector<int> Color(g.size(),0); \n    queue<ii> Q( { {root,0}} ); // insert root to queue, it is  first layer_0\n    visited[root] = true;\n    Color[root] = RED;\n    while ( !Q.empty() )\n    {\n        /*top.first is node, top.second its depth i.e layer */\n        auto top = Q.front();\n        Q.pop();\n        for (int u : g[top.first]){\n            if ( !visited[u] ){\n                visited[u] = true;\n                //Mark even layers to red, odd layers to green\n                Color[u] = (top.second+1) % 2 == 0 ?  RED : GREEN; \n                Q.push({u, top.second+1 });\n            }\n        }\n    }\n    for(int i=0; i < g.size(); ++i){\n        for( auto v: g[i]){\n            if ( Color[i] == Color[v] ) return false;\n        }\n    }\n    return true;\n}\nint main(){\n    graph g(3);\n    g[0].push_back(1);\n    g[1].push_back(2);\n    g[2].push_back(3);\n    cout << (bipartite_check(g) == true ? \"YES\" : \"NO\") << endl;\n    return 0;\n}\n

The complexity of algorithm is is $O(V + E) + O(E) $, BFS and loop over edges. But we can say it \\(O(V+E)\\) since it is Big-O notation.

","tags":["Bipartite Checking","Graph"]},{"location":"graph/breadth-first-search/","title":"Breadth First Search","text":"

Breadth First Search (BFS) is an algorithm for traversing or searching tree. (For example, you can find the shortest path from one node to another in an unweighted graph.)

An example breadth first search traversal","tags":["Graph","Breadth First Search","BFS"]},{"location":"graph/breadth-first-search/#method","title":"Method","text":"

BFS is a traversing algorithm where you should start traversing from a selected node (source or starting node) and traverse the graph layerwise thus exploring the neighbour nodes (nodes which are directly connected to source node). You must then move towards the next-level neighbour nodes. [1]

\u2022 As the name BFS suggests, you are required to traverse the graph breadthwise as follows: \u2022 First move horizontally and visit all the nodes of the current layer \u2022 Add to the queue neighbour nodes of current layer. \u2022 Move to the next layer, which are in the queue

Example question: Given a unweighted graph, a source and a destination, we need to find shortest path from source to destination in the graph in most optimal way?

#include <bits/stdc++.h>\nusing namespace std;\n\ncont int MaxN=100005; // Max number of nodes 5\n\nvector <int> adj[MaxN];\nbool mark[MaxN];\n\nvoid bfs(int starting_point,int ending_point) {\n    memset(mark,0,sizeof(mark)); //clear the cache\n    queue <pair <int,int> > q; // the value of node\n    // , and length between this node and the starting node\n\n    q.push_back(make_pair(starting_point,0));\n    mark[starting_point]=1;\n\n    while(q.empty()==false) {\n        pair <int,int> tmp = q.front(); // get the next node\n        q.pop(); // delete from q\n\n        if(ending_point==tmp.first) {\n            printf(\"The length of path between %d - %d : %d\\n\",\n            starting_point,ending_point,tmp.second);\n            return;\n        }\n\n        for (auto j : adj[tmp.first]) {\n            if(mark[j]) continue ; // if it reached before\n            mark[j]=1;\n            q.push_back(make_pair(j,tmp.second+1)); // add next node to queue\n        }\n    }\n}\n\nint main() {\n    cin \u00bb n\n\n    for (int i=0 ; i < m; i++) {\n        cin \u00bb a \u00bb b;\n        adj[a].push_back(b);\n    }\n\n    cin \u00bb start_point \u00bb end_point;\n    bfs(start_point);\n    return 0;\n}\n
","tags":["Graph","Breadth First Search","BFS"]},{"location":"graph/breadth-first-search/#complexity","title":"Complexity","text":"

The time complexity of BFS is \\(O(V + E)\\), where \\(V\\) is the number of nodes and \\(E\\) is the number of edges.

","tags":["Graph","Breadth First Search","BFS"]},{"location":"graph/bridges-and-articulation-points/","title":"Bridges and Articulation Points","text":"","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#dfs-order","title":"DFS Order","text":"

DFS order is traversing all the nodes of a given graph by fixing the root node in the same way as in the DFS algorithm, but without revisiting a discovered node. An important observation here is that the edges and nodes we use will form a tree structure. This is because, for every node (except the root), we only arrive from another node, and for the root node, we do not arrive from any other node, thus forming a tree structure.

void dfs(int node){\n    used[node] = true;\n    for(auto it : g[node])\n        if(!used[it])\n            dfs(it);\n}\n
","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#types-of-edges","title":"Types of Edges","text":"

When traversing a graph using DFS order, several types of edges can be encountered. These edges will be very helpful in understanding some graph algorithms.

Types of Edges: - Tree edge: These are the main edges used while traversing the graph. - Forward edge: These edges lead to a node that has been visited before and is located in our own subtree. - Back edge: These edges lead to nodes that have been visited before but where the DFS process is not yet complete. - Cross edge: These edges lead to nodes that have been visited before and where the DFS process is already complete.

An important observation about these edges is that in an undirected graph, it is impossible to have a cross edge. This is because it is not possible for an edge emerging from a node where the DFS process is complete to remain unvisited.

Green-colored edges are tree edges. Edge (1,8) is a forward edge. Edge (6,4) is a back edge. Edge (5,4) is a cross edge.","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#bridge","title":"Bridge","text":"

In an undirected and connected graph, if removing an edge causes the graph to become disconnected, this edge is called a bridge.

","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#finding-bridges","title":"Finding Bridges","text":"

Although there are several algorithms to find bridges (such as Chain Decomposition), we will focus on Tarjan's Algorithm, which is among the easiest to implement and the fastest.

When traversing a graph using DFS, if there is a back edge coming out of the subtree of the lower endpoint of an edge, then that edge is not a bridge. This is because the back edge prevents the separation of the subtree and its ancestors when the edge is removed.

This algorithm is based exactly on this principle, keeping track of the minimum depth reached by the back edges within the subtree of each node.

If the minimum depth reached by the back edges in the subtree of the lower endpoint of an edge is greater than or equal to the depth of the upper endpoint, then this edge is a bridge. This is because no back edge in the subtree of the edge's lower endpoint reaches a node above the current edge. Therefore, if we remove this edge, the subtree and its ancestors become disconnected.

Using Tarjan's Algorithm, we can find all bridges in a graph with a time complexity of \\(\\mathcal{O}(V + E)\\), where \\(V\\) represents the number of vertices and \\(E\\) represents the number of edges in the graph.

int dfs(int node, int parent, int depth) {\n    int minDepth = depth;\n    dep[node] = depth;  // dep dizisi her dugumun derinligini tutmaktadir.\n    used[node] = true;\n    for (auto it : g[node]) {\n        if (it == parent)\n            continue;\n        if (used[it]) {\n            minDepth = min(minDepth, dep[it]);\n            // Eger komsu dugum daha once kullanilmis ise\n            // Bu edge back edge veya forward edgedir.\n            continue;\n        }\n        int val = dfs(it, node, depth + 1);\n        // val degeri alt agacindan yukari cikan minimum derinliktir.\n        if (val >= depth + 1)\n            bridges.push_back({node, it});\n        minDepth = min(minDepth, val);\n    }\n    return minDepth;\n}\n
","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#articulation-point","title":"Articulation Point","text":"

In an undirected graph, if removing a node increases the number of connected components, that node is called an articulation point or cut point.

For example, if we remove node 0, the remaining nodes are split into two groups: 5 and 1, 2, 3, 4. Similarly, if we remove node 1, the nodes are split into 5, 0 and 2, 3, 4. Therefore, nodes 0 and 1 are **articulation points**.","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/bridges-and-articulation-points/#finding-articulation-points","title":"Finding Articulation Points","text":"

Tarjan's Algorithm for finding articulation points in an undirected graph:

  • Traverse the graph using DFS order.

  • For each node, calculate the depth of the minimum depth node that can be reached from the current node and its subtree through back edges. This value is called the low value of the node.

  • If the low value of any child of a non-root node is greater than or equal to the depth of the current node, then the current node is an articulation point. This is because no back edge in the subtree of this node can reach a node above the current node. Therefore, if this node is removed, its subtree will become disconnected from its ancestors.

  • If the current node is the root (the starting node of the DFS order) and there are multiple branches during the DFS traversal, then the root itself is an articulation point. This is because the root has multiple connected subgraphs.

Using Tarjan's Algorithm, we can find all articulation points in a graph with a time complexity of \\(\\mathcal{O}(V + E)\\), where \\(V\\) is the number of vertices and \\(E\\) is the number of edges in the graph.

int dfs(int node, int parent, int depth) {\n    int minDepth = depth, children = 0;\n    dep[node] = depth;  // dep array holds depth of each node.\n    used[node] = true;\n    for (auto it : g[node]) {\n        if (it == parent)\n            continue;\n        if (used[it]) {\n            minDepth = min(minDepth, dep[it]);\n            continue;\n        }\n        int val = dfs(it, node, depth + 1);\n        if (val >= depth and parent != -1)\n            isCutPoint[node] = true;\n        minDepth = min(minDepth, val);\n        children++;\n    }\n    // This if represents the root condition that we mentioned above.\n    if (parent == -1 and children >= 2)\n        isCutPoint[node] = true;\n    return minDepth;\n}\n
","tags":["Bridge","Articulation Point","Cut Vertex","Cut Edge","Graph"]},{"location":"graph/cycle-finding/","title":"Cycle Finding","text":"

Cycle: A sequence of nodes that returns to the starting node while visiting each node at most once and contains at least two nodes.

We can use dfs order in order to find the graph has a cycle or not.

If we find a back edge while traversing the graph then we can say that graph has a cycle. Because back edge connects the nodes at the top and bottom ends and causes a cycle.

The algorithm that we are going to use to find the cycle in the directed graph:

  • Traverse the graph with dfs order.
  • When you come to a node, color it gray and start visiting its neighbors.
  • If one of the current node's neighbors is gray, then there is a cycle in the graph. Because a gray node is definitely an ancestor of the current node, and an edge to one of its ancestors is definitely a back edge.
  • Once you're done visiting the neighbors, color the node black.
bool dfs(int node){\n    // The color array holds the color of each node.\n    // 0 represents white, 1 represents gray, and 2 represents black.\n    color[node] = 1;\n    for(int i = 0; i < g[node].size(); i++){\n        int child = g[node][i];\n        if(color[child] == 1)\n            return true;\n        if(!color[child])\n            if(dfs(child))\n                return true;\n    }\n    color[node] = 2;\n    return false;\n}\n
","tags":["Graph","Cycle"]},{"location":"graph/definitions/","title":"Graph Definitions","text":"","tags":["Graph"]},{"location":"graph/definitions/#definitions-of-common-terms","title":"Definitions of Common Terms","text":"
  • Node - An individual data element of a graph is called Node. Node is also known as vertex.
  • Edge - An edge is a connecting link between two nodes. It is represented as e = {a,b} Edge is also called Arc.
  • Adjacent - Two vertices are adjacent if they are connected by an edge.
  • Degree - a degree of a node is the number of edges incident to the node.
  • Undirected Graphs - Undirected graphs have edges that do not have a direction. The edges indicate a two-way relationship, in that each edge can be traversed in both directions.
  • Directed Graphs - Directed graphs have edges with direction. The edges indicate a one-way relationship, in that each edge can only be traversed in a single direction.
  • Weighted Edges - If each edge of graphs has an association with a real number, this is called its weight.
  • Self-Loop - It is an edge having the same node for both destination and source point.
  • Multi-Edge - Some Adjacent nodes may have more than one edge between each other.
","tags":["Graph"]},{"location":"graph/definitions/#walks-trails-paths-cycles-and-circuits","title":"Walks, Trails, Paths, Cycles and Circuits","text":"
  • Walk - A sequence of nodes and edges in a graph.
  • Trail - A walk without visiting the same edge.
  • Circuit - A trail that has the same node at the start and end.
  • Path - A walk without visiting same node.
  • Cycle - A circuit without visiting same node.
","tags":["Graph"]},{"location":"graph/definitions/#special-graphs","title":"Special Graphs","text":"
  • Complete Graph - A graph having at least one edge between every two nodes.
  • Connected Graph - A graph with paths between every pair of nodes.
  • Tree - an undirected connected graph that has any two nodes that are connected by exactly one path. There are some other definitions that you can notice it is tree:
    • an undirected graph is connected and has no cycles. an undirected graph is acyclic, and a simple cycle is formed if any edge is added to the graph.
    • an undirected graph is connected, it will become disconnected if any edge is removed.
    • an undirected graph is connected, and has (number of nodes - 1) edges.
","tags":["Graph"]},{"location":"graph/definitions/#bipartite-graphs","title":"Bipartite Graphs","text":"

A bipartite graph is a graph whose vertices can be divided into two disjoint and independent sets U and V such that every edge connects a vertex in U to one in V. Vertex sets U and V are usually called the parts of the graph. [1]. The figure is shown in below. It is similar to graph coloring with two colors. Coloring graph with two colors is that every vertex have a corresponding color, and for any edge, it's vertices should be different color. In other words, if we can color neighbours two different colors, we can say that graph is bipartite.

Example bipartite graph, all edges satisfy the coloring constraint

We have some observations here. - A graph 2- colorable if and only if it is bipartite. - A graph does not contain odd-length cycle if and only if it is bipartite. - Every tree is a bipartite graph since trees do not contain any cycles.

","tags":["Graph"]},{"location":"graph/definitions/#directed-acyclic-graphs","title":"Directed Acyclic Graphs","text":"

A directed acyclic graph(DAG) is a finite directed graph with no directed cycles. Equivalently, a DAG is a directed graph that has a topological ordering (we cover it in this bundle), a sequence of the vertices such that every edge is directed from earlier to later in the sequence [2]. DAGs can be used to encode precedence relations or dependencies in a natural way [3 - Algorithm Design, Kleinberg, Tardos]. There are several applications using topological ordering directly such as finding critical path or automatic differentiation on computational graphs (this is extremely useful for deep learning frameworks [4]).

Example Directed Acyclic Graphs Example computational graph also a DAG, partial derivatives are written to edges respect to topological order","tags":["Graph"]},{"location":"graph/depth-first-search/","title":"Depth First Search","text":"

Depth First Search (DFS) is an algorithm for traversing or searching tree. (For example, you can check if graph is connected or not via DFS) [2]

Example of DFS traversal","tags":["Graph","Depth First Search","DFS"]},{"location":"graph/depth-first-search/#method","title":"Method","text":"

The DFS algorithm is a recursive algorithm that uses the idea of backtracking. It involves exhaustive searches of all the nodes by going ahead, if possible, else by backtracking.

Here, the word backtrack means that when you are moving forward and there are no more nodes along the current path, you move backwards on the same path to find nodes to traverse. All the nodes will be visited on the current path till all the unvisited nodes have been traversed after which the next path will be selected. [3]

vector<vector<int\u00bb adj; // graph represented as an adjacency list\nint n; // number of vertices\nvector<bool> visited;\nvoid dfs(int v) {\n    visited[v] = true;\n    for (int u : adj[v]) {\n        if (!visited[u]) dfs(u);\n    }\n}\n

This recursive nature of DFS can be implemented using stacks. The basic idea is as follows: Pick a starting node and push all its adjacent nodes into a stack. Pop a node from stack to select the next node to visit and push all its adjacent nodes into a stack. Repeat this process until the stack is empty. However, ensure that the nodes that are visited are marked. This will prevent you from visiting the same node more than once. If you do not mark the nodes that are visited and you visit the same node more than once, you may end up in an infinite loop. [3]

DFS-iterative(G, s): //Where G is graph and s is source vertex let S be stack\nS.push(s) //Inserting s in stack\nmark s as visited.\nwhile ( S is not empty):\n    //Pop a vertex from stack to visit next v = S.top( )\n    S.pop( )\n    //Push all the neighbours of v in stack that are not visited\n    for all neighbours w of v in Graph G:\n        if w is not visited :\n            S.push(w)\n            mark w as visited\n

Example Question: Given an undirected graph, find out whether the graph is strongly connected or not? An undirected graph is strongly connected if there is a path between any two pair of vertices.

#include <bits/stdc++.h>\nusing namespace std;\n\ncont int MaxN=100005; // Max number of nodes\n\nvector <int> adj[MaxN];\nbool mark[MaxN];\n\nvoid dfs(int k) {\n    mark[k]=1; // visited\n    for(auto j : adj[k]) // iterate over adjacent nodes\n        if(mark[j]==false) // check if it is visited or not\n            dfs(j); // do these operation for that node\n}\n\nint main() {\n    cin \u00bb n \u00bb m; // number of nodes , number of edges\n    for (int i=0 ; i < m; i++){\n        cin \u00bb a \u00bb b;\n        adj[a].push_back(b);\n        adj[b].push_back(a);\n    }\n\n    dfs(1);\n\n    bool connected=1;\n    for(int i=1 ; i <= n ;i++)\n        if(mark[i]==0) {\n            connected=0;\n            break;\n        }\n\n    if(connected)\n        cout \u00ab \"Graph is connected\" \u00ab endl;\n    else\n        cout \u00ab \"Graph is not connected\" \u00ab endl;\n\n    return 0;\n}\n
","tags":["Graph","Depth First Search","DFS"]},{"location":"graph/depth-first-search/#complexity","title":"Complexity","text":"

The time complexity of DFS is \\(O(V+E)\\) when implemented using an adjacency list ( with Adjacency Matrices it is \\(O(V^2)\\)), where \\(V\\) is the number of nodes and \\(E\\) is the number of edges. [4]

","tags":["Graph","Depth First Search","DFS"]},{"location":"graph/heap/","title":"Heap","text":"an example max-heap with 9 nodes

The heap is a complete binary tree with N nodes, the value of all the nodes in the left and right sub-tree of the root node should be smaller than the root node's value.

In a heap, the highest (or lowest) priority element is always stored at the root. A heap is not a sorted structure and can be regarded as partially ordered. As visible from the heap-diagram, there is no particular relationship among nodes on any given level, even among the siblings. Because a heap is a complete binary tree, it has a smallest possible height. A heap with \\(N\\) nodes has \\(logN\\) height. A heap is a useful data structure when you need to remove the object with the highest (or lowest) priority.

","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#implementation","title":"Implementation","text":"

Heaps are usually implemented in an array (fixed size or dynamic array), and do not require pointers between elements. After an element is inserted into or deleted from a heap, the heap property may be violated and the heap must be balanced by internal operations.

The first (or last) element will contain the root. The next two elements of the array contain its children. The next four contain the four children of the two child nodes, etc. Thus the children of the node at position n would be at positions \\(2*n\\) and \\(2*n + 1\\) in a one-based array. This allows moving up or down the tree by doing simple index computations. Balancing a heap is done by sift-up or sift-down operations (swapping elements which are out of order). So we can build a heap from an array without requiring extra memory.

example a heap as an array","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#insertion","title":"Insertion","text":"

Basically add the new element at the end of the heap. Then look it's parent if it is smaller or bigger depends on the whether it is max-heap or min-heap (max-heap called when Parents are always greater), swap with the parent. If it is swapped do the same operation for the parent.

","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#deletion","title":"Deletion","text":"

If you are going to delete a node (root node or another one does not matter),

  1. Swap the node to be deleted with the last element of heap to maintain a balanced structure.
  2. Delete the last element which is the node we want to delete at the start.
  3. Now you have a node which is in the wrong place, You have to find the correct place for the swapped last element, to do this starting point you should check its left and right children, if one them is greater than our node you should swap it with the greatest child(or smallest if it is min-heap).
  4. Still current node may in the wrong place, so apply Step 3 as long as it is not greater than its children(or smaller if it is min-heap).
an example deletion on a heap structure
class BinHeap:\n    def __init__(self):\n        self.heapList = [0]\n        self.currentSize = 0\n\n    def percUp(self,i):\n        while i // 2 > 0:\n            if self.heapList[i] < self.heapList[i // 2]:\n                tmp = self.heapList[i // 2]\n                self.heapList[i // 2] = self.heapList[i]\n                self.heapList[i] = tmp\n            i = i // 2\n\n    def insert(self,k):\n        self.heapList.append(k)\n        self.currentSize = self.currentSize + 1\n        self.percUp(self.currentSize)\n\n    def percDown(self,i):\n        while (i * 2) <= self.currentSize:\n            mc = self.minChild(i)\n            if self.heapList[i] > self.heapList[mc]:\n                tmp = self.heapList[i]\n                self.heapList[i] = self.heapList[mc]\n                self.heapList[mc] = tmp\n            i = mc\n\n    def minChild(self,i):\n        if i * 2 + 1 > self.currentSize:\n            return i * 2\n        else:\n            if self.heapList[i*2] < self.heapList[i*2+1]:\n                return i * 2\n            else:\n                return i * 2 + 1\n\n    def delMin(self):\n        retval = self.heapList[1]\n        self.heapList[1] = self.heapList[self.currentSize]\n        self.currentSize = self.currentSize - 1\n        self.heapList.pop()\n        self.percDown(1)\n        return retval\n\n    def buildHeap(self,alist):\n        i = len(alist) // 2\n        self.currentSize = len(alist)\n        self.heapList = [0] + alist[:]\n        while (i > 0):\n            self.percDown(i)\n            i = i - 1\n\nbh = BinHeap()\nbh.buildHeap([9,5,6,2,3])\n\nprint(bh.delMin())\nprint(bh.delMin())\nprint(bh.delMin())\nprint(bh.delMin())\nprint(bh.delMin())\n
","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#complexity","title":"Complexity","text":"

Insertion \\(\\mathcal{O}(logN)\\), delete-min \\(\\mathcal{O}(logN)\\) , and finding minimum \\(\\mathcal{O}(1)\\). These operations depend on heap's height and heaps are always complete binary trees, basically the height is \\(logN\\). (N is number of Node)

","tags":["Heap","Priority Queue"]},{"location":"graph/heap/#priority-queue","title":"Priority Queue","text":"

Priority queues are a type of container adaptors, specifically designed so that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.

While priority queues are often implemented with heaps, they are conceptually distinct from heaps. A priority queue is an abstract concept like \"a list\" or \"a map\"; just as a list can be implemented with a linked list or an array, a priority queue can be implemented with a heap or a variety of other methods such as an unordered array.

#include <iostream>       // std::cout\n#include <queue>          // std::priority_queue\nusing namespace std;\nint main () {\n    priority_queue<int> mypq;\n\n    mypq.push(30);\n    mypq.push(100);\n    mypq.push(25);\n    mypq.push(40);\n\n    cout << \"Popping out elements...\";\n    while (!mypq.empty()) {\n        cout << ' ' << mypq.top();\n        mypq.pop();\n    }\n    return 0;\n}\n
","tags":["Heap","Priority Queue"]},{"location":"graph/introduction/","title":"Introduction","text":"

A graph is a structure amounting to a set of objects in which some pairs of the objects are in some sense \"related\". The objects correspond to the mathematical abstractions called vertices (also called nodes or points) and each of the related pairs of vertices is called an edge. Typically, a graph is depicted in diagrammatic form as a set of dots for the vertices, joined by lines for the edges. [8]

Why graphs? Graphs are usually used to represent different elements that are somehow related to each other.

A Graph consists of a finite set of vertices(or nodes) and set of edges which connect a pair of nodes. G = (V,E)

V = set of nodes

E = set of edges(e) represented as e = a,b

Graph are used to show a relation between objects. So, some graphs may have directional edges (e.g. people and their love relationships that are not mutual: Alice may love Alex, while Alex is not in love with her and so on), and some graphs may have weighted edges (e.g. people and their relationship in the instance of a debt)

Figure 1: a simple unweigted graph","tags":["Graph"]},{"location":"graph/max-flow/","title":"Max Flow","text":"","tags":["Graph","Max Flow","Maximum Flow","Ford Fulkerson"]},{"location":"graph/max-flow/#flow-network","title":"Flow Network","text":"

A flow network is a special type of directed graph that contains a single source and a single target node. In a flow network, each edge has a capacity, which indicates the maximum amount of flow that can pass through that edge.

One of the earliest examples of a flow network in history.","tags":["Graph","Max Flow","Maximum Flow","Ford Fulkerson"]},{"location":"graph/max-flow/#maximum-flow","title":"Maximum Flow","text":"

Maximum flow is an algorithm that calculates the maximum amount of flow that can reach the target from the source in a flow network while maintaining a continuous flow.

There are several algorithms to solve the Maximum Flow problem. The time complexities of some popular ones are:

  • Ford-Fulkerson algorithm: \\(\\mathcal{O}(E * \\text{flowCount})\\)
  • Edmonds-Karp algorithm: \\(\\mathcal{O}(V * E^2)\\)
  • Dinic's algorithm: \\(\\mathcal{O}(E * V^2)\\)

Where V is the number of vertices and E is the number of edges in the flow network.

","tags":["Graph","Max Flow","Maximum Flow","Ford Fulkerson"]},{"location":"graph/max-flow/#ford-fulkerson","title":"Ford Fulkerson","text":"

The steps of the Ford-Fulkerson maximum flow algorithm are as follows:

  • Find a path from the source to the target.
  • The edge with the minimum capacity in the found path determines the flow that can pass through this path.
  • Decrease the capacities of the edges in the path by the flow amount (the minimum capacity found in step 2) and add the reverse edges to the graph with a capacity equal to the flow.
  • Repeat until there are no more paths from the source to the target.

Why does this algorithm work?

For example, let's assume we find a flow of size x through an edge from u to v.

Suppose the path we found is \\(a \\rightarrow ... \\rightarrow u \\rightarrow v \\rightarrow ... \\rightarrow b\\).

We will add a new edge from v to u with a capacity of x to our graph, but this newly added reverse edge does not exist in the original graph.

After adding the reverse edges, the new path we find might look like \\(c \\rightarrow ... \\rightarrow v \\rightarrow u \\rightarrow ... \\rightarrow d\\), with a flow of size y.

It is clear that \\(y \\leq x\\).

We can represent three different valid flows as follows:

  • A flow of size y following the path \\(a \\rightarrow ... \\rightarrow u \\rightarrow ... \\rightarrow d\\)
  • A flow of size y following the path \\(c \\rightarrow ... \\rightarrow u \\rightarrow ... \\rightarrow b\\)
  • A flow of size x - y following the path \\(a \\rightarrow ... \\rightarrow u \\rightarrow v \\rightarrow ... \\rightarrow d\\)

The overall time complexity of the Ford-Fulkerson algorithm is \\(\\mathcal{O}(E * \\text{flowCount})\\) because, in the worst case, each found path increases the flow by only 1. Since finding each path takes time proportional to the number of edges, the complexity becomes \\(\\mathcal{O}(E * \\text{flowCount})\\).

However, if we implement the Ford-Fulkerson algorithm using BFS, the complexity changes. In this case, for every edge, the flows that consider this edge as the bottleneck will continually increase, leading to a time complexity of \\(\\mathcal{O}(V * E^2)\\). This specific implementation is known as the Edmonds-Karp Algorithm.

The figure on the left shows how much flow is passing through each edge. The figure on the right represents the current state of the graph. Flow = 7 Flow = 8 Flow = 13 Flow = 15
// c matrix holds the capacities of the edges.\n// g adjacency list allows us to traverse the graph.\nbool bfs() {\n    vector<bool> visited(n, false);\n    queue<int> q;\n    q.push(source);\n    visited[source] = true;\n    while (!q.empty()) {\n        int node = q.front();\n        q.pop();\n        if (node == sink)\n            break;\n        for (int i = 0; i < g[node].size(); i++) {\n            int child = g[node][i];\n            if (c[node][child] <= 0 or visited[child])\n                continue;\n            visited[child] = true;\n            parent[child] = node;\n            q.push(child);\n        }\n    }\n    return visited[sink];\n}\nint max_flow() {\n    while (bfs()) {\n        int curFlow = -1, node = sink;\n        while (node != source) {\n            // curFlow is the minimum capacity in the current path, i.e. the flow we found.\n            int len = c[parent[node]][node];\n            if (curFlow == -1)\n                curFlow = len;\n            else\n                curFlow = min(curFlow, len);\n            node = parent[node];\n        }\n        flow += curFlow;\n        node = sink;\n        while (node != source) {\n            c[parent[node]][node] -= curFlow;\n            // We are subtracting the flow we found from the path we found.\n            c[node][parent[node]] += curFlow;  // We are adding the reverses of the edges\n            node = parent[node];\n        }\n    }\n    return flow;\n}\n
","tags":["Graph","Max Flow","Maximum Flow","Ford Fulkerson"]},{"location":"graph/minimum-spanning-tree/","title":"Minimum Spanning Tree","text":"","tags":["Graph","Minimum Spanning Tree","Prim","Kruskal"]},{"location":"graph/minimum-spanning-tree/#definition","title":"Definition","text":"

Given an undirected weighted connected graph \\(G = (V,E)\\) Spanning tree of G is a connected acyclic sub graph that covers all nodes and some edges. In a disconnected graph -where there is more than one connected component- the spanning tree of that graph is defined as the forest of the spanning trees of each connected component of the graph.

Minimum spanning tree (MST) is a spanning tree in which the sum of edge weights is minimum. The MST of a graph is not unique in general, there might be more than one spanning tree with the same minimum cost. For example, take a graph where all edges have the same weight, then any spanning tree would be a minimum spanning tree. In problems involving minimum spanning trees where you have to output the tree itself (and not just the minimum cost), it either puts more constraint so the answer is unique, or simply asks for any minimum spanning tree.

MST of the graph. It spans all nodes of the graph and it is connected.

To find the minimum spanning tree of a graph, we will introduce two algorithms. The first one called Prim's algorithm, which is similar to Dijkstra's algorithm. Another algorithm is Kruskal agorithm, which makes use of the disjoint set data structure. Let's discover each one of them in detail!

","tags":["Graph","Minimum Spanning Tree","Prim","Kruskal"]},{"location":"graph/minimum-spanning-tree/#prim-algorithm","title":"Prim Algorithm","text":"

Prim algorithm is very similar to Dijkstra's shortest path algorithm. In this algorithm we have a set \\(S\\) which represents the explored nodes and again we can maintain a priority queue data structure the closest node in \\(V-S\\). It is a greedy algorithm just like Dijkstra's shortest path algorithm.

G = (V, E)   V set of all nodes, E set of all edges\nT = {}       result, edges of MST\nS = {1}      explored nodes\nwhile S /= V do\n    let (u, v) be the lowest cost edge such that u in S and v in V - S;\n    T = T U {(u, v)}\n    S = S U {v}\nend\n
Prim Algorithm in Pseudo code, what is the problem here?

There is a problem with this implementation, it assumes that the graph is connected. If the graph is not connected this algorithm will be stuck on loop. There is a good visualization for Prim algorithm at [10]. If we use priority queue complexity would be \\(O(ElogV)\\).

Example of how Prim Algorithm constructs the MST","tags":["Graph","Minimum Spanning Tree","Prim","Kruskal"]},{"location":"graph/minimum-spanning-tree/#kruskal-algorithm","title":"Kruskal Algorithm","text":"

In Prim algorithm we started with a specific node and then proceeded with choosing the closest neighbor node to our current graph. In Kruskal algorithm, we follow a different strategy; we start building our MST by choosing one edge at a time, and link our (intially separated) nodes together until we connect all of the graph.

To achieve this task, we will start with having all the nodes separated each in a group. In addition, we will have the list of edges from the original graph sorted based on their cost. At each step, we will:

  1. Pick the smallest available edge (that is not taken yet)
  2. Link the nodes it connects together, by merging their group into one unified group
  3. Add the cost of the edge to our answer

However, you may realize in some cases the link we add will connect two nodes from the same group (because they were grouped before by other taken edges), hence violating the spanning tree condition (Acyclic) and more importantly introducing unnecessary edges that adds more cost to the answer. So to solve this problem, we will only add the edges as long as they connect two currently (at the time of processing this edge) separated nodes that belong to different groups, hence completing the algorithm.

The optimality of Kruskal algorithm comes from the fact that we are taking from a sorted list of edges. For more rigorous proof please refer to [11].

So how can we effectively merge the group of nodes and check that which group each node belong? We can utilize disjoint set data structure which will help us to make union and find operations in an amortized constant \\(\\mathcal{O}(1)\\) time.

typedef pair<int,pair<int,int>> edge;\n// represent edge as triplet (w,u,v)\n// w is weigth, u and v verticies.\n// edge.first is weigth edge.second.first -> u, edge.second.second -> v\ntypedef vector<edge> weigthed_graph;\n\n/*union - find data structure utilities */\nconst int maxN = 3005;\nint parent[maxN];\nint ssize[maxN];\nvoid make_set(int v);\nint find_set(int v);\nvoid union_sets(int a, int b);\nvoid init_union_find();\n\n/*Code that finds edges in MST */\nvoid kruskal(vector<edge> &edgeList ){\n    vector<edge> mst;\n    init_union_find();\n    sort(edgeList.begin(),edgeList.end(), \\\n        [](const auto &a, const auto  &b) { return a.first< b.first;}); \n    //well this weird syntax is lambda function \n    // for sorting pairs to respect their first element.\n    for( auto e: edgeList){\n        if( find_set(e.second.first )!= find_set(e.second.second)){\n            mst.push_back(e);\n            union_sets(e.second.first, e.second.second);\n        }\n    }\n}\n

To calculate the time complexity, observe how we first sorted the edges, this takes \\(\\mathcal{O}(E log E)\\). In addition we pass through the edges one by one, and each time we check which group the two nodes of the edge belongs to, and in some cases merge the two groups. So in the worst case we will assume that both operations (finding and merging) happens, but since the disjoint data structure guarantee \\(\\mathcal{O}(1)\\) amortized time for both operations, we end up with \\(\\mathcal{O}(E)\\) amortized time of processing the nodes.

So in total we have \\(\\mathcal{O}(E log E)\\) from sorting edges and \\(\\mathcal{O}(E)\\) from processing them, those results in a total of \\(\\mathcal{O}(E log E)\\) (if you don't understand why please refer to the first bundle where we discuss time complexity).

Example of how Kruskal Algorithm constructs the MST","tags":["Graph","Minimum Spanning Tree","Prim","Kruskal"]},{"location":"graph/representing-graphs/","title":"Representing Graphs","text":"","tags":["Graph"]},{"location":"graph/representing-graphs/#edge-lists","title":"Edge Lists","text":"

A simple way to define edge list is that it has a list of pairs. We just have a list of objects consisting of the vertex numbers of 2 nodes and other attributes like weight or the direction of edges. [16]

  • + For some specific algorithms you need to iterate over all the edges, (i.e. kruskal's algorithm)
  • + All edges are stored exactly once.
  • - It is hard to determine whether two nodes are connected or not.
  • - It is hard to get information about the edges of a specific vertex.
#include <iostream>\n#include <vector>\nusing namespace std;\n\nint main(){\n    int edge_number;\n    vector<pair <int,int> > edges;\n    cin >> edge_number;\n    for( int i=0 ; i<edge_number ; i++ ){\n        int a,b;\n        cin >> a >> b;\n        edges.push_back(make_pair(a,b)); // a struct can be used if edges are weighted or have other properties.\n    }\n}\n
","tags":["Graph"]},{"location":"graph/representing-graphs/#adjacency-matrices","title":"Adjacency Matrices","text":"

Stores edges, in a 2-D matrix. matrix[a][b] keeps an information about road from a to b. [16] - + We can easily check if there is a road between two vertices. - - Looping through all edges of a specific node is expensive because you have to check all of the empty cells too. Also these empty cells takes huge memory in a graph which has many vertices. (For example representing a tree)

#include <iostream>\n#include <vector>\nusing namespace std;\nint main(){\n    int node_number;\n    vector<vector<int> > Matrix;\n    cin >> node_number;\n    for( int i=0 ; i<node_number ; i++ )\n        for( int j=0 ; j<node_number ; j++ ){\n            Matrix.push_back(vector <int> ());\n            int weight;\n            cin >>weight ;\n            Matrix[i].push_back(weight);\n        }\n}\n
","tags":["Graph"]},{"location":"graph/representing-graphs/#adjacency-list","title":"Adjacency List","text":"

Each node has a list consisting of nodes each is adjacent to. So, there will be no empty cells. Memory will be equal to number of edges. The most used one is in algorithms. [16]

  • + You do not have to use space for empty cells.
  • + Easily iterate over all the neighbors of a specific node.
  • - If you want to check if two nodes are connected, in this form you still need to iterate over all the neighbors of one of them. But, there are some structures that you can do this operation in O(log N). For example if you won't add any edge, you can sort every vector with nodes' names, so you can find it by binary search.
#include <iostream>\n#include <vector>\nusing namespace std;\n\nint main(){\n    int node_number,path_number;\n\n    vector<vector<int> > paths; \n    // use object instead of int, \n    //if you need to store other features\n\n    cin >> node_number >> path_number;\n    for( int i=0 ; i<node_number ; i++ )\n        Matrix.push_back(vector <int> ());\n    for( int j=0 ; j< path_number ; j++ ){\n        int beginning_node, end_node;\n        cin >> beginning_node >> end_node;\n\n        Matrix[ beginning_node ].push_back( end_node ); // push st\n        // Matrix[ end_node ].push_back(  beginning_node ); \n        // ^^^ If edges are Undirected, you should push in reverse direction too\n    }\n}\n
","tags":["Graph"]},{"location":"graph/shortest-path/","title":"Shortest Path Problem","text":"","tags":["Graph","Shortest Path Problem","Dijkstra"]},{"location":"graph/shortest-path/#definition","title":"Definition","text":"

Let \\(G(V,E)\\) be a graph, \\(v_i\\) and \\(v_j\\) be two nodes of \\(G\\). We say a path between \\(v_i\\) and \\(v_j\\) is the shortest path if sum of the edge weights (cost) in the path is minimum. In other words, the shortest path problem is the problem of finding a path between two vertices (or nodes) in a graph such that the sum of the weights of its constituent edges is minimized. [5]

Example shortest path in graph. Source is A and target is F. Image taken from [5].

We will cover several shortest path algorithms in this bundle. One of them is Dijkstra\u2019s Shortest Path Algorithm but it has some drawbacks: Edge weights should be non-negative for the optimally of the algorithm. We will discover other algorithms in which these condition isn\u2019t necessary, like Floyd-Warshall and Bellman-Ford algorithms.

","tags":["Graph","Shortest Path Problem","Dijkstra"]},{"location":"graph/shortest-path/#dijkstras-shortest-path-algorithm","title":"Dijkstra's Shortest Path Algorithm","text":"

Dijkstra\u2019s Shortest Path algorithm is straight forward. In brief we have a set \\(S\\) that contains explored nodes and \\(d\\) which contains the shortest path cost from source to another node. In other words, \\(d(u)\\) represents the shortest path cost from source to node \\(u\\). The procedure follows as that. First, add source node to set \\(S\\) which represents the explored nodes and assigns the minimum cost of the source to zero. Then each iteration we add node to \\(S\\) that has lowest cost \\((d(u))\\) from unexplored nodes. Let\u2019s say \\(S\u2032 = V \u2212 S\\) which means unexplored nodes. For all nodes in \\(S\u2032\\) we calculate \\(d(x)\\) for each node \\(x\\) is \\(S\u2032\\) then we pick minimum cost node and add it to \\(S\\). So how we calculate \\(d(x)\\)? For any \\(x\\) node from \\(S\u2032\\), \\(d(x)\\) calculated as that, let\u2019s say \\(e\\) cost of any edge from \\(S\\) to \\(x\\) then \\(d(x) = min(d(u) + e)\\). It is a greedy algorithm.

Here is the explanation of the algorithm step by step.

  1. Initialize an empty set, distance array, insert source to set.

  2. Initialize a min-heap, put source to heap with key is zero.

  3. While heap is not empty, take the top element from heap and add its neighbours to min-heap.

  4. Once we pick an element from the heap, it is guaranteed that the same node will never be added to heap with lower key value.

In implementation we can use priority queue data structure in order to increase efficiency. If we put unexplored nodes to min - priority queue where the distance is key, we can take the lowest cost unexplored node in \\(O(log(n))\\) time which is efficient.

typedef pair<int,int> edge;\ntypedef vector<edge> adjList;\ntypedef vector<adjList> graph;\n\nvoid dijkstra(graph &g, int s) {\n    vector<int> dist(g.size(),INT_MAX/2);\n    vector<bool> visited(g.size(),false);\n\n    dist[s] = 0;\n\n    priority_queue<edge, vector<edge>, greater<edge>> q;\n    q.push({0, s});\n\n    while(!q.empty()) {\n        int v = q.top().second;\n        int d = q.top().first;\n        q.pop();\n\n        if(visited[v]) continue;\n        visited[v] = true;\n\n        for(auto it: g[v]) {\n            int u = it.first;\n            int w = it.second;\n            if(dist[v] + w < dist[u]) {\n                dist[u] = dist[v] + w;\n                q.push({dist[u], u});\n            } \n        }       \n    }\n}\n
","tags":["Graph","Shortest Path Problem","Dijkstra"]},{"location":"graph/strong-connectivity-and-biconnectivity/","title":"Strong Connectivity and Biconnectivity","text":"","tags":["Strong Connectivity","Biconnectivity","Graph"]},{"location":"graph/strong-connectivity-and-biconnectivity/#strong-connectivity","title":"Strong Connectivity","text":"

To reach a target node from a given node, it must be possible to arrive at the target by passing through a finite number of nodes.

In an undirected graph, if every node is reachable from every other node, the graph is called connected. When the same concept is applied to directed graphs, it is called strongly connected.

In other words, for a directed graph to be strongly connected, it must be possible to reach every other node from any given node.

","tags":["Strong Connectivity","Biconnectivity","Graph"]},{"location":"graph/strong-connectivity-and-biconnectivity/#biconnectivity","title":"Biconnectivity","text":"

In an undirected graph, if the remaining graph remains connected when any node is removed, the graph is called biconnected. In other words, if the graph has no articulation points, it is considered a biconnected graph.

An example of biconnected graph","tags":["Strong Connectivity","Biconnectivity","Graph"]},{"location":"graph/strongly-connected-components/","title":"Strongly Connected Components","text":"

All directed graphs can be divided into disjoint subgraphs that are strongly connected. For two subgraphs to be disjoint, they must not share any common edges or nodes. If we consider each of these resulting subgraphs as a single node and create a new graph, the resulting graph will be a directed acyclic graph (DAG), meaning it will have no cycles.

The subgraphs marked in red are the strongly connected components. The newly formed graph, created by treating each strongly connected component as a single node, results in a directed acyclic graph (DAG), meaning it contains no cycles.

Tarjan's Algorithm for finding strongly connected components (SCCs) in a directed graph (An alternative approach is Kosaraju's Algorithm, but Tarjan's algorithm is often preferred in practice due to its speed and simpler understanding):

  • Start traversing the graph using DFS order from any node and push the visited nodes onto a stack. Calculate the discovery time for each node. (Discovery time is the time unit when the node is first reached during DFS traversal, and we will call this the index.)
  • If a node is in the stack, it is not yet part of any strongly connected component. This is because, when a strongly connected component is found, all the nodes belonging to that component are removed from the stack.
  • For each node, calculate the index of the node that has the minimum index among the nodes reachable from the current node and its subtree through edges that do not belong to any strongly connected component. This value is called the \"minimum reachable depth\" from the subtree of the node (also known as the \"low\" value).
  • If a node's low value is equal to its own index, then this node and all nodes below it in the stack form a strongly connected component. This is because if we call this node \"u,\" there must be an edge from u's subtree back to u itself. Otherwise, u's low value would be clearly smaller than its own index.
  • When a strongly connected component is found (as explained in the previous step), remove all nodes belonging to this component from the stack.

Using Tarjan's Algorithm, we can find all strongly connected components in a graph with a time complexity of \\(\\mathcal{O}(V + E)\\), where \\(V\\) is the number of vertices and \\(E\\) is the number of edges.

void dfs(int node) {\n    low[node] = index[node] = ++curTime;\n    // curTime holds the discovery time of each node.\n    used[node] = true;\n\n    st.push(node);\n    inStack[node] = true;\n    // inStack holds whether a node is in the stack or not.\n    for (auto it : g[node]) {\n        if (!used[it]) {\n            dfs(it);\n            low[node] = min(low[node], low[it]);\n        } else if (inStack[it])\n            low[node] = min(low[node], index[it]);\n        // If the adjacent node is in the stack, then this edge can be a back edge.\n    }\n    if (low[node] == index[node]) {\n        while (1) {\n            int x = st.top();\n            st.pop();\n            cout << x << \" \";\n            inStack[x] = false;\n            if (x == node)\n                break;\n        }\n        cout << endl;\n    }\n}\n\nvoid scc() {\n    for (int i = 0; i < n; i++)\n        if (!used[i])\n            dfs(i);\n}\n
","tags":["Strongly Connected Components","Graph"]},{"location":"graph/topological-sort/","title":"Topological Sort","text":"","tags":["Graph","Topological Sort"]},{"location":"graph/topological-sort/#definition","title":"Definition","text":"

Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge u->v, vertex u comes before v in the ordering. Topological Sorting for a graph is not possible if the graph is not a DAG [6].

There are many important usages of topological sorting in computer science; applications of this type arise in instruction scheduling, ordering of formula cell evaluation when recomputing formula values in spreadsheets, logic synthesis, determining the order of compilation tasks to perform in makefiles, data serialization, and resolving symbol dependencies in linkers. It is also used to decide in which order to load tables with foreign keys in databases [7].

There are known algorithms (e.g Kahn\u2019s algorithm) to find topological order in linear time. Below, you can find one of the implementations:

For example, a topological sorting of this graph is \u201c5 4 2 3 1 0\u201d. There can be more than one topological sorting for a graph. For example, another topological sorting of the following graph is \u201c4 5 2 3 1 0\u201d. The first vertex in topological sorting is always a vertex with in-degree as 0 (a vertex with no incoming edges)[6].","tags":["Graph","Topological Sort"]},{"location":"graph/topological-sort/#algorithm","title":"Algorithm","text":"
typedef vector<int> adjList;\ntypedef vector<adjList> graph;\ntypedef pair<int,int> ii;\n\nvoid kahn(graph &g) {\n    vector<int> result;\n    queue<int> q;\n    vector<int> degree(g.size(),0); // number of incoming egdes.\n    for(auto &list: g){\n        for(auto &node:list) {\n            degree[node]++;\n        } \n    }\n\n    for(int i=0; i < g.size(); ++i) {\n        if (degree[i] == 0)\n        q.push(i);\n    }\n\n    while( !q.empty()) {\n        int node = q.front();\n        result.push_back(node);\n        q.pop();\n\n        for (auto &ng: g[node]) {\n            degree[ng]--;\n            if (degree[ng] == 0)\n                q.push(ng); \n        }\n    }\n\n    for(auto &i:result)\n        cout << i << \" \";\n    cout << endl;\n}\nint main(){\n    graph g(6);\n    g[1].push_back(0);\n    g[1].push_back(2);\n    g[2].push_back(3);\n    g[3].push_back(4);\n    g[4].push_back(5);\n    kahn(g);\n    return 0; \n}\n

As for time complexity: we traverse all edges in the beginning (calculating degrees) and in the while segment we remove edges (once for an edge) and traverse all nodes. Hence, the time complexity of this algorithm is \\(O(V +E)\\). Note that this implementation assumes the graph is DAG. Try improving this code to support checking if the graph is DAG!

","tags":["Graph","Topological Sort"]},{"location":"graph/tree-traversals/","title":"Tree Traversals","text":"

The tree traversal is the process of visiting every node exactly once in a tree structure for some purposes(like getting information or updating information). In a binary tree there are some described order to travel, these are specific for binary trees but they may be generalized to other trees and even graphs as well.

a binary tree","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/tree-traversals/#preorder-traversal","title":"Preorder Traversal","text":"

Preorder means that a root will be evaluated before its children. In other words the order of evaluation is: Root-Left-Right

Preorder Traversal\n    Look Data\n    Traverse the left node\n    Traverse the right node\n

Example: 50 \u2013 7 \u2013 3 \u2013 2 \u2013 8 \u2013 16 \u2013 5 \u2013 12 \u2013 17 \u2013 54 \u2013 9 \u2013 13

","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/tree-traversals/#inorder-traversal","title":"Inorder Traversal","text":"

Inorder means that the left child (and all of the left child\u2019s children) will be evaluated before the root and before the right child and its children. Left-Root-Right (by the way, in binary search tree inorder retrieves data in sorted order)

Inorder Traversal\n    Traverse the left node\n    Look Data\n    Traverse the right node \n

Example: 2 \u2013 3 \u2013 7 \u2013 16 \u2013 8 \u2013 50 \u2013 12 \u2013 54 \u2013 17 \u2013 5 \u2013 9 \u2013 13

","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/tree-traversals/#postorder-traversal","title":"Postorder Traversal","text":"

Postorder is the opposite of preorder, all children are evaluated before their root: Left-Right-Root

Postorder Traversal\n    Traverse the left node\n    Traverse the right node \n    Look Data\n

Example: 2 \u2013 3 \u2013 16 \u2013 8 \u2013 7 \u2013 54 \u2013 17 \u2013 12 \u2013 13 \u2013 9 \u2013 5 \u2013 50

","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/tree-traversals/#implementation","title":"Implementation","text":"
class Node:\n    def __init__(self,key):\n        self.left = None\n        self.right = None\n        self.val = key\n\ndef printInorder(root):\n    if root:\n        printInorder(root.left)\n        print(root.val)\n        printInorder(root.right)\n\ndef printPostorder(root):\n    if root:\n        printPostorder(root.left)\n        printPostorder(root.right)\n        print(root.val)\n\ndef printPreorder(root):\n    if root:\n        print(root.val)\n        printPreorder(root.left)\n        printPreorder(root.right)\n
","tags":["Tree","Preorder","Postorder","Inorder"]},{"location":"graph/union-find/","title":"Union Find","text":"

A disjoint-set data structure is a data structure that keeps track of a set of elements partitioned into a number of disjoint (non-overlapping) subsets. A union-find algorithm is an algorithm that performs two useful operations on such a data structure: [11, 12]

  • Find: Determine which subset a particular element is in. This can be used for determining if two elements are in the same subset.
  • Union: Join two subsets into a single subset
  • Union-Find Algorithm can be used to check whether an undirected graph contains cycle or not. This is another method based on Union-Find. This method assumes that graph doesn\u2019t contain any self-loops.
  • Most commonly used in kruskal's minumum spanning tree algorithm, it is used to check whether two nodes are in same connected component or not. [10]
","tags":["Graph","Union Find","Disjoint Set Union","DSU"]},{"location":"graph/union-find/#implementation","title":"Implementation","text":"
#include <bits/stdc++.h>\nusing namespace std;\n\ncont int MaxN=100005; // Max number of nodes\n\nint ancestor[MaxN];\n\nint parent(int k) // return the ancestor\n{\n    if(ancestor[k]==k) return k;\n    return ancestor[k] = parent(ancestor[k]); \n    // do not forget to equlize ancestor[k], it is going to decrease time complexity for the next operations\n}\n\nint MakeUnion(int a,int b) // setting parent of root(a) as root(b).\n{\n    a = parent(a);\n    b= parent(b);\n    ancestor[a] = b;\n}\nint find(int a,int b)\n{\n    return parent(a)==parent(b);\n}\n
","tags":["Graph","Union Find","Disjoint Set Union","DSU"]},{"location":"graph/union-find/#complexity","title":"Complexity","text":"

Using both path compression, splitting, or halving and union by rank or size ensures that the amortized time per operation is only \\(\\mathcal{O}(\\alpha (n))\\), which is optimal, where \\(\\alpha (n)\\) is the inverse Ackermann function. This function has a value \\(\\alpha (n)<5\\) for any value of n that can be written in this physical universe, so the disjoint-set operations take place in essentially constant time.

","tags":["Graph","Union Find","Disjoint Set Union","DSU"]},{"location":"introduction/","title":"Introduction","text":"

Editor: Muhammed Burak Bu\u011frul

Reviewers: Kadir Emre Oto & Yusuf Hakan Kalayc\u0131

"},{"location":"introduction/#introduction","title":"Introduction","text":"

First of all, this is an intensive algorithm programme prepared by inzva, which includes lectures, contests, problem-solvings and a variety of practises. \"Competitive Programming\" term will be mentioned frequently in this programme, especially for it's community, help in progress in algorithms and data structures etc.

Just for a quick cover up we will have a look at what happens when you compile and run a program, basic data types and functions. After that, we will examine C++ Standard Template Library(STL), time complexity and memory space.

"},{"location":"introduction/#command-line","title":"Command Line","text":"

A lot of people don't use command line if they can use an alternative. There are powerful IDEs (Integrated Development Environments) and they really make programming easier in some aspects. However, knowing how to use command line is important, especially for competitive programming. Firstly, it gives a low level knowledge and full control; secondly, every computer and environment has command line interface.

In this document, you will find only a basic introduction to the command line, which is no more than the basic usage of a file system, compiler, and programs.

There are a lot of differences between command line of Windows and Linux. But the differences between those of Mac and Linux are less.

"},{"location":"introduction/#linux-and-mac","title":"Linux and Mac","text":"

Mac users can use the built-in Terminal. You can find it by searching from Spotlight. Linux users can use gnome-terminal or any other installed one. Again, you can find them by using the built-in search tab.

Some basic commands:

  • ls list files in current directory. Usage: ls
  • cd change directory. Usage: cd ~/Desktop
  • mkdir make a new directory. Usage: mkdir directory_name
  • mv move command (cut). Usage: mv source_path destination_path
  • cp copy command. Usage: cp source_path destination_path
  • rm remove command. Usage: rm file_path

You can read more about the unix command line at: http://linuxcommand.org

"},{"location":"introduction/#compiling-and-executing-programs","title":"Compiling and Executing Programs","text":""},{"location":"introduction/#g","title":"G++","text":"

G++ is installed in Linux environments but in Mac, you should install Xcode first.

You can compile your cpp souce file by typing g++ source.cpp. Default output of this command is a.out.

"},{"location":"introduction/#running-executable-files","title":"Running Executable Files","text":"

For Linux and Mac, the command to run a program is ./program_name. If you use default g++ command, the name of your program will be a.out, so you should type ./a.out in order to run it.

"},{"location":"introduction/#closing-a-program","title":"Closing a Program","text":"

When you want to kill a program in running step, you can simply hit Control + C.

When you want to suspend a program in running step, you can simply hit Control + Z.

When you want to register EOF on standart input, you can simply hit Control + D.

"},{"location":"introduction/#inputoutput-redirection","title":"Input/Output Redirection","text":"

You can redirect input and output streams of a program by using command line and it is surprisingly easy.

"},{"location":"introduction/#saving-output-to-a-file","title":"Saving Output to a File","text":"

The only thing you need is > symbol. Just add it at the end of your run command with the output file name: ./a.out > output.txt

Note: This redirection process creates output.txt if it doesn't exist; otherwise deletes all content in it, then writes into it. If you want to use > in appending mode you should use >> instead.

"},{"location":"introduction/#reading-input-from-a-file","title":"Reading Input from a File","text":"

It is almost the same as output file redirection. The symbol is < now. Usage: ./a.out < input.txt

This will make your job easier than copying and pasting input to test your program, especially in the contests.

"},{"location":"introduction/#using-both-at-the-same-time","title":"Using Both at the Same Time","text":"

One of the wonderful things about these redirections is that they can be used at the same time. You can simply add both to the end of your run command: ./a.out < input.txt > output.txt

"},{"location":"introduction/#pipe","title":"pipe","text":"

Sometimes, you may want to redirect the output of a program to another program as input. You can use the | symbol for this. Usage: ./program1 | ./program2

"},{"location":"introduction/#diff","title":"diff","text":"

As the name denotes, it can check two files line by line if they are the same or not. If not, it outputs different lines. Usage: diff file1.txt file2.txt

It is very useful for comparing output of brute force solution and real solution.

"},{"location":"introduction/#structs-and-classes","title":"Structs and Classes","text":"

In almost every programming language, you can define your own data type. C++ has structs, classes; Python has dictionaries, classes etc. You can think of them as packets that store more than one different data and implement functions at the simplest level. They have a lot more abilities than these two (You can check OOP out).

Let us examine a fraction struct written in C++.

We need to store two values for a fraction, numerator and denominator.

struct Fraction {\n  int numerator, denominator;\n};\n

This is the simplest definition of a struct. Fraction struct contains two int variables. We call them members. So, Fraction struct has two members called numerator and denominator.

#include <cstdio>\n\nstruct Fraction {\n    int numerator, denominator;\n};\n\nFraction bigFraction(Fraction a, Fraction b) {\n\n    if( a.numerator * b.denominator > a.denominator * b.numerator )\n        return a;\n\n    return b;\n}\n\nint main() {\n    // Create two Fractions in order to compare them\n    Fraction a, b;\n\n    a.numerator = 15;\n    a.denominator = 20;\n\n    b.numerator = 12;\n    b.denominator = 18;\n\n    // Create a new Fraction in order to store biggest of Fraction a and Fraction b.\n    fraction biggest = bigFraction(a, b);\n\n    printf(\"The biggest fraction is %d / %d\\n\", biggest.numerator, biggest.denominator);\n    return 0;\n}\n

Let us do the same in Python3:

class Fraction:\n\n    def __init__(self, numerator, denominator):\n        self.numerator, self.denominator = numerator, denominator\n\ndef bigFraction(a, b):\n\n    if a.numerator * b.denominator > a.denominator * b.numerator:\n        return a\n\n    return b\n\na, b = Fraction(15, 20), Fraction(12, 18)  # Create two Fractions in order to compare them\nbiggest = bigFraction(a, b)\n\nprint(biggest.numerator, biggest.denominator)\n

In the sample codes above, a, b and biggest are called objects of Fraction. Also, the word instance can be used instead of object.

"},{"location":"introduction/#the-arrow-operator-c","title":"The Arrow Operator (C++)","text":"

Sometimes, usage of struct can change in C++. When you have a pointer to a struct, you should use -> to access its members instead of . operator. If you still want to use . operator, you should do in this way: (*ptr).member. But arrow operator is simpler: ptr->member.

"},{"location":"introduction/#big-o-notation","title":"Big O Notation","text":"

When dealing with algorithms or coming up with a solution, we need to calculate how fast our algorithm or solution is. We can calculate this in terms of number of operations. Big \\(\\mathcal{O}\\) notation moves in exactly at this point. Big \\(\\mathcal{O}\\) notation gives an upper limit to these number of operations. The formal definition of Big \\(\\mathcal{O}\\) is [1].

Let \\(f\\) be a real or complex valued function and \\(g\\) a real valued function, both defined on some unbounded subset of the real positive numbers, such that \\(g(x)\\) is strictly positive for all large enough values of \\(x\\). One writes:

\\[f(x) = \\mathcal{O}{(g(x))} \\ as\\ x \\rightarrow \\infty\\]

If and only if for all sufficiently large values of x, the absolute value of \\(f(x)\\) is at most a positive constant multiple of \\(g(x)\\). That is, \\(f(x)\\) = \\(\\mathcal{O}{(g(x))}\\) if and only if there exists a positive real number \\(M\\) and a real number \\(x_0\\) such that:

\\[|f(x)| \\leq Mg(x)\\ for \\ all\\ x\\ such\\ that\\ x_0 \\leq x\\]

In many contexts, the assumption that we are interested in the growth rate as the variable \\(x\\) goes to infinity is left unstated, and one writes more simply that:

\\[f(x) = \\mathcal{O}(g(x))\\]

Almost every case for competitive programming, basic understanding of Big \\(\\mathcal{O}\\) notation is enough to decide whether to implement a solution or not.

Note: Big \\(\\mathcal{O}\\) notation can be used for calculating both the run time complexity and the memory space used.

"},{"location":"introduction/#recursion","title":"Recursion","text":"

Recursion occurs when functions repeat themselves in order to create repeated applications or solve a problem by handling smaller situations first. There are thousands of examples in mathematics. One of the simple ones is factorial of \\(n\\). It can be shown by \\(n!\\) in mathematics and it gives the product of all positive integers from \\(1\\) to \\(n\\), for example, \\(4! = 1\\cdot 2\\cdot 3\\cdot 4 = 24\\). If we write factorial in a mathematical way, it will be:

\\[ \\begin{align*} f(n) &= \\begin{cases} 1 & \\text{if $n = 0$\\,\\, } \\\\ n \\cdot f(n - 1) & \\text{if $n > 0$\\,\\,} \\end{cases} \\end{align*} \\]

The reason why we didn't simply write it as \\(f(n) = n \\cdot f(n-1)\\) is that it doesn't give sufficient information about function. We should know where to end the function calls, otherwise it can call itself infinitely. Ending condition is \\(n = 0\\) here. We call it base case. Every recursive function needs at least one base case.

So if we write every step of \\(f(4)\\), it will be:

\\[ \\begin{align*} 4! &= 4\\cdot f(3) && \\text{recursive step} \\\\ &= 4\\cdot 3\\cdot f(2) && \\text{recursive step} \\\\ &= 4\\cdot 3\\cdot 2\\cdot f(1) && \\text{recursive step} \\\\ &= 4\\cdot 3\\cdot 2\\cdot 1\\cdot f(0) && \\text{recursive step} \\\\ &= 4\\cdot 3\\cdot 2\\cdot 1\\cdot 1 && \\text{base case} \\\\ &= 24 && \\text{arithmetic} \\end{align*} \\]

Basically, we can apply this recursive logic into programming:

int factorial(int n) {\n    int result = 1;\n    for(int i = 1; i <= n; i++)\n        res *= i;\n    return result;\n}\n

We can say a function is a recursive if it calls itself. Let us change this iterative factorial function into a recursive one. When you imagine how the recursive code will look like, you will notice it will look like the mathematical one:

int factorial(int n) {\n    if(n == 0)\n        return 1;\n    return n * factorial(n - 1);\n}\n

Note that we didn't forget to put our base case into the recursive function implementation.

"},{"location":"introduction/#time-complexity","title":"Time Complexity","text":"

In case above, it can be seen that both recursive and iterative implementations of factorial function runs in \\(\\mathcal{O}{(n)}\\) time. But this equality doesn't occur always. Let us examine fibonacci function, it is mathematically defines as:

\\[ \\begin{align*} f(n) &= \\begin{cases} 1 & \\text{if $n = 0$ or $n = 1$\\,\\, } \\\\ f(n - 1) + f(n - 2) & \\text{if $n > 1$\\,\\,} \\end{cases} \\end{align*} \\]

We can implement this function with just one for loop:

int fibonacci(int n) {\n    int result = 1, previous = 1;\n    for (int i = 2; i <= n; i++) {\n        int tmp = result;\n        result += previous;\n        previous = tmp;\n    }\n    return result;\n}\n

Again, we can implement recursive one according to the mathematical formula:

int fibonacci(int n) {\n    if( n == 0 || n == 1 )\n        return 1;\n    return fibonacci(n - 1) + fibonacci(n - 2);\n}\n

Let us calculate time complexity of iterative one. There are three basic operations inside a for loop that repeats \\(n-2\\) times. So time complexity is \\(\\mathcal{O}(n)\\). But what about the recursive one? Let us examine its recursion tree(diagram of function calls) for \\(n = 5\\) on visualgo.

\\(f\\) function called more than one for some values of n. Actually in every level, number of function calls doubles. So time complexity of the recursive implementation is \\(\\mathcal{O}{(2^n)}\\). It is far away worse than the iterative one. Recursive one can be optimized by techniques like memoization, but it is another topic to learn in further weeks.

"},{"location":"introduction/#mutual-recursion","title":"Mutual Recursion","text":"

Mutual recursion occurs when functions call each other. For example function f calls another function g, which also somehow calls f again.

Note: When using mutual recursions in C++, don't forget to declare one of the functions so that the other function can know first one from its' prototype.

Note 2: You can chain more than two functions and it will be still a mutual recursion.

"},{"location":"introduction/#enumeration-and-brute-force","title":"Enumeration and Brute-Force","text":"

Enumeration is numbering method on a set.

For example, permutation is one of enumeration techniques. First permutation of numbers in range \\(1\\) and \\(n\\) is:

\\[1, 2, 3... n-1, n\\]

And second one is:

\\[1, 2, 3... n, n-1\\]

Finally, the last one is:

\\[n, n-1... 3, 2, 1\\]

Additionally, we can try to enumerate all possible distributions of \\(n\\) elements into 3 different sets. An example of a distribution of 5 elements can be represented as:

\\[1, 1, 2, 1, 3\\]

In this distribution the first, the second and the fourth elements goes into the first set; third element goes into second set and the last element goes into the third set.

Enumerations can be done with recursive functions easily. We will provide example implementations of 3-set one. But before examining recursive implementation, let us try to implement iterative one:

#include <cstdio>\n\nint main(){\n\n    for( int i=1 ; i<=3 ; i++ )\n        for( int j=1 ; j<=3 ; j++ )\n            for( int k=1 ; k<=3 ; k++ )\n                for( int l=1 ; l<=3 ; l++ )\n                    for( int m=1 ; m<=3 ; m++ )\n                        printf(\"%d %d %d %d %d\\n\", i, j, k, l, m);\n\n    return 0;\n}\n

It will print all possible distributions of 5 elements into 3 sets. But what if we had 6 elements? Yes, we should have added another for loop. What if we had \\(n\\) elements? We can not add infinite number of for loops. But we can apply same logic with recursive functions easily:

#include <cstdio>\n\nint ar[100];\n\nvoid enumerate( int element, int n ){\n\n    if( element > n ){ // Base case\n\n        for( int i=1 ; i<=n ; i++ )\n            printf(\"%d \", ar[i]);\n\n        printf(\"\\n\");\n        return;\n    }\n\n    for( int i=1 ; i<=3 ; i++ ){\n        ar[element] = i;\n        enumerate(element + 1, n);\n    }\n}\n\nint main(){\n    enumerate(1, 5);\n    return 0;\n}\n

Brute-Force is trying all cases in order to achieve something(searching best, shortest, cheapest etc.).

One of the simplest examples of brute-forces approaches is primality checking. We know that for a prime \\(P\\) there is no positive integer in range \\([2, P-1]\\) that evenly divides \\(P\\). We can simply check all integers in this range to decide if it is prime:

bool isPrime(int N) {\n    for( int i=2 ; i<N ; i++ )\n        if( N % i == 0 )\n            return false;\n    return true;\n}\n

It is a simple function, but its' time complexity is \\(\\mathcal{O}(N)\\). Instead we can benefit from the fact if there is a positive integer \\(x\\) that evenly divides \\(N\\), there is a positive integer \\(\\frac{N}{x}\\) as well. As we know this fact, we can only check the integer in range \\([2, \\sqrt{N}]\\):

bool isPrime(int N) {\n    for( int i=2 ; i*i <= N ; i++ )\n        if( N % i == 0 )\n            return false;\n    return true;\n}\n

Now, its' time complexity is \\(\\mathcal{O}{(\\sqrt{N})}\\). It is far away better than \\(\\mathcal{O}{(N)}\\).

"},{"location":"introduction/#built-in-data-structures-and-functions","title":"Built-In Data Structures and Functions","text":"

There is no need to reinvent the wheel. Every language has its' own built in data structures, functions etc. After this point, the document will be C++ centered. But Python alternatives will be given.

"},{"location":"introduction/#the-c-standard-template-library-stl","title":"The C++ Standard Template Library (STL)","text":"

The STL is a well known library for C++ that includes variety of data structures and algorithms.

Note: Third party libraries generally not allowed in contests.

"},{"location":"introduction/#pairs","title":"Pairs","text":"

C++: Sometimes you may need to store two elements for an object. We can do this by creating a struct/class or two dimensional array. They will all work well but using pairs will be much more easier. You can think of pair as a class that has two variables named first and second. That's all for the basic. The good part is, you can decide their types(int, double, your own struct/class etc.). An example for pairs in C++:

#include <iostream>\n\nusing namespace std;\n\nint main(){\n\n    pair<int, int> p(1, 2);\n    pair<int, string> p2;\n\n    p2.first = 3;\n    p2.second = \"Hey there!\";\n\n    pair<pair<int, string>, string> nested;\n\n    nested.first = p2;\n    nested.second = \"This is a nested one\";\n\n    cout << \"Info of p -> \" << p.first << \" \" << p.second << endl;\n    cout << \"Info of p2 -> \" << p2.first << \" \" << p2.second << endl;\n    cout << \"Info of nested -> \" << nested.first.first << \" \" << nested.first.second\n            << \" \" << nested.second << endl;\n\n    return 0;\n}\n

Python: You can simply create a tuple or an array:

p = (1, 2)\np2 = [1, \"Hey there!\"]\nnested = ((3, \"inner?\"), \"outer\", \"this is a tuple you can add more\")\n\np2[0] = 3\n# nested[0] = \"don't\"  # In python you can't change tuples, but you can change arrays\n\nprint(p, p2, nested)\n
"},{"location":"introduction/#vectors","title":"Vectors","text":"

C++: When using array, we should decide its size. What if we don't have to do this, what if we could add elements into it without considering the current size? Well, all these ideas take us to vectors.

C++ has this structure. Its name is vector. It is a dynamic array but you don't have to think about its size. You can simply add elements into it. Like pairs, you can use it with any type (int, double, another vector, your struct/class etc.). Usage of a vector is very similar to classic array:

#include <iostream>\n#include <vector>\n\nusing namespace std;\n\nint main(){\n\n    vector<int> ar;\n\n    for( int i=0 ; i<10 ; i++ )\n        ar.push_back(i);\n\n    for( int i=0 ; i<(int)ar.size() ; i++ )\n        cout << ar[i] << \" \";\n\n    cout << endl;\n    return 0;\n}\n

Python: Python lists already behave like vectors:

ar = []\n\nfor i in range(10):\n    ar.append(i)\n\nprint(ar)\n
"},{"location":"introduction/#stacks-queues-and-deques","title":"Stacks, Queues, and Deques","text":"

C++: They are no different than stack, queue and deque we already know. It provides the implementation, you can simply include the libraries and use them. See queue, stack, deque.

"},{"location":"introduction/#priority-queues","title":"Priority Queues","text":"

It is basically a built-in heap structure. You can add an element in \\(\\mathcal{O}(logN)\\) time, get the first item in \\(O(logN)\\) time. The first item will be decided according to your choice of priority. This priority can be magnitude of value, enterence time etc.

C++: The different thing for priority queue is you should add #include <queue>, not <priority_queue>. You can find samples here. Again, you can define a priority queue with any type you want.

Note: Default priority_queue prioritizes elements by highest value first. Here is three ways of defining priority.

Python: You can use heapq in python.

"},{"location":"introduction/#sets-and-maps","title":"Sets and Maps","text":"

C++: Now that we mentioned binary trees (heap above), we can continue on built-in self balanced binary trees. Sets are key collections, and maps are key-value collections. Sets are useful when you want to add/remove elements in \\(\\mathcal{O}(logN)\\) time and also check existence of an item(key) in \\(O(logN)\\) time. Maps basically do the same but you can change value associated to a key without changing the position of the key in the tree. You can check c++ references for set and map. You can define them with any type you want. If you want to use them with your own struct/class, you must implement a compare function.

Python: You can use dictionaries for map and sets for set in python without importing any other libraries.

"},{"location":"introduction/#iterators","title":"Iterators","text":"

C++: You can use iterators for every built-in data structure in C++ for pointing their objects.

Python: You can iterate through any iterable in python by using in. You can check this example.

"},{"location":"introduction/#sorting","title":"Sorting","text":"

C++: In almost every language, there is a built-in sort function. C++ has one as well. It runs in \\(\\mathcal{O}(N log N)\\) time. You can pass your own compare function into sort function of C++.

Python: You can use sort function for any list or list like collection in order to sort them or if you don't want to change the original collection, you can use sorted() function instead. You can pass your own compare function into sort function of python by using key variable.

"},{"location":"introduction/#suggested-readings","title":"Suggested Readings","text":""},{"location":"introduction/#c","title":"C++","text":"
  • next_permutation: Link
  • STL document: Link
  • binary_search: Link
  • upper_bound: Link
  • lower_bound: Link
  • reverse: Link
  • fill: Link
  • count: Link
"},{"location":"introduction/#python","title":"Python","text":"
  • bisect: Link
  • collections: Link
  • built-in functions: Link
  • lambda: Link
"},{"location":"introduction/#references","title":"References","text":"
  1. Landau, Edmund (1909). Handbuch der Lehre von der Verteilung der Primzahlen [Handbook on the theory of the distribution of the primes] (in German). Leipzig: B. G. Teubner. p. 31.
"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..0d8f77b --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,183 @@ + + + + https://inzva.github.io/Algorithm-Program/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/algorithms/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/deque/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/fenwick-tree/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/linked-list/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/lowest-common-ancestor/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/mo-algorithm/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/prefix-sum/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/queue/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/segment-tree/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/sparse-table/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/sqrt-decomposition/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/stack/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/data-structures/trie/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/bitmask-dp/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/common-dp-problems/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/digit-dp/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/dp-on-dags/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/dp-on-rooted-trees/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/dynamic-programming/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/greedy-algorithms/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/tree-child-sibling-notation/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/dynamic-programming/walk-counting-with-matrix/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/binary-search-tree/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/bipartite-checking/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/breadth-first-search/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/bridges-and-articulation-points/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/cycle-finding/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/definitions/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/depth-first-search/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/heap/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/introduction/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/max-flow/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/minimum-spanning-tree/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/representing-graphs/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/shortest-path/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/strong-connectivity-and-biconnectivity/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/strongly-connected-components/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/topological-sort/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/tree-traversals/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/graph/union-find/ + 2025-03-07 + + + https://inzva.github.io/Algorithm-Program/introduction/ + 2025-03-07 + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..388260df50c80541c3a65eceb6a19a62be6c6c06 GIT binary patch literal 656 zcmV;B0&o2viwFn+H_B%M|8r?{Wo=<_E_iKh0L_`rZrd;n$M1cLAa})ChhZN`Q|z+y z4%-7L5@QRIL{+5gWKTcJNsAtO+W^ytBqC(_2Z|K`bas#D6j#qsDPVqBf7oo-E65Ig z$o<3m_pcx3%ldJDw;O9D;FV0y^spY7%eStZrfEZgA=yG3tbIprkO6f!W4GOWUGMK! zaS=h<%hz{7ah1nj=Y9;=L!`B|~AHg&tM&3}8lB~Iw~_uKnV zX8X}>Kg*Px?fSg#^@0EPX!~NJB`LgRYl!RUc&wlb#lzDGnt+awr{GS8E2!d%A)mmT z7>HG2;RM9SVM>^d%}z#GH4!E>uUV*xt5i6Kv!PKHm1Lu?d?e@-WLB4tRBRDs($E^}j?Gtd+anQ3`IcX1KKY1ymTMK29oo+UMD zfGO$%Y5-f7r;ymK=tbZ!TuiPs$)3$I;-r8?f;WxHNavb!t7SUQ>k360F}Rl3*`y%5 zXu!(t#a6MbAhD!jMe&ZqoI&FHIq+pZwGZK~NegGZypW27pI<~|P*G193r6gNv(b=j qumYl{gSp!F7mAGvTr}n;09wgilI8y#;qw;(@Bac&`SL8M8UO%uBu%IQ literal 0 HcmV?d00001 diff --git a/static/img/favicon.png b/static/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..15c2cae8b1f5eccffd5c166e4a724f8eab82f126 GIT binary patch literal 11695 zcmX9^2RxPU+dnqhdu8vvDcQ0jdqg%xc4a4f%a*+f;@UrpG(e)y>tvs~wvj zeQxHw)l7fex=b~J1#=X=o0vqQo4h*#{e@=S-9?R?>p+*wHlO5-0eSWV83VJIZ9X;e zS^NfrcRI_O0kA-{uQ3}gP%(*ly&G;(rzn=S$YQ+-IrLqW5j56kO zMl*&6CcKoz2}Xo;AsXjj|0ew5>VO^GS-sLBLWSqnWJ-jNQpm|&{jz0&e&jgQcGD;d60uQHeQ_sgI3~MMg&l57;U^dPFt!RHP+sVk?w)FyRTcnVH$<=BAvT9Y>`h z&$sNmXfeIPsi_pA;^Kv6WjF*8JuDVUtU|#P!rI+qe&fPAtIekTeB;li#v&P4Bl}q| z8FRZVElF??j)Jfngof^zuuEf)OQT}ylg|q-vwNP8stnz|yozdTiBC^YORK7S$BI;R%*DX8hgu1AfNzvEU?N|b_7k}^OXo`x8=2uq} zL=ez*f6KX7`*K6`wyghcgr#ssdWyamZ)SY^iHQJq^B;m{yaI+)K4(_r)WoEu;KD*? zG71Xo)&HW>rF?`}S69hMVmR{QEIFfPaLP_KF0)cm6mS&Tcy8J<`w1e@IJ9#Aiz4OF ze*8ElDT%~sshtkqLC;T#)+gMJK-aeoU<{zwK!2$Gt;k}HREanvBjeF$Hzo=J^Ea>% zRt^ppUS7Pwy0MEh&64CqBfd62;vq*A(MszF^bG`Rvd47Y4h@Cx-eJ5t``!CzZ(hg5 zB>MH=KV5K^Nvuyhy=w!};GEq;gzU zru=CN++{ew2CE9`bGe>hJ?}f1u4#OwtLEG|Ken(CTVBqclA5|2aPyaeo0}V9nh+Tx zr(l_Wmk1A?RX?xb?T8V#v$o0H$AY^0`orVAo7?KCyz>73GS=4CWJ&i^pAhya47%kj z3hr$GKy*5?9S!Ve(_WzPlirMN9T>bOJml8%0s!%S7@(> zO#^%OE#<3FwSRtHaa*1&)8pjh>pfcvh$oaemm6#HRx9_^I?T_}f8tDtOBo&$7+qcV zJ0r!-L3XxKDaNgj&MUvP6#Ln;XPG3iX9Z<+qn%-x>t+2gS@!6Dr)m^gfy4pjUDHKw#*XznIV8yeAJnF`Lr>Ty&e&bb3 z+VmM&9WQCtu(E@LLx0_q!TvYYB9WZY_sNtD?LPWHqoc*c{FB8QP46-MPMsnX>ZcXBjq?$^%m{kP)w;bv@YahpCT1HnTZPNk(T|4}bd)kB z?*DL+P>!Vui=g+#_WJQ0>%CUqZ>!?bv&jQS?zT8{mchD+tgr~)!Og9$py8*AUS1L= zCMKg}V<;6qLnK}ttIZX(POan4QFFX=rK3 ze*AdDq7s+?=@Uf+A;Xt4y^_)I-=h~7&D}jcSBEl0c4e+ADBxjPto;0>pv)4})5pDe zgU8CsYI${jNOjMX7r7%JJ_!Ez-+zqk?8=EM4ei@HQ5!Yu_ws4@({TCt_-5N)Ni4oT zGlPm1zL4C}k(vJ5QuXc&A?!^ruVhx7fq?<EE6erZcgucZb@jKOzOp#j zZ!CL4x5ylF(6g&K)JTZYgMN7bjJ2Kr1enZ6__;|*3a|#5I_utBx&{X8R)-Z;9u~_rWmQ#d zBhqKL)gC<1l}fHbgLqz~jr~IWP=Qdbk22+f)a62qK)Y%j-M#mW^sak%Zxht~#}X>Y zCC~RA_V{S}v1?)&E+zL7lNyN-6`sFZaLn6}tZ`%ZtV&8sYq1iGjO**`#cgd1MfIl! z40XK85HVpNSwj;hO0<%1uFpDHWo7eVx5HkAx0jq2dTzLJZLWAdi78agef9h9`0VUv znxo>N>=!~6ikPs<$Bl76{QvIVI(k*spRe{&ahyQm*in>bpw;KNe^8)9esJdNyxq3U2J=- zw?BazKo{^3GT6AoUz&w>NxW6`Br%x4oab$gs#=n&ySu2*Uc*deuk|7Ky8U|DseFSD zEJ`(%@3AroDXBE}yQ!YGE!m!&^A+uX(s?7Ttx`vqJ2lD8&60)^i%&JN4{ujr?6jY+ z;=br5H{#44nMq_gCDlJLsZGJwuYC=-R<*Gy3f6{VWWwNjA*&DeANoOla9}&myCwO#bu7Q<x*uwi?!t9+S;)leNru9*AMf1wu7mBYh73j`cNzQCdUc1X=G1cTljR$ zsySY2RLE?diP(K(y}6v}P<{9ipM|RC{lW4^?#0r#Txs=1|G&;8baZ>C88YJs3evU* zm$-a*Q)0iHcldRUj5Z2*kDIe6wrt<_684x0*}?XP8|F){@ zyY8DrKD)Jjvyr_O;+=QNgU%SrS=W^!EXdIUE6v+7A)$TWzSv$YH+PtvoV)nOmQfOF%5GP*pYa?zL#3CidE z3Wswe0U9#GUrJ*CG|7}mNJtd?|IRNZeflJ>RB*9ax~{OifGeIAd-ZQW!0zl9xkpam z1BHYA{f-;|7f>aKHLF~(uBTSq65yTOwT+EeAGu_`WPgaTne&AFq0%86F!Nea(#(}A zoBO%xWin0En;~M?FME9$Z{@mdsj2^3t|%m)YD{70&lpcp~$Ea{=y&Bs^( z7yVGk`p4g?iX3 zWhEEoyn-2{OOMEhznm9de7{DY4sCHqH`onb8qcp!3 zuYGn{>k|xgcgjIawkj_5kS;k2K9l(et1ABIST!G$ajX1|mG5vg4xf8={x}v820rY&SKgsquIBA2(JRH9MRj_oh zgQ6vMh<+EUc3y>GtJUfD)SLdR501ha?z#jDN1yB!$&`}P(o_HtiFqv@?y1V|&o{5`Vo^Am#8mK_keWy9du#senxMu z%?xLrxQvhMT;|KJncw?z{qOJLN(4i zMTB^A>ng_LDtK~chR2s^U#DckZMzNU;lqb(VU*^h?oPh*3@S1-=j=HmSDXRT!y>ig1h zPJ_;{NKKbUyZn8IfGgsFtDg+ym{_r{LwR8ZKUV|eY0rUV6hM`J{XU}{7ZiNTmnW-_#_K>f#=nhjTIxO(OllC6z zy*%B~F*N+bYsdZQoUsr=L_rY_I|gC$PBvcuV6X(e_-o0fv^0%8{@I1x+==wR`1w8M zCr{YKon{fs-35Lh4;*GKF%m%?3j}6L8!V_bT1wpwx0lK8l^Lz7+ zKjAnK{Mab+L{gK5>FHDe^oD<$2Pr(1tHH}3*GOW8y3Qgky&#~MO|g2iHBnkxO4a`? zUNRgJ8gt2wjf&I|VreA`TUs77$!+q0Zt;1$yaHfxna^lEp>W-ovjN5i9-yeOYK+6f zLm6BwQ=%0JR8Afq8|rsK?H+gn=<=2;{#$NN7i)iFf}|;l zwadEJawJ!JS2FWCT^FwT!}7ASpectZ&5Qz4n`-JpLPALXCZdh%rb^oJe)T*zF(svV zQ;cjeeDeEu6MZA2SA4~B%cxp1%h}h9b8}m@cY-Y3NN8ze29i1IZ!m;eR%eJbT&aM) zhK8coWW4`xZNR|7qK2ri`8Q>&c5*yXFvNtYghc(wl`mpBn@luALsd&lML{9B+hQ|5 ztw#WLd|w*ZW+lp={o5G<`@|nd2nvF$5EIE>x==xP7p^GS82aQy=NJHNwcb|sRK~%qpe;Fsw3oIrVLY# zUl&S)N%83`MMX4T3f%dXQg)tGtoOymA8yX?4R1H1vxerwALj*J-vvH2*NxgavBimv z3c>z-bCjt=xPZlb<@Y+TRg<7vchfe@k5cGO4m$59AX ztgDRK#KS~}%e`zW1QA;QSP^r&TB zS63JHyXQ)B;C62j5cbWnqH`d+qd$IB9{7?fST>j(0<8RbJR*Dcm~fQ1HUH8K=o&yl zvK2$l(&ebgNJ~<3|D}!&YLib+)X;3dynkkEto-;ft<2SdV(a;848mRgOc&uHpur)lE0R|}X%#p&@9Rex)Fbul zim6*_NwcVi{x^*v(z2>KvFh(LZQ-It^D$$i4t)E@{x9H-9HUo(XG$arZdd2e-{(6FQ*Ki=<$qz5{Wm?ME9K8Wn>Xg#iC%0) zcmA)a`SAI(pi8f^mWO*ke-2RC&l7szjh6h75T{P+zT|2VLy5^Es?wP+UC1z4>+wdg zlrraFJg(XL{GC^bFe!=sm-C42zy2yRr4CQTv&2Gl4ne7sH!?DkwXK;I$GX#Z>j?UiR9^3mcN>h&RbubAx7uSHzqjmg| z_wU(nOL+?}|J^~KTpRz#ZjYzO3(--6X`>B1iM=)t<=WpP4RMQN}!{5?K7sCn7@n{P}Z4r#SnVF%beH zx)XV`S4vl=3EX&@gm zgcjDQ8bam!Z?@KkJYr58gjH}eY;Laq-2tH6kvm-f&cc^*A(R9PAh;B-H|e^TS(ec@ zg7GvmMWZm-3>vFAqmh=3v2jMklU*!y%Y;fx<5Vm0EMqsC%)4}5g#J^va(b7wn)5`T zk-)j3$Q{zMnVOl={n=ltxvNAON&dt2pu{RXBBFk1TXMM{v7{-Ajq=tK2L}gf#@N~x zcPqTdjN~0W2Pi$OLvSUHC8kg=i?O-A9Xzwss>hq#+TGeAx_1HV~k9D zuuAvgseF9y#-zMY^}Q~&aX`ha#2PoZYA`{`KF-|f6MVyKkDnGwguDb4Yy^Kol#7B_ zlj&@Wm%zQi?CZYy!|H97aS624z&c)$jhB%7Lr?3OHM8TEF{e<0G>e^J3d7H z8h9U22i3tbR3f!3$5#apia!4Z9CG^&;as|Ly@%@ zB<5Q-okj2H%0u}vHx~tn4K%O#C`Y<3obQHyCn2;hpHWs;R&Ip^GfWZCOGPFnC0$Et z3W*X#r>}acfb5JEd_|rPjSfgC$Q6AbpZ)go*H9OrNGnkqF@rKl9DM_Wg4){Wog?&Q zsJeswd!9&}3PhbDnrR{7&Kj3oC{4P0dULL={+pgH&^@(HOv-&Oy3}=c4+;##!zx? z-AR)01#hLQ1nIDV?B=H`sf_9Jc?AlSeRgaB- z93b)sO612-8Z@;oftW16XcBb(F4{X3Iqkwtr--#kq(39UFqlXb>~s8U1#C8}nQ}^Y zaPE-6PE1TJM0{dBCeU9^zCB@*YXKzewpVA?U+j$}AR zD_N0>i?()AH^c)d@Bdw09Fr>qS#a6Z&mHVFE){lJ*blb^^e-iQ>H1fG!pRZ zcp+Bk0I106=!`XC<#JTU#h{%=+kMx>3<*ly`^r=EUyj$}K%vFqe}(&mbdsT`J2O3d zo+4XR{mrtjR3Ffbd7ex)V-8yabI{C@3Gfqy-%IB*OF zA8Nk9qqaxdc`uZ#1gVhxN9uC3DE-cJ=0IG9kn7)oM*i#?SDLj@(26@zCB@nW5osq6 zi*mQuC_ZbyxqgN8B*A<#Ha0fTNk92ON*98)IMuCHA$`z^#>vZTTi|suN3dPS36L3t zjjr!8t`ZCmDHf8`N{1n%YJ1>qkb#NXaXD2ZT2s`f>1?pGDSOUW@80y55j$PXkpk(N z0k-7%gNjBO?hHP&L51PUXn~@})at&N=@;8hj=h6@yPnafR;T>9Y zW6Ar)2Jt|UY!{k6fG(}RXu@U+1urRnB0g2X;+tk$p>uDCLjwb<>DL(xbbXv{1*xlp z9$Sbcq=Ii?$`W0u*~+9U^(-kld0>000t6t!=Pe7j#&wuU6jYx*C@cbp- zV>zlLrgY7wL(Sp0JVp>i6k%aupa1@DnG-C?s}nuf#)=PEjp7h=oaO}!yKVsCpQ)e3 zdRx*R8Rs?L+qxq@0nSm`2)HIMOD<9Pc z7r%SQ^*!Ddw|;K-;TbK(`4k!oQPEiGIX^ddG=dRUX$wqiErd{pac*udI(I4}siFj- ztD{2G{w2WFWdp>w{^@AXqpU z1~yxt6j!q3a$dPL*$$BCnwkzpeo>dX1p6eRrsF!Z`2BnC?*oH^6>r1o{;^xZVyGot zZu?wcYz#Cm`Ku%Ssj!d5QT}~KA7wONH8%y~nn!>Eg0yOgS{AAq=^ET|n2PJ`lbse@ zGkDEg(-&0s8V(YJG5;|$B1p)|mB0+tygn(B1=pP9f6fqS!11@H^p>L19u=v?vjc;* zS<_ROk-YLhTku)~H^5F;-`V@z`>A%pQrnEZXcCa97oZg;m*o0J@BU~?2C5e&b=1#t zi)8%km`6|h&Pm+8-;DRXezVr`@|;LHIBAnqgQcdCD>cV6cSU6tOn_GYIVFXx&VG#f zXh>uv0i5MTDBg*%z%1~@9IsUvf~9v3Bswne=Q;vplV3>TJTYbmkHOvDJz+%V?;B*Y zoG4ZOJw0rd@3PeTjCtE2NU{Kj2`mESkODM{_KRP%rms(@pn}LLD`QUASj22B7UAojYb`)Y{rwB;*D^{R0dt@IL;82X!mt6RTe_D18uAD_!otA70HWTrkrxmL`+x^i5;Wbr@p!yu&17Ju%T~8vI(*uWtag7- z{1Aufj_(Plx&Orzq|S|4u1Bkw@fxqex_6`4#=ppc1G6){gVCsceSJTnwBHB(21JGt z8x;iVaNvSJe0QplBpA&9_UlW>N{bG9p!2)_el_bMeC0e@1X_L?WZ&Jc&MFzpZyeR) zg94X?O22XZi?a}vwE2REtTLaWf5A9I=hyt)JZD!|6(uDMqzmJB*h`5V5XsPRGJcJq zBB?fg6HER26MWt*rz5|<=H^-3(K5$%11sKeqe;iR^(0mRcsQRoa$mU( z@-;GYaA3h~f>RKJp@$j)&QJ_w9ZiK{RrjyqENSv7-`k{@O~^FGp29iy|dNCZ#|5Ew5mu4KOFTCiv6o=@RgW93hcm^Ham_*~Fg96S+@YSdCbX+tDxr)2>kBtbC8;G@HqMI$5aQ$a zK9pDp-KlONz@^}od+;E-Q14)H6Cz~Fp%>P3kau&1WdV_tR}>_x@(llTV9!4U`6X*X zrnh^55ED8~a4`OE+MvI$tlaI=$O0T=Z*T7r%sCiVJ_-Wq^2f^&>Hd)s6~MLJJUlwO zy1`HqSHTAWWf6ERZ@zfV%fk_T9Gsv97rUKJdo(o4VoC$rR*8lY%oM47zlCylzn+QHx`AaF|}+~#HV)16We zj;gO9@6*$JFQXuH2oN~z6eu4^zkj;gECxy^U_eT!KKB6kVJl#RHxT98et`*SAh6fk ziiz#Kpnv`v(<5S(M!BtPKB0oX&PQ5MK!C9R>2Nown~7OjF+w(9KpIq&7cIv<+J9_f z0`N8(Dh?Ky8&H*oMn}07Em%<7hU`$VaC#c4NA(hBeyj!@qNc;ru(+aEv@P-Po4uacv^6xBUd11sd z$kGG9oNanpf_1lnl_}4HuP4OSN$&0&+E``Nm&0Pn(I^-(67<;C2TFwlDgrhk;f(2X z4KfPq3RaMna5bP6kbHCxS`Wq_X!c+%f+NJi_kH8jezue~W z)b+6#C;04LPa9}S-+d|Qx%|I>w zRi_TA#Ocw|P=Zhr5+0}~4}`+N$S;1Dpi@g74HisvCO+ zvFIMXDD{|J$Gd{eP~{>Wp|d71h)jLf-=<4?aKG2c2nJvSj}HAmG&IyZA+GVisfib@ zVQM%lu^**MSH`EN!axJD-1wF=+u%qE0_k&5(|X?!xps~3+tZ^~Wy;+MPGUFXl`YqY zZyofii}*)t?9Kjq`$_>DkXzjIpI@xTi`D+O!*z8;w6uejKN1p%A`AP&Z4uFB!k2h_ z35|$gfoy=28CuTYC@!UI z1uY9H%)EMq3}oQ;Zs!M9(4-6N>PWx~j`q{5`}1z*)aD$2Tby8f=vk*@tRucLnbd`M z;Q>i<#PoP6oc9}gX&Mm9;cUP!Mg<3kh?*KFc>r97%E;td7*6~D`P*zsk6YlC+dDXn zo34+~Bs}O@DSwwkm`5+D@ZIyituET7uKhlhjZ#iNnnM5#%jZjn4ykD(g8T@}dy+g|Y literal 0 HcmV?d00001 diff --git a/static/img/logo.png b/static/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c2928d2d2e36a3b8ce75f9561f17dfa851cc278f GIT binary patch literal 25654 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 { + renderMathInElement(body, { + delimiters: [ + { left: "$$", right: "$$", display: true }, + { left: "$", right: "$", display: false }, + { left: "\\(", right: "\\)", display: false }, + { left: "\\[", right: "\\]", display: true } + ], + }) +}) \ No newline at end of file diff --git a/static/stylesheets/main.css b/static/stylesheets/main.css new file mode 100644 index 0000000..029fe9f --- /dev/null +++ b/static/stylesheets/main.css @@ -0,0 +1,4 @@ +.md-sidebar--primary { + display: none; + visibility: hidden; +}

How to Use This Site