From 70bdf5ed11395aee16383eb3b9abfbd358b07eb1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 18:30:53 +0000 Subject: [PATCH] deploy: d91860e0f7cf3559656da1923f015cc8b76edd98 --- 404.html | 8 ++++---- CNAME | 1 - ...009d3.7e268ae7.js => 1e2009d3.e75c8998.js} | 2 +- ...3321d.eae7bdb9.js => 2523321d.85fed179.js} | 2 +- ...9abcd.29ada0be.js => 2a09abcd.ae41ee68.js} | 2 +- ...bc122.cdd2fcf0.js => 337bc122.53d298b4.js} | 2 +- ...f3aa1.4c98e03e.js => 377f3aa1.27922c0d.js} | 2 +- ...4b779.a33bbff3.js => 3da4b779.f7a9f496.js} | 2 +- ...247b5.4bd0c3fd.js => 3de247b5.ed11a74c.js} | 2 +- ...0b1a9.e4798bae.js => 4200b1a9.7692be27.js} | 2 +- ...86f4e.b0df1295.js => 4e286f4e.d6756c5b.js} | 2 +- ...12fa2.4d63da2f.js => 4ee12fa2.1cedc9fe.js} | 2 +- ...24505.ab30cae6.js => 51624505.5d814829.js} | 2 +- ...b7838.e5a05e06.js => 713b7838.f48c11a2.js} | 2 +- ...ccf44.5b6f1b34.js => 75cccf44.4b938733.js} | 2 +- ...cc978.7cfa1cd4.js => 788cc978.6c7e62a6.js} | 2 +- ...94373.373d5a6c.js => 7cf94373.7832df69.js} | 2 +- ...80cdb.fae43e52.js => 7d580cdb.21c0eb66.js} | 2 +- ...ed470.ae70d26f.js => 834ed470.15bfe5dc.js} | 2 +- ...f91d3.d0466885.js => 83bf91d3.e7bae794.js} | 2 +- ...25ffc.955d8c56.js => 90425ffc.a4229fd7.js} | 2 +- ...41f0b.79e14732.js => 95f41f0b.6fe751ba.js} | 2 +- ...50c57.bc586b34.js => 9eb50c57.23f36b2e.js} | 2 +- ...e6ffb.f8d1346f.js => a2be6ffb.7a939c96.js} | 2 +- ...48ea2.d5faeb42.js => a6a48ea2.50fc62cb.js} | 2 +- ...721d4.e0b371f9.js => ab2721d4.319c2058.js} | 2 +- ...b72a7.1e28998e.js => af8b72a7.7e44f77a.js} | 2 +- ...32f14.3c491fc9.js => b5a32f14.bd4170d8.js} | 2 +- ...1ccdc.859f8a18.js => b9b1ccdc.11390f7f.js} | 2 +- ...82650.671a659f.js => bb882650.2bca4416.js} | 2 +- ...2b263.c19c407b.js => cfa2b263.0d6e56da.js} | 2 +- ...7fb17.fd985da7.js => d7f7fb17.d47054f6.js} | 2 +- ...2ebad.0c0a899d.js => dff2ebad.f70dfd2d.js} | 2 +- ...be158.eaa96907.js => f48be158.6dc62990.js} | 2 +- ...3ef4a.6b0877e2.js => f533ef4a.e27803af.js} | 2 +- ...c832f.d6dc7ae0.js => f60c832f.186a1d8e.js} | 2 +- ...91f97.acb581ec.js => fcc91f97.9c27af9a.js} | 2 +- .../js/{main.5876beef.js => main.a28961b3.js} | 4 ++-- ...CENSE.txt => main.a28961b3.js.LICENSE.txt} | 0 ...n.98394322.js => runtime~main.295aa6bf.js} | 2 +- blog/2023/08/02/copr/index.html | 10 +++++----- blog/aoc-2022/1st-week/index.html | 10 +++++----- blog/aoc-2022/2nd-week/index.html | 10 +++++----- blog/aoc-2022/3rd-week/index.html | 10 +++++----- blog/aoc-2022/4th-week/index.html | 10 +++++----- blog/aoc-2022/intro/index.html | 10 +++++----- blog/archive/index.html | 8 ++++---- blog/index.html | 8 ++++---- blog/leetcode/sort-diagonally/index.html | 10 +++++----- blog/tags/admin/index.html | 8 ++++---- blog/tags/advent-of-code-2022/index.html | 8 ++++---- blog/tags/advent-of-code/index.html | 8 ++++---- blog/tags/copr/index.html | 8 ++++---- blog/tags/cpp/index.html | 8 ++++---- blog/tags/index.html | 8 ++++---- blog/tags/iterators/index.html | 8 ++++---- blog/tags/leetcode/index.html | 8 ++++---- blog/tags/red-hat/index.html | 8 ++++---- blog/tags/rust/index.html | 8 ++++---- blog/tags/vps/index.html | 8 ++++---- blog/tags/🏭/index.html | 8 ++++---- contributions/index.html | 8 ++++---- .../graphs/iterative-and-iterators.tar.bz2 | Bin 1940 -> 1932 bytes .../graphs/iterative-and-iterators.tar.gz | Bin 1959 -> 1960 bytes files/ib002/recursion/karel-1.tar.bz2 | Bin 5879 -> 5888 bytes files/ib002/recursion/karel-1.tar.gz | Bin 6586 -> 6587 bytes .../recursion/pyramid-slide-down.tar.bz2 | Bin 1541 -> 1546 bytes .../ib002/recursion/pyramid-slide-down.tar.gz | Bin 1421 -> 1421 bytes files/ib002/time-complexity/extend.tar.bz2 | Bin 4076 -> 4077 bytes files/ib002/time-complexity/extend.tar.gz | Bin 3909 -> 3915 bytes files/pb071/bonuses/03.tar.bz2 | Bin 2654 -> 2655 bytes files/pb071/bonuses/03.tar.gz | Bin 2338 -> 2336 bytes files/pb071/bonuses/04.tar.bz2 | Bin 2524 -> 2549 bytes files/pb071/bonuses/04.tar.gz | Bin 2498 -> 2501 bytes files/pb071/bonuses/05-06.tar.bz2 | Bin 3638 -> 3628 bytes files/pb071/bonuses/05-06.tar.gz | Bin 3489 -> 3489 bytes files/pb071/bonuses/08.tar.bz2 | Bin 76259 -> 76286 bytes files/pb071/bonuses/08.tar.gz | Bin 106557 -> 106563 bytes files/pb071/bonuses/10.tar.bz2 | Bin 234829 -> 234823 bytes files/pb071/bonuses/10.tar.gz | Bin 230107 -> 230108 bytes .../postcondition-ambiguity/index.html | 10 +++++----- .../algorithms-and-correctness/index.html | 8 ++++---- .../index.html | 8 ++++---- ib002/category/graphs/index.html | 8 ++++---- ib002/category/recursion/index.html | 8 ++++---- ib002/category/red-black-trees/index.html | 8 ++++---- ib002/graphs/bfs-tree/index.html | 10 +++++----- .../graphs/iterative-and-iterators/index.html | 10 +++++----- ib002/index.html | 10 +++++----- ib002/rb-trees/applications/index.html | 10 +++++----- ib002/rb-trees/rules/index.html | 10 +++++----- ib002/recursion/karel-1/index.html | 10 +++++----- ib002/recursion/pyramid-slide-down/index.html | 10 +++++----- ib002/tags/applications/index.html | 8 ++++---- ib002/tags/backtracking/index.html | 8 ++++---- ib002/tags/balanced-trees/index.html | 8 ++++---- ib002/tags/bfs/index.html | 8 ++++---- ib002/tags/bottom-up-dp/index.html | 8 ++++---- ib002/tags/c/index.html | 8 ++++---- ib002/tags/csharp/index.html | 8 ++++---- ib002/tags/dynamic-array/index.html | 8 ++++---- ib002/tags/dynamic-programming/index.html | 8 ++++---- ib002/tags/exponential/index.html | 8 ++++---- ib002/tags/graphs/index.html | 8 ++++---- ib002/tags/greedy/index.html | 8 ++++---- ib002/tags/index.html | 8 ++++---- ib002/tags/iterative/index.html | 8 ++++---- ib002/tags/iterators/index.html | 8 ++++---- ib002/tags/java/index.html | 8 ++++---- ib002/tags/karel/index.html | 8 ++++---- ib002/tags/postconditions/index.html | 8 ++++---- ib002/tags/python/index.html | 8 ++++---- ib002/tags/recursion/index.html | 8 ++++---- ib002/tags/red-black-trees/index.html | 8 ++++---- ib002/tags/sorting/index.html | 8 ++++---- ib002/tags/testing/index.html | 8 ++++---- ib002/tags/time-complexity/index.html | 8 ++++---- ib002/tags/top-down-dp/index.html | 8 ++++---- ib002/time-complexity/extend/index.html | 10 +++++----- index.html | 8 ++++---- pb071/bonuses/seminar-03/index.html | 10 +++++----- pb071/bonuses/seminar-04/index.html | 10 +++++----- pb071/bonuses/seminar-05-06/index.html | 10 +++++----- pb071/bonuses/seminar-08/index.html | 10 +++++----- pb071/bonuses/seminar-10/index.html | 10 +++++----- pb071/category/bonuses/index.html | 8 ++++---- pb071/category/practice-exams/index.html | 8 ++++---- pb071/index.html | 10 +++++----- pb071/mr/index.html | 10 +++++----- pb071/pexam/cams/index.html | 10 +++++----- pb071/pexam/garbage_collect/index.html | 10 +++++----- pb161/environment/index.html | 10 +++++----- pb161/index.html | 10 +++++----- search/index.html | 8 ++++---- talks/index.html | 8 ++++---- 135 files changed, 377 insertions(+), 378 deletions(-) delete mode 100644 CNAME rename assets/js/{1e2009d3.7e268ae7.js => 1e2009d3.e75c8998.js} (99%) rename assets/js/{2523321d.eae7bdb9.js => 2523321d.85fed179.js} (98%) rename assets/js/{2a09abcd.29ada0be.js => 2a09abcd.ae41ee68.js} (99%) rename assets/js/{337bc122.cdd2fcf0.js => 337bc122.53d298b4.js} (58%) rename assets/js/{377f3aa1.4c98e03e.js => 377f3aa1.27922c0d.js} (99%) rename assets/js/{3da4b779.a33bbff3.js => 3da4b779.f7a9f496.js} (99%) rename assets/js/{3de247b5.4bd0c3fd.js => 3de247b5.ed11a74c.js} (99%) rename assets/js/{4200b1a9.e4798bae.js => 4200b1a9.7692be27.js} (99%) rename assets/js/{4e286f4e.b0df1295.js => 4e286f4e.d6756c5b.js} (99%) rename assets/js/{4ee12fa2.4d63da2f.js => 4ee12fa2.1cedc9fe.js} (95%) rename assets/js/{51624505.ab30cae6.js => 51624505.5d814829.js} (99%) rename assets/js/{713b7838.e5a05e06.js => 713b7838.f48c11a2.js} (99%) rename assets/js/{75cccf44.5b6f1b34.js => 75cccf44.4b938733.js} (98%) rename assets/js/{788cc978.7cfa1cd4.js => 788cc978.6c7e62a6.js} (99%) rename assets/js/{7cf94373.373d5a6c.js => 7cf94373.7832df69.js} (98%) rename assets/js/{7d580cdb.fae43e52.js => 7d580cdb.21c0eb66.js} (99%) rename assets/js/{834ed470.ae70d26f.js => 834ed470.15bfe5dc.js} (96%) rename assets/js/{83bf91d3.d0466885.js => 83bf91d3.e7bae794.js} (98%) rename assets/js/{90425ffc.955d8c56.js => 90425ffc.a4229fd7.js} (99%) rename assets/js/{95f41f0b.79e14732.js => 95f41f0b.6fe751ba.js} (98%) rename assets/js/{9eb50c57.bc586b34.js => 9eb50c57.23f36b2e.js} (97%) rename assets/js/{a2be6ffb.f8d1346f.js => a2be6ffb.7a939c96.js} (99%) rename assets/js/{a6a48ea2.d5faeb42.js => a6a48ea2.50fc62cb.js} (98%) rename assets/js/{ab2721d4.e0b371f9.js => ab2721d4.319c2058.js} (81%) rename assets/js/{af8b72a7.1e28998e.js => af8b72a7.7e44f77a.js} (98%) rename assets/js/{b5a32f14.3c491fc9.js => b5a32f14.bd4170d8.js} (99%) rename assets/js/{b9b1ccdc.859f8a18.js => b9b1ccdc.11390f7f.js} (99%) rename assets/js/{bb882650.671a659f.js => bb882650.2bca4416.js} (68%) rename assets/js/{cfa2b263.c19c407b.js => cfa2b263.0d6e56da.js} (99%) rename assets/js/{d7f7fb17.fd985da7.js => d7f7fb17.d47054f6.js} (98%) rename assets/js/{dff2ebad.0c0a899d.js => dff2ebad.f70dfd2d.js} (99%) rename assets/js/{f48be158.eaa96907.js => f48be158.6dc62990.js} (99%) rename assets/js/{f533ef4a.6b0877e2.js => f533ef4a.e27803af.js} (98%) rename assets/js/{f60c832f.d6dc7ae0.js => f60c832f.186a1d8e.js} (99%) rename assets/js/{fcc91f97.acb581ec.js => fcc91f97.9c27af9a.js} (99%) rename assets/js/{main.5876beef.js => main.a28961b3.js} (99%) rename assets/js/{main.5876beef.js.LICENSE.txt => main.a28961b3.js.LICENSE.txt} (100%) rename assets/js/{runtime~main.98394322.js => runtime~main.295aa6bf.js} (56%) diff --git a/404.html b/404.html index dca9ae1..16a5dec 100644 --- a/404.html +++ b/404.html @@ -13,13 +13,13 @@ - - + +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - + + \ No newline at end of file diff --git a/CNAME b/CNAME deleted file mode 100644 index 4c91a2c..0000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -blog.mfocko.xyz \ No newline at end of file diff --git a/assets/js/1e2009d3.7e268ae7.js b/assets/js/1e2009d3.e75c8998.js similarity index 99% rename from assets/js/1e2009d3.7e268ae7.js rename to assets/js/1e2009d3.e75c8998.js index bd0120c..3fc7665 100644 --- a/assets/js/1e2009d3.7e268ae7.js +++ b/assets/js/1e2009d3.e75c8998.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3906],{3905:(e,a,t)=>{t.d(a,{Zo:()=>m,kt:()=>u});var n=t(7294);function r(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function l(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var a=1;a=0||(r[t]=e[t]);return r}(e,a);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=n.createContext({}),p=function(e){var a=n.useContext(s),t=a;return e&&(t="function"==typeof e?e(a):o(o({},a),e)),t},m=function(e){var a=p(e.components);return n.createElement(s.Provider,{value:a},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},k=n.forwardRef((function(e,a){var t=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),c=p(t),k=r,u=c["".concat(s,".").concat(k)]||c[k]||d[k]||l;return t?n.createElement(u,o(o({ref:a},m),{},{components:t})):n.createElement(u,o({ref:a},m))}));function u(e,a){var t=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var l=t.length,o=new Array(l);o[0]=k;var i={};for(var s in a)hasOwnProperty.call(a,s)&&(i[s]=a[s]);i.originalType=e,i[c]="string"==typeof e?e:r,o[1]=i;for(var p=2;p{t.r(a),t.d(a,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var n=t(7462),r=(t(7294),t(3905));const l={id:"applications",title:"Pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f",description:"Uk\xe1zka pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f v standardn\xedch kni\u017enic\xedch zn\xe1m\xfdch jazyk\u016f.\n",tags:["balanced trees","red-black trees","applications"],last_update:{date:new Date("2022-04-05T00:00:00.000Z")}},o=void 0,i={unversionedId:"rb-trees/applications",id:"rb-trees/applications",title:"Pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f",description:"Uk\xe1zka pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f v standardn\xedch kni\u017enic\xedch zn\xe1m\xfdch jazyk\u016f.\n",source:"@site/ib002/08-rb-trees/2022-04-05-applications.md",sourceDirName:"08-rb-trees",slug:"/rb-trees/applications",permalink:"/ib002/rb-trees/applications",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/08-rb-trees/2022-04-05-applications.md",tags:[{label:"balanced trees",permalink:"/ib002/tags/balanced-trees"},{label:"red-black trees",permalink:"/ib002/tags/red-black-trees"},{label:"applications",permalink:"/ib002/tags/applications"}],version:"current",lastUpdatedAt:1649116800,formattedLastUpdatedAt:"Apr 5, 2022",frontMatter:{id:"applications",title:"Pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f",description:"Uk\xe1zka pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f v standardn\xedch kni\u017enic\xedch zn\xe1m\xfdch jazyk\u016f.\n",tags:["balanced trees","red-black trees","applications"],last_update:{date:"2022-04-05T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Red-Black Trees",permalink:"/ib002/category/red-black-trees"},next:{title:"On the rules of the red-black tree",permalink:"/ib002/rb-trees/rules"}},s={},p=[{value:"Pou\u017eit\xed",id:"pou\u017eit\xed",level:2},{value:"R\u016fzn\xe9 implementace",id:"r\u016fzn\xe9-implementace",level:2},{value:"C++",id:"c",level:3},{value:"clang",id:"clang",level:4},{value:"gcc",id:"gcc",level:4},{value:"Java",id:"java",level:3},{value:"C#",id:"c-1",level:3},{value:"Vztah mezi mno\u017einou a mapou",id:"vztah-mezi-mno\u017einou-a-mapou",level:2}],m={toc:p},c="wrapper";function d(e){let{components:a,...t}=e;return(0,r.kt)(c,(0,n.Z)({},m,t,{components:a,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"pou\u017eit\xed"},"Pou\u017eit\xed"),(0,r.kt)("p",null,"\u010cerveno-\u010dern\xe9 stromy jsou celkem obl\xedben\xe9 pro implementaci ADT mno\u017einy nebo slovn\xedku za p\u0159edpokladu, \u017ee nad vkl\xe1dan\xfdmi kl\xed\u010di existuje uspo\u0159\xe1d\xe1n\xed. Jazyky n\xed\u017ee implementuj\xed dan\xe9 datov\xe9 struktury v 2 variant\xe1ch a to:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"se\u0159azen\xe9: pou\u017e\xedvaj\xed na pozad\xed pr\xe1v\u011b \u010derveno-\u010dern\xfd strom"),(0,r.kt)("li",{parentName:"ul"},"nese\u0159azen\xe9: pou\u017e\xedvaj\xed na pozad\xed ha\u0161ovac\xed tabulku")),(0,r.kt)("p",null,"Pro srovn\xe1n\xed, jak jsme si \u0159\xedkali na cvi\u010den\xed, \u010derveno-\u010dern\xfd strom m\xe1 operace hled\xe1n\xed, vkl\xe1d\xe1n\xed a maz\xe1n\xed v \u010dasov\xe9 slo\u017eitosti ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"log"),(0,r.kt)("mo",{parentName:"mrow"},"\u2061"),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(\\log n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mop"},"lo",(0,r.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")"))))),". Na druhou stranu ha\u0161ovac\xed tabulka m\xe1 ide\xe1ln\u011b konstantn\xed \u010dasovou slo\u017eitost, ale v nejhor\u0161\xedm p\u0159\xedpad\u011b (detaily na posledn\xedm cvi\u010den\xed v semestru) je to bohu\u017eel ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")"))))),"."),(0,r.kt)("p",null,"V\xfd\u0161e jsme si uk\xe1zali n\u011bjak\xe9 p\u0159edpoklady nutn\xe9 pro ha\u0161ovac\xed tabulku i \u010derveno-\u010dern\xfd strom. Co je tedy lep\u0161\xed?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"\u010derveno-\u010dern\xfd strom n\xe1m poskytuje ",(0,r.kt)("em",{parentName:"li"},"stabiln\xed \u010dasovou slo\u017eitost"),", ale za cenu po\u017eadavku ",(0,r.kt)("em",{parentName:"li"},"uspo\u0159\xe1d\xe1n\xed")," nad prvky"),(0,r.kt)("li",{parentName:"ul"},"ha\u0161ovac\xed tabulka n\xe1m poskytuje ",(0,r.kt)("em",{parentName:"li"},"pomyslnou perfektn\xed \u010dasovou slo\u017eitost"))),(0,r.kt)("h2",{id:"r\u016fzn\xe9-implementace"},"R\u016fzn\xe9 implementace"),(0,r.kt)("p",null,"Pro uk\xe1zku pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f v implementac\xedch standardn\xedch knihoven\njsme vybrali n\u011bkolik jazyk\u016f."),(0,r.kt)("p",null,"Pokud V\xe1s zaj\xedmaj\xed r\u016fzn\xe9 implementace, tak bychom doporu\u010dili \u201eprohrab\xe1vat\u201c se p\u0159es n\u011b v n\xe1sleduj\xedc\xedm po\u0159ad\xed: ",(0,r.kt)("inlineCode",{parentName:"p"},"C# \u2192 Java \u2192 C++"),". D\u016fvod pro zvolen\xe9 po\u0159ad\xed vych\xe1z\xed z toho, \u017ee C# implementace je pom\u011brn\u011b \u010diteln\xe1 a obsahuje mno\u017estv\xed vysv\u011btluj\xedc\xedch koment\xe1\u0159\u016f. Implementace v Jav\u011b je stejn\u011b \u010diteln\xe1, a\u010dkoli ji\u017e s minimem koment\xe1\u0159\u016f, kter\xe9 se maxim\xe1ln\u011b odkazuj\xed na CLRS. C++ implementace je \u201ezna\u010dn\u011b pozna\u010den\xe1\u201c podtr\u017e\xedtky ;)"),(0,r.kt)("h3",{id:"c"},"C++"),(0,r.kt)("p",null,"V C++ si m\u016f\u017eeme vybrat mezi 2 r\u016fzn\xfdmi implementacemi (",(0,r.kt)("inlineCode",{parentName:"p"},"clang")," nebo ",(0,r.kt)("inlineCode",{parentName:"p"},"gcc"),")."),(0,r.kt)("h4",{id:"clang"},"clang"),(0,r.kt)("p",null,"Hlavi\u010dkov\xe9 soubory, kter\xe9 pou\u017e\xedv\xe1me p\u0159i pr\xe1ci s mno\u017einou nebo slovn\xedkem (zaj\xedmav\xe9 sekce jsou vyta\u017eeny):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/llvm/llvm-project/blob/main/libcxx/include/map"},(0,r.kt)("inlineCode",{parentName:"a"},"map"))),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-cpp"},"template ,\n class _Allocator = allocator > >\nclass _LIBCPP_TEMPLATE_VIS map\n{\npublic:\n // types:\n typedef _Key key_type;\n typedef _Tp mapped_type;\n typedef pair value_type;\n\n// \u2026\n\nprivate:\n typedef __tree<__value_type, __vc, __allocator_type> __base;\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/llvm/llvm-project/blob/main/libcxx/include/set"},(0,r.kt)("inlineCode",{parentName:"a"},"set"))),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-cpp"},"template ,\n class _Allocator = allocator<_Key> >\nclass _LIBCPP_TEMPLATE_VIS set\n{\npublic:\n // types:\n typedef _Key key_type;\n typedef key_type value_type;\n\n// \u2026\n\nprivate:\n typedef __tree __base;\n")))),(0,r.kt)("p",null,"U obou hlavi\u010dek si m\u016f\u017eeme v\u0161imnout, \u017ee deklaruj\xed n\u011bjak\xfd soukrom\xfd typ ",(0,r.kt)("inlineCode",{parentName:"p"},"__base"),", kter\xfd je aliasem pro ",(0,r.kt)("inlineCode",{parentName:"p"},"__tree"),". Ten n\xe1s pak vede k hlavi\u010dce ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/llvm/llvm-project/blob/main/libcxx/include/__tree"},(0,r.kt)("inlineCode",{parentName:"a"},"__tree")),"."),(0,r.kt)("p",null,"V\xfd\u0148atek:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-cpp"},"/*\n\n_NodePtr algorithms\n\nThe algorithms taking _NodePtr are red black tree algorithms. Those\nalgorithms taking a parameter named __root should assume that __root\npoints to a proper red black tree (unless otherwise specified).\n\n\u2026\n\n*/\n")),(0,r.kt)("h4",{id:"gcc"},"gcc"),(0,r.kt)("p",null,"Pro ",(0,r.kt)("inlineCode",{parentName:"p"},"gcc")," je postup t\xe9m\u011b\u0159 stejn\xfd. Pro zm\u011bnu v hlavi\u010dk\xe1ch ",(0,r.kt)("inlineCode",{parentName:"p"},"map")," a ",(0,r.kt)("inlineCode",{parentName:"p"},"set")," nenajdeme nic, deklarace jsou a\u017e v hlavi\u010dkov\xfdch souborech:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/stl_map.h;h=9c2b0745673431b4b396ba27982170478838137e;hb=HEAD"},(0,r.kt)("inlineCode",{parentName:"a"},"bits/stl_map.h"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/stl_set.h;h=9c2b0745673431b4b396ba27982170478838137e;hb=HEAD"},(0,r.kt)("inlineCode",{parentName:"a"},"bits/stl_set.h")))),(0,r.kt)("p",null,"V obou se zase odkazuje na n\u011bjakou hlavi\u010dku ",(0,r.kt)("a",{parentName:"p",href:"https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/stl_tree.h;h=a4de61417652a288e361a55fcc8bb7a9838c58a5;hb=HEAD"},(0,r.kt)("inlineCode",{parentName:"a"},"bits/stl_tree.h")),", zase v\xfd\u0148atek:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-cpp"}," // Red-black tree class, designed for use in implementing STL\n // associative containers (set, multiset, map, and multimap). The\n // insertion and deletion algorithms are based on those in Cormen,\n // Leiserson, and Rivest, Introduction to Algorithms (MIT Press,\n // 1990), except that\n //\n // (1) the header cell is maintained with links not only to the root\n // but also to the leftmost node of the tree, to enable constant\n // time begin(), and to the rightmost node of the tree, to enable\n // linear time performance when used with the generic set algorithms\n // (set_union, etc.)\n //\n // (2) when a node being deleted has two children its successor node\n // is relinked into its place, rather than copied, so that the only\n // iterators invalidated are those referring to the deleted node.\n\n enum _Rb_tree_color { _S_red = false, _S_black = true };\n\n struct _Rb_tree_node_base\n {\n typedef _Rb_tree_node_base* _Base_ptr;\n typedef const _Rb_tree_node_base* _Const_Base_ptr;\n\n _Rb_tree_color _M_color;\n _Base_ptr _M_parent;\n _Base_ptr _M_left;\n _Base_ptr _M_right;\n\n static _Base_ptr\n _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT\n {\n while (__x->_M_left != 0) __x = __x->_M_left;\n return __x;\n }\n\n static _Const_Base_ptr\n _S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT\n {\n while (__x->_M_left != 0) __x = __x->_M_left;\n return __x;\n }\n\n static _Base_ptr\n _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT\n {\n while (__x->_M_right != 0) __x = __x->_M_right;\n return __x;\n }\n\n static _Const_Base_ptr\n _S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT\n {\n while (__x->_M_right != 0) __x = __x->_M_right;\n return __x;\n }\n")),(0,r.kt)("p",null,"Tady u\u017e taky vid\xedme n\u011bjak\xfd k\xf3d pro nalezen\xed minima/maxima ve strom\u011b. Mimo jin\xe9\nje\u0161t\u011b existuje ",(0,r.kt)("a",{parentName:"p",href:"https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/src/c%2B%2B98/tree.cc;h=fd14991589a57c6aa847f57105a938cd2bf4df6f;hb=HEAD"},(0,r.kt)("inlineCode",{parentName:"a"},"tree.cc")),", kde je lze nal\xe9zt t\u0159eba funkci s n\xe1sleduj\xedc\xed hlavi\u010dkou:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-cpp"},"void\n_Rb_tree_insert_and_rebalance(const bool __insert_left,\n _Rb_tree_node_base* __x,\n _Rb_tree_node_base* __p,\n _Rb_tree_node_base& __header) throw ();\n")),(0,r.kt)("h3",{id:"java"},"Java"),(0,r.kt)("p",null,"V Jav\u011b jsou pro n\xe1s kl\xed\u010dov\xe9 implementace ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/TreeSet.java"},(0,r.kt)("inlineCode",{parentName:"a"},"TreeSet"))," a ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/TreeMap.java"},(0,r.kt)("inlineCode",{parentName:"a"},"TreeMap")),"."),(0,r.kt)("p",null,"V implementaci ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeSet")," si m\u016f\u017eete pov\u0161imnout:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-java"},"public class TreeSet extends AbstractSet\n implements NavigableSet, Cloneable, java.io.Serializable\n{\n /**\n * The backing map.\n */\n private transient NavigableMap m;\n\n // Dummy value to associate with an Object in the backing Map\n private static final Object PRESENT = new Object();\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"TreeSet")," v Jav\u011b tedy pou\u017e\xedv\xe1 na pozad\xed ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeMap")," (co\u017e je vid\u011bt ve v\xfdchoz\xedm konstruktoru, kde se vol\xe1 konstruktor p\u0159eb\xedraj\xedc\xed ",(0,r.kt)("inlineCode",{parentName:"p"},"NavigableMap"),", a je mu p\u0159ed\xe1no ",(0,r.kt)("inlineCode",{parentName:"p"},"new TreeMap<>()"),")."),(0,r.kt)("p",null,"Co se t\xfd\u010de ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeMap"),", tak hned ze za\u010d\xe1tku definice ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeMap")," je vid\u011bt:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-java"},'public class TreeMap\n extends AbstractMap\n implements NavigableMap, Cloneable, java.io.Serializable\n{\n /**\n * The comparator used to maintain order in this tree map, or\n * null if it uses the natural ordering of its keys.\n *\n * @serial\n */\n @SuppressWarnings("serial") // Conditionally serializable\n private final Comparator comparator;\n\n private transient Entry root;\n')),(0,r.kt)("p",null,"Tak\u017ee m\xe1me \u201en\u011bjak\xfd ko\u0159en\u201c typu ",(0,r.kt)("inlineCode",{parentName:"p"},"Entry"),". Zkus\xedme si naj\xedt definici dan\xe9ho typu\u2026"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-java"}," // Red-black mechanics\n\n private static final boolean RED = false;\n private static final boolean BLACK = true;\n\n /**\n * Node in the Tree. Doubles as a means to pass key-value pairs back to\n * user (see Map.Entry).\n */\n\n static final class Entry implements Map.Entry {\n K key;\n V value;\n Entry left;\n Entry right;\n Entry parent;\n boolean color = BLACK;\n")),(0,r.kt)("p",null,"A m\xe1me RB-tree."),(0,r.kt)("p",null,"(Implementace vych\xe1z\xed z projektu OpenJDK.)"),(0,r.kt)("h3",{id:"c-1"},"C#"),(0,r.kt)("p",null,"V C# se zam\u011b\u0159\xedme na nejnov\u011bj\u0161\xed vyd\xe1n\xed (.NET), kter\xe9 je open-source a podporov\xe1no i na opera\u010dn\xedch syst\xe9mech zalo\u017een\xfdch na Linuxu."),(0,r.kt)("p",null,"Nejd\u0159\xedve se pod\xedv\xe1me na implementaci slovn\xedku (",(0,r.kt)("a",{parentName:"p",href:"https://github.com/dotnet/runtime/blob/main/src/libraries/System.Collections/src/System/Collections/Generic/SortedDictionary.cs"},(0,r.kt)("inlineCode",{parentName:"a"},"SortedDictionary")),")."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"}," public class SortedDictionary : IDictionary, IDictionary, IReadOnlyDictionary where TKey : notnull\n {\n [NonSerialized]\n private KeyCollection? _keys;\n [NonSerialized]\n private ValueCollection? _values;\n\n private readonly TreeSet> _set; // Do not rename (binary serialization)\n")),(0,r.kt)("p",null,"Na prvn\xed pohled m\xe1me probl\xe9m, proto\u017ee ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeSet")," nen\xed ",(0,r.kt)("inlineCode",{parentName:"p"},"SortedSet"),", kter\xfd by jsme \u010dekali. Kdy\u017e se p\u0159esuneme na konec souboru, tak zjist\xedme, \u017ee ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeSet")," je jenom ",(0,r.kt)("em",{parentName:"p"},"backward-compatible wrapper")," pro ",(0,r.kt)("inlineCode",{parentName:"p"},"SortedSet"),"."),(0,r.kt)("p",null,"P\u0159esuneme se k ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/dotnet/runtime/blob/main/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs"},(0,r.kt)("inlineCode",{parentName:"a"},"SortedSet")),". A hned ze za\u010d\xe1tku vid\xedme:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-cs"},' // A binary search tree is a red-black tree if it satisfies the following red-black properties:\n // 1. Every node is either red or black\n // 2. Every leaf (nil node) is black\n // 3. If a node is red, the both its children are black\n // 4. Every simple path from a node to a descendant leaf contains the same number of black nodes\n //\n // The basic idea of a red-black tree is to represent 2-3-4 trees as standard BSTs but to add one extra bit of information\n // per node to encode 3-nodes and 4-nodes.\n // 4-nodes will be represented as: B\n // R R\n //\n // 3 -node will be represented as: B or B\n // R B B R\n //\n // For a detailed description of the algorithm, take a look at "Algorithms" by Robert Sedgewick.\n\n internal enum NodeColor : byte\n {\n Black,\n Red\n }\n\n internal delegate bool TreeWalkPredicate(SortedSet.Node node);\n\n internal enum TreeRotation : byte\n {\n Left,\n LeftRight,\n Right,\n RightLeft\n }\n')),(0,r.kt)("p",null,"Vysv\u011btlen\xed v koment\xe1\u0159i trochu p\u0159edb\xedh\xe1 n\xe1pl\u0148 cvi\u010den\xed zam\u011b\u0159en\xe9ho na B-stromy ;)"),(0,r.kt)("h2",{id:"vztah-mezi-mno\u017einou-a-mapou"},"Vztah mezi mno\u017einou a mapou"),(0,r.kt)("p",null,"P\u0159i ka\u017ed\xe9 implementaci ve standardn\xed knihovn\u011b jsme si mohli v\u0161imnout, \u017ee strom implementuje v\u017edy jenom jeden typ:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Jazyk"),(0,r.kt)("th",{parentName:"tr",align:null},"Zp\u016fsob implementace"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"C++"),(0,r.kt)("td",{parentName:"tr",align:null},"mapa ukl\xe1d\xe1 dvojice do mno\u017einy")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Java"),(0,r.kt)("td",{parentName:"tr",align:null},"mno\u017eina ukl\xe1d\xe1 prvky s \u201edummy\u201c hodnotou do mapy")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"C#"),(0,r.kt)("td",{parentName:"tr",align:null},"mapa ukl\xe1d\xe1 dvojice do mno\u017einy")))),(0,r.kt)("p",null,"Mapa vy\u017eaduje, aby ka\u017ed\xfd kl\xed\u010d m\u011bl p\u0159i\u0159azenou pr\xe1v\u011b jednu hodnotu, tedy kl\xed\u010de jsou navz\xe1jem mezi sebou unik\xe1tn\xed. To n\xe1m umo\u017e\u0148uje organizovat kl\xed\u010de do mno\u017einy, zde ale naraz\xedme na nep\u0159\xedjemn\xfd probl\xe9m spo\u010d\xedvaj\xedc\xed v tom, \u017ee mus\xedme do mno\u017einy vkladat dvojice prvk\u016f: ",(0,r.kt)("inlineCode",{parentName:"p"},"(key, value)"),". Tenhle p\u0159\xedstup m\xe1 ale z\xe1sadn\xed probl\xe9m:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"# let's represent dictionary/map as a set\nset_of_values = set()\n\n# let's insert few pairs\nset_of_values.add((1, 2))\nset_of_values.add((0, 42))\n\n# let's set key 1 to value 6\nset_of_values.add((1, 6))\n\nset_of_values\n")),(0,r.kt)("p",null,"A dostaneme:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"{(1, 6), (1, 2), (0, 42)}\n")),(0,r.kt)("p",null,"V jednotliv\xfdch implementac\xedch, kter\xe9 jste mohli vid\u011bt v\xfd\u0161e, se vyu\u017e\xedv\xe1 nasleduj\xedc\xed, kdy\u017e:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"mapa ukl\xe1d\xe1 dvojice do mno\u017einy"),": Dvojice je obalen\xe1 v samostatn\xedm typu, kter\xfd porovn\xe1v\xe1 jenom kl\xed\u010de"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"mno\u017eina ukl\xe1d\xe1 kl\xed\u010de do mapy"),": V map\u011b se ignoruj\xed hodnoty p\u0159i\u0159azen\xe9 kl\xed\u010d\u016fm")))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3906],{3905:(e,a,t)=>{t.d(a,{Zo:()=>m,kt:()=>u});var n=t(7294);function r(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function l(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function o(e){for(var a=1;a=0||(r[t]=e[t]);return r}(e,a);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=n.createContext({}),p=function(e){var a=n.useContext(s),t=a;return e&&(t="function"==typeof e?e(a):o(o({},a),e)),t},m=function(e){var a=p(e.components);return n.createElement(s.Provider,{value:a},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},k=n.forwardRef((function(e,a){var t=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),c=p(t),k=r,u=c["".concat(s,".").concat(k)]||c[k]||d[k]||l;return t?n.createElement(u,o(o({ref:a},m),{},{components:t})):n.createElement(u,o({ref:a},m))}));function u(e,a){var t=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var l=t.length,o=new Array(l);o[0]=k;var i={};for(var s in a)hasOwnProperty.call(a,s)&&(i[s]=a[s]);i.originalType=e,i[c]="string"==typeof e?e:r,o[1]=i;for(var p=2;p{t.r(a),t.d(a,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var n=t(7462),r=(t(7294),t(3905));const l={id:"applications",title:"Pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f",description:"Uk\xe1zka pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f v standardn\xedch kni\u017enic\xedch zn\xe1m\xfdch jazyk\u016f.\n",tags:["balanced trees","red-black trees","applications"],last_update:{date:new Date("2022-04-05T00:00:00.000Z")}},o=void 0,i={unversionedId:"rb-trees/applications",id:"rb-trees/applications",title:"Pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f",description:"Uk\xe1zka pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f v standardn\xedch kni\u017enic\xedch zn\xe1m\xfdch jazyk\u016f.\n",source:"@site/ib002/08-rb-trees/2022-04-05-applications.md",sourceDirName:"08-rb-trees",slug:"/rb-trees/applications",permalink:"/ib002/rb-trees/applications",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/08-rb-trees/2022-04-05-applications.md",tags:[{label:"balanced trees",permalink:"/ib002/tags/balanced-trees"},{label:"red-black trees",permalink:"/ib002/tags/red-black-trees"},{label:"applications",permalink:"/ib002/tags/applications"}],version:"current",lastUpdatedAt:1649116800,formattedLastUpdatedAt:"Apr 5, 2022",frontMatter:{id:"applications",title:"Pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f",description:"Uk\xe1zka pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f v standardn\xedch kni\u017enic\xedch zn\xe1m\xfdch jazyk\u016f.\n",tags:["balanced trees","red-black trees","applications"],last_update:{date:"2022-04-05T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Red-Black Trees",permalink:"/ib002/category/red-black-trees"},next:{title:"On the rules of the red-black tree",permalink:"/ib002/rb-trees/rules"}},s={},p=[{value:"Pou\u017eit\xed",id:"pou\u017eit\xed",level:2},{value:"R\u016fzn\xe9 implementace",id:"r\u016fzn\xe9-implementace",level:2},{value:"C++",id:"c",level:3},{value:"clang",id:"clang",level:4},{value:"gcc",id:"gcc",level:4},{value:"Java",id:"java",level:3},{value:"C#",id:"c-1",level:3},{value:"Vztah mezi mno\u017einou a mapou",id:"vztah-mezi-mno\u017einou-a-mapou",level:2}],m={toc:p},c="wrapper";function d(e){let{components:a,...t}=e;return(0,r.kt)(c,(0,n.Z)({},m,t,{components:a,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"pou\u017eit\xed"},"Pou\u017eit\xed"),(0,r.kt)("p",null,"\u010cerveno-\u010dern\xe9 stromy jsou celkem obl\xedben\xe9 pro implementaci ADT mno\u017einy nebo slovn\xedku za p\u0159edpokladu, \u017ee nad vkl\xe1dan\xfdmi kl\xed\u010di existuje uspo\u0159\xe1d\xe1n\xed. Jazyky n\xed\u017ee implementuj\xed dan\xe9 datov\xe9 struktury v 2 variant\xe1ch a to:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"se\u0159azen\xe9: pou\u017e\xedvaj\xed na pozad\xed pr\xe1v\u011b \u010derveno-\u010dern\xfd strom"),(0,r.kt)("li",{parentName:"ul"},"nese\u0159azen\xe9: pou\u017e\xedvaj\xed na pozad\xed ha\u0161ovac\xed tabulku")),(0,r.kt)("p",null,"Pro srovn\xe1n\xed, jak jsme si \u0159\xedkali na cvi\u010den\xed, \u010derveno-\u010dern\xfd strom m\xe1 operace hled\xe1n\xed, vkl\xe1d\xe1n\xed a maz\xe1n\xed v \u010dasov\xe9 slo\u017eitosti ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"log"),(0,r.kt)("mo",{parentName:"mrow"},"\u2061"),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(\\log n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mop"},"lo",(0,r.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")"))))),". Na druhou stranu ha\u0161ovac\xed tabulka m\xe1 ide\xe1ln\u011b konstantn\xed \u010dasovou slo\u017eitost, ale v nejhor\u0161\xedm p\u0159\xedpad\u011b (detaily na posledn\xedm cvi\u010den\xed v semestru) je to bohu\u017eel ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")"))))),"."),(0,r.kt)("p",null,"V\xfd\u0161e jsme si uk\xe1zali n\u011bjak\xe9 p\u0159edpoklady nutn\xe9 pro ha\u0161ovac\xed tabulku i \u010derveno-\u010dern\xfd strom. Co je tedy lep\u0161\xed?"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"\u010derveno-\u010dern\xfd strom n\xe1m poskytuje ",(0,r.kt)("em",{parentName:"li"},"stabiln\xed \u010dasovou slo\u017eitost"),", ale za cenu po\u017eadavku ",(0,r.kt)("em",{parentName:"li"},"uspo\u0159\xe1d\xe1n\xed")," nad prvky"),(0,r.kt)("li",{parentName:"ul"},"ha\u0161ovac\xed tabulka n\xe1m poskytuje ",(0,r.kt)("em",{parentName:"li"},"pomyslnou perfektn\xed \u010dasovou slo\u017eitost"))),(0,r.kt)("h2",{id:"r\u016fzn\xe9-implementace"},"R\u016fzn\xe9 implementace"),(0,r.kt)("p",null,"Pro uk\xe1zku pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f v implementac\xedch standardn\xedch knihoven\njsme vybrali n\u011bkolik jazyk\u016f."),(0,r.kt)("p",null,"Pokud V\xe1s zaj\xedmaj\xed r\u016fzn\xe9 implementace, tak bychom doporu\u010dili \u201eprohrab\xe1vat\u201c se p\u0159es n\u011b v n\xe1sleduj\xedc\xedm po\u0159ad\xed: ",(0,r.kt)("inlineCode",{parentName:"p"},"C# \u2192 Java \u2192 C++"),". D\u016fvod pro zvolen\xe9 po\u0159ad\xed vych\xe1z\xed z toho, \u017ee C# implementace je pom\u011brn\u011b \u010diteln\xe1 a obsahuje mno\u017estv\xed vysv\u011btluj\xedc\xedch koment\xe1\u0159\u016f. Implementace v Jav\u011b je stejn\u011b \u010diteln\xe1, a\u010dkoli ji\u017e s minimem koment\xe1\u0159\u016f, kter\xe9 se maxim\xe1ln\u011b odkazuj\xed na CLRS. C++ implementace je \u201ezna\u010dn\u011b pozna\u010den\xe1\u201c podtr\u017e\xedtky ;)"),(0,r.kt)("h3",{id:"c"},"C++"),(0,r.kt)("p",null,"V C++ si m\u016f\u017eeme vybrat mezi 2 r\u016fzn\xfdmi implementacemi (",(0,r.kt)("inlineCode",{parentName:"p"},"clang")," nebo ",(0,r.kt)("inlineCode",{parentName:"p"},"gcc"),")."),(0,r.kt)("h4",{id:"clang"},"clang"),(0,r.kt)("p",null,"Hlavi\u010dkov\xe9 soubory, kter\xe9 pou\u017e\xedv\xe1me p\u0159i pr\xe1ci s mno\u017einou nebo slovn\xedkem (zaj\xedmav\xe9 sekce jsou vyta\u017eeny):"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/llvm/llvm-project/blob/main/libcxx/include/map"},(0,r.kt)("inlineCode",{parentName:"a"},"map"))),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-cpp"},"template ,\n class _Allocator = allocator > >\nclass _LIBCPP_TEMPLATE_VIS map\n{\npublic:\n // types:\n typedef _Key key_type;\n typedef _Tp mapped_type;\n typedef pair value_type;\n\n// \u2026\n\nprivate:\n typedef __tree<__value_type, __vc, __allocator_type> __base;\n"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("a",{parentName:"p",href:"https://github.com/llvm/llvm-project/blob/main/libcxx/include/set"},(0,r.kt)("inlineCode",{parentName:"a"},"set"))),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre",className:"language-cpp"},"template ,\n class _Allocator = allocator<_Key> >\nclass _LIBCPP_TEMPLATE_VIS set\n{\npublic:\n // types:\n typedef _Key key_type;\n typedef key_type value_type;\n\n// \u2026\n\nprivate:\n typedef __tree __base;\n")))),(0,r.kt)("p",null,"U obou hlavi\u010dek si m\u016f\u017eeme v\u0161imnout, \u017ee deklaruj\xed n\u011bjak\xfd soukrom\xfd typ ",(0,r.kt)("inlineCode",{parentName:"p"},"__base"),", kter\xfd je aliasem pro ",(0,r.kt)("inlineCode",{parentName:"p"},"__tree"),". Ten n\xe1s pak vede k hlavi\u010dce ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/llvm/llvm-project/blob/main/libcxx/include/__tree"},(0,r.kt)("inlineCode",{parentName:"a"},"__tree")),"."),(0,r.kt)("p",null,"V\xfd\u0148atek:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-cpp"},"/*\n\n_NodePtr algorithms\n\nThe algorithms taking _NodePtr are red black tree algorithms. Those\nalgorithms taking a parameter named __root should assume that __root\npoints to a proper red black tree (unless otherwise specified).\n\n\u2026\n\n*/\n")),(0,r.kt)("h4",{id:"gcc"},"gcc"),(0,r.kt)("p",null,"Pro ",(0,r.kt)("inlineCode",{parentName:"p"},"gcc")," je postup t\xe9m\u011b\u0159 stejn\xfd. Pro zm\u011bnu v hlavi\u010dk\xe1ch ",(0,r.kt)("inlineCode",{parentName:"p"},"map")," a ",(0,r.kt)("inlineCode",{parentName:"p"},"set")," nenajdeme nic, deklarace jsou a\u017e v hlavi\u010dkov\xfdch souborech:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/stl_map.h;h=9c2b0745673431b4b396ba27982170478838137e;hb=HEAD"},(0,r.kt)("inlineCode",{parentName:"a"},"bits/stl_map.h"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/stl_set.h;h=9c2b0745673431b4b396ba27982170478838137e;hb=HEAD"},(0,r.kt)("inlineCode",{parentName:"a"},"bits/stl_set.h")))),(0,r.kt)("p",null,"V obou se zase odkazuje na n\u011bjakou hlavi\u010dku ",(0,r.kt)("a",{parentName:"p",href:"https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/stl_tree.h;h=a4de61417652a288e361a55fcc8bb7a9838c58a5;hb=HEAD"},(0,r.kt)("inlineCode",{parentName:"a"},"bits/stl_tree.h")),", zase v\xfd\u0148atek:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-cpp"}," // Red-black tree class, designed for use in implementing STL\n // associative containers (set, multiset, map, and multimap). The\n // insertion and deletion algorithms are based on those in Cormen,\n // Leiserson, and Rivest, Introduction to Algorithms (MIT Press,\n // 1990), except that\n //\n // (1) the header cell is maintained with links not only to the root\n // but also to the leftmost node of the tree, to enable constant\n // time begin(), and to the rightmost node of the tree, to enable\n // linear time performance when used with the generic set algorithms\n // (set_union, etc.)\n //\n // (2) when a node being deleted has two children its successor node\n // is relinked into its place, rather than copied, so that the only\n // iterators invalidated are those referring to the deleted node.\n\n enum _Rb_tree_color { _S_red = false, _S_black = true };\n\n struct _Rb_tree_node_base\n {\n typedef _Rb_tree_node_base* _Base_ptr;\n typedef const _Rb_tree_node_base* _Const_Base_ptr;\n\n _Rb_tree_color _M_color;\n _Base_ptr _M_parent;\n _Base_ptr _M_left;\n _Base_ptr _M_right;\n\n static _Base_ptr\n _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT\n {\n while (__x->_M_left != 0) __x = __x->_M_left;\n return __x;\n }\n\n static _Const_Base_ptr\n _S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT\n {\n while (__x->_M_left != 0) __x = __x->_M_left;\n return __x;\n }\n\n static _Base_ptr\n _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT\n {\n while (__x->_M_right != 0) __x = __x->_M_right;\n return __x;\n }\n\n static _Const_Base_ptr\n _S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT\n {\n while (__x->_M_right != 0) __x = __x->_M_right;\n return __x;\n }\n")),(0,r.kt)("p",null,"Tady u\u017e taky vid\xedme n\u011bjak\xfd k\xf3d pro nalezen\xed minima/maxima ve strom\u011b. Mimo jin\xe9\nje\u0161t\u011b existuje ",(0,r.kt)("a",{parentName:"p",href:"https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/src/c%2B%2B98/tree.cc;h=fd14991589a57c6aa847f57105a938cd2bf4df6f;hb=HEAD"},(0,r.kt)("inlineCode",{parentName:"a"},"tree.cc")),", kde je lze nal\xe9zt t\u0159eba funkci s n\xe1sleduj\xedc\xed hlavi\u010dkou:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-cpp"},"void\n_Rb_tree_insert_and_rebalance(const bool __insert_left,\n _Rb_tree_node_base* __x,\n _Rb_tree_node_base* __p,\n _Rb_tree_node_base& __header) throw ();\n")),(0,r.kt)("h3",{id:"java"},"Java"),(0,r.kt)("p",null,"V Jav\u011b jsou pro n\xe1s kl\xed\u010dov\xe9 implementace ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/TreeSet.java"},(0,r.kt)("inlineCode",{parentName:"a"},"TreeSet"))," a ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/TreeMap.java"},(0,r.kt)("inlineCode",{parentName:"a"},"TreeMap")),"."),(0,r.kt)("p",null,"V implementaci ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeSet")," si m\u016f\u017eete pov\u0161imnout:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-java"},"public class TreeSet extends AbstractSet\n implements NavigableSet, Cloneable, java.io.Serializable\n{\n /**\n * The backing map.\n */\n private transient NavigableMap m;\n\n // Dummy value to associate with an Object in the backing Map\n private static final Object PRESENT = new Object();\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"TreeSet")," v Jav\u011b tedy pou\u017e\xedv\xe1 na pozad\xed ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeMap")," (co\u017e je vid\u011bt ve v\xfdchoz\xedm konstruktoru, kde se vol\xe1 konstruktor p\u0159eb\xedraj\xedc\xed ",(0,r.kt)("inlineCode",{parentName:"p"},"NavigableMap"),", a je mu p\u0159ed\xe1no ",(0,r.kt)("inlineCode",{parentName:"p"},"new TreeMap<>()"),")."),(0,r.kt)("p",null,"Co se t\xfd\u010de ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeMap"),", tak hned ze za\u010d\xe1tku definice ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeMap")," je vid\u011bt:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-java"},'public class TreeMap\n extends AbstractMap\n implements NavigableMap, Cloneable, java.io.Serializable\n{\n /**\n * The comparator used to maintain order in this tree map, or\n * null if it uses the natural ordering of its keys.\n *\n * @serial\n */\n @SuppressWarnings("serial") // Conditionally serializable\n private final Comparator comparator;\n\n private transient Entry root;\n')),(0,r.kt)("p",null,"Tak\u017ee m\xe1me \u201en\u011bjak\xfd ko\u0159en\u201c typu ",(0,r.kt)("inlineCode",{parentName:"p"},"Entry"),". Zkus\xedme si naj\xedt definici dan\xe9ho typu\u2026"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-java"}," // Red-black mechanics\n\n private static final boolean RED = false;\n private static final boolean BLACK = true;\n\n /**\n * Node in the Tree. Doubles as a means to pass key-value pairs back to\n * user (see Map.Entry).\n */\n\n static final class Entry implements Map.Entry {\n K key;\n V value;\n Entry left;\n Entry right;\n Entry parent;\n boolean color = BLACK;\n")),(0,r.kt)("p",null,"A m\xe1me RB-tree."),(0,r.kt)("p",null,"(Implementace vych\xe1z\xed z projektu OpenJDK.)"),(0,r.kt)("h3",{id:"c-1"},"C#"),(0,r.kt)("p",null,"V C# se zam\u011b\u0159\xedme na nejnov\u011bj\u0161\xed vyd\xe1n\xed (.NET), kter\xe9 je open-source a podporov\xe1no i na opera\u010dn\xedch syst\xe9mech zalo\u017een\xfdch na Linuxu."),(0,r.kt)("p",null,"Nejd\u0159\xedve se pod\xedv\xe1me na implementaci slovn\xedku (",(0,r.kt)("a",{parentName:"p",href:"https://github.com/dotnet/runtime/blob/main/src/libraries/System.Collections/src/System/Collections/Generic/SortedDictionary.cs"},(0,r.kt)("inlineCode",{parentName:"a"},"SortedDictionary")),")."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-csharp"}," public class SortedDictionary : IDictionary, IDictionary, IReadOnlyDictionary where TKey : notnull\n {\n [NonSerialized]\n private KeyCollection? _keys;\n [NonSerialized]\n private ValueCollection? _values;\n\n private readonly TreeSet> _set; // Do not rename (binary serialization)\n")),(0,r.kt)("p",null,"Na prvn\xed pohled m\xe1me probl\xe9m, proto\u017ee ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeSet")," nen\xed ",(0,r.kt)("inlineCode",{parentName:"p"},"SortedSet"),", kter\xfd by jsme \u010dekali. Kdy\u017e se p\u0159esuneme na konec souboru, tak zjist\xedme, \u017ee ",(0,r.kt)("inlineCode",{parentName:"p"},"TreeSet")," je jenom ",(0,r.kt)("em",{parentName:"p"},"backward-compatible wrapper")," pro ",(0,r.kt)("inlineCode",{parentName:"p"},"SortedSet"),"."),(0,r.kt)("p",null,"P\u0159esuneme se k ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/dotnet/runtime/blob/main/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs"},(0,r.kt)("inlineCode",{parentName:"a"},"SortedSet")),". A hned ze za\u010d\xe1tku vid\xedme:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-cs"},' // A binary search tree is a red-black tree if it satisfies the following red-black properties:\n // 1. Every node is either red or black\n // 2. Every leaf (nil node) is black\n // 3. If a node is red, the both its children are black\n // 4. Every simple path from a node to a descendant leaf contains the same number of black nodes\n //\n // The basic idea of a red-black tree is to represent 2-3-4 trees as standard BSTs but to add one extra bit of information\n // per node to encode 3-nodes and 4-nodes.\n // 4-nodes will be represented as: B\n // R R\n //\n // 3 -node will be represented as: B or B\n // R B B R\n //\n // For a detailed description of the algorithm, take a look at "Algorithms" by Robert Sedgewick.\n\n internal enum NodeColor : byte\n {\n Black,\n Red\n }\n\n internal delegate bool TreeWalkPredicate(SortedSet.Node node);\n\n internal enum TreeRotation : byte\n {\n Left,\n LeftRight,\n Right,\n RightLeft\n }\n')),(0,r.kt)("p",null,"Vysv\u011btlen\xed v koment\xe1\u0159i trochu p\u0159edb\xedh\xe1 n\xe1pl\u0148 cvi\u010den\xed zam\u011b\u0159en\xe9ho na B-stromy ;)"),(0,r.kt)("h2",{id:"vztah-mezi-mno\u017einou-a-mapou"},"Vztah mezi mno\u017einou a mapou"),(0,r.kt)("p",null,"P\u0159i ka\u017ed\xe9 implementaci ve standardn\xed knihovn\u011b jsme si mohli v\u0161imnout, \u017ee strom implementuje v\u017edy jenom jeden typ:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Jazyk"),(0,r.kt)("th",{parentName:"tr",align:null},"Zp\u016fsob implementace"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"C++"),(0,r.kt)("td",{parentName:"tr",align:null},"mapa ukl\xe1d\xe1 dvojice do mno\u017einy")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Java"),(0,r.kt)("td",{parentName:"tr",align:null},"mno\u017eina ukl\xe1d\xe1 prvky s \u201edummy\u201c hodnotou do mapy")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"C#"),(0,r.kt)("td",{parentName:"tr",align:null},"mapa ukl\xe1d\xe1 dvojice do mno\u017einy")))),(0,r.kt)("p",null,"Mapa vy\u017eaduje, aby ka\u017ed\xfd kl\xed\u010d m\u011bl p\u0159i\u0159azenou pr\xe1v\u011b jednu hodnotu, tedy kl\xed\u010de jsou navz\xe1jem mezi sebou unik\xe1tn\xed. To n\xe1m umo\u017e\u0148uje organizovat kl\xed\u010de do mno\u017einy, zde ale naraz\xedme na nep\u0159\xedjemn\xfd probl\xe9m spo\u010d\xedvaj\xedc\xed v tom, \u017ee mus\xedme do mno\u017einy vkladat dvojice prvk\u016f: ",(0,r.kt)("inlineCode",{parentName:"p"},"(key, value)"),". Tenhle p\u0159\xedstup m\xe1 ale z\xe1sadn\xed probl\xe9m:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"# let's represent dictionary/map as a set\nset_of_values = set()\n\n# let's insert few pairs\nset_of_values.add((1, 2))\nset_of_values.add((0, 42))\n\n# let's set key 1 to value 6\nset_of_values.add((1, 6))\n\nset_of_values\n")),(0,r.kt)("p",null,"A dostaneme:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"{(1, 6), (1, 2), (0, 42)}\n")),(0,r.kt)("p",null,"V jednotliv\xfdch implementac\xedch, kter\xe9 jste mohli vid\u011bt v\xfd\u0161e, se vyu\u017e\xedv\xe1 nasleduj\xedc\xed, kdy\u017e:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"mapa ukl\xe1d\xe1 dvojice do mno\u017einy"),": Dvojice je obalen\xe1 v samostatn\xedm typu, kter\xfd porovn\xe1v\xe1 jenom kl\xed\u010de"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("em",{parentName:"li"},"mno\u017eina ukl\xe1d\xe1 kl\xed\u010de do mapy"),": V map\u011b se ignoruj\xed hodnoty p\u0159i\u0159azen\xe9 kl\xed\u010d\u016fm")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2523321d.eae7bdb9.js b/assets/js/2523321d.85fed179.js similarity index 98% rename from assets/js/2523321d.eae7bdb9.js rename to assets/js/2523321d.85fed179.js index 9ccf823..85afc2c 100644 --- a/assets/js/2523321d.eae7bdb9.js +++ b/assets/js/2523321d.85fed179.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9193],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),u=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return i.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),d=a,k=c["".concat(s,".").concat(d)]||c[d]||m[d]||r;return n?i.createElement(k,o(o({ref:t},p),{},{components:n})):i.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>r,metadata:()=>l,toc:()=>u});var i=n(7462),a=(n(7294),n(3905));const r={id:"seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n"},o="8th seminar bonus assignment",l={unversionedId:"bonuses/seminar-08",id:"bonuses/seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n",source:"@site/pb071/bonuses/08.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-08",permalink:"/pb071/bonuses/seminar-08",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/08.md",tags:[],version:"current",lastUpdatedAt:1694110423,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n"},sidebar:"autogeneratedBar",previous:{title:"5th and 6th seminar",permalink:"/pb071/bonuses/seminar-05-06"},next:{title:"10th seminar",permalink:"/pb071/bonuses/seminar-10"}},s={},u=[{value:"Introduction",id:"introduction",level:2},{value:"Warning",id:"warning",level:2},{value:"Testing",id:"testing",level:2},{value:"Task no. 1: Counting (0.75 K\u20a1)",id:"task-no-1-counting-075-k",level:2},{value:"Requirements",id:"requirements",level:3},{value:"Bonus part (0.75 K\u20a1)",id:"bonus-part-075-k",level:3},{value:"Task no. 2: Weird trees (1 K\u20a1)",id:"task-no-2-weird-trees-1-k",level:2},{value:"Submitting",id:"submitting",level:2}],p={toc:u},c="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(c,(0,i.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"8th-seminar-bonus-assignment"},"8th seminar bonus assignment"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/08.tar.gz"},"Source")),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"In this bonus you can implement two tasks, one of them has a bonus part with generic\nsolution."),(0,a.kt)("p",null,"One is focused on counting ananas or in case of generic version any substring in\nthe file, but with a restriction on the function you use."),(0,a.kt)("p",null,"Other one has a more algorithmic spirit."),(0,a.kt)("p",null,"For this bonus you can get at maximum 2.5 K\u20a1."),(0,a.kt)("h2",{id:"warning"},"Warning"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"DO NOT COMMIT test data")," to your own git repository, since the tests include\nfiles that exceed 10MB by themselves. Even if they are on separate branch, they\ntake up the space."),(0,a.kt)("h2",{id:"testing"},"Testing"),(0,a.kt)("p",null,"For testing you are provided with python script (requires ",(0,a.kt)("inlineCode",{parentName:"p"},"click")," to be installed:\n",(0,a.kt)("inlineCode",{parentName:"p"},"pip3 install --user click"),") and ",(0,a.kt)("inlineCode",{parentName:"p"},"Makefile")," that provides following targets:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check-counting")," - runs the ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," tests"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check-counting-bonus")," - runs the ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," tests with bonus implemented"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check")," - runs both ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"counting-bonus")," tests"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"clean")," - removes output files from the test runs")),(0,a.kt)("h2",{id:"task-no-1-counting-075-k"},"Task no. 1: Counting (0.75 K\u20a1)"),(0,a.kt)("p",null,"Your first task is to make smallish program that counts occurences of specific\n(or given) word from file and writes the number to other file."),(0,a.kt)("p",null,"Usage of the program is:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"Usage: ./counting [string-to-be-counted]\n")),(0,a.kt)("p",null,"Arguments that are passed to the program represent:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"")," - path to the file where we count the words"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"")," - path to the file where we output the count"),(0,a.kt)("li",{parentName:"ul"},"(optional argument) ",(0,a.kt)("inlineCode",{parentName:"li"},"[string-to-be-counted]")," - in case you implement bonus,\notherwise we default to word ",(0,a.kt)("inlineCode",{parentName:"li"},"ananas")," ;)")),(0,a.kt)("p",null,"In skeleton you are given 3 empty, but documented, functions to implement."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"count_anything")," - function accepts input file and substring to be counted in\nthe file, returns the count."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"count_ananas")," - same as ",(0,a.kt)("inlineCode",{parentName:"li"},"count_anything"),", but specialized for ananases, the\ndefault implementation from the skeleton expects you to implement ",(0,a.kt)("inlineCode",{parentName:"li"},"count_anything"),"\nand therefore it just calls the other function."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"write_number")," - function that writes the number to the file, why would you\nneed the function is explained later :)")),(0,a.kt)("h3",{id:"requirements"},"Requirements"),(0,a.kt)("p",null,"For manipulation with the files you are only allowed to use ",(0,a.kt)("inlineCode",{parentName:"p"},"fopen"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"fclose"),",\n",(0,a.kt)("inlineCode",{parentName:"p"},"fgetc")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"fputc"),". Functions like ",(0,a.kt)("inlineCode",{parentName:"p"},"fprintf")," (except for ",(0,a.kt)("inlineCode",{parentName:"p"},"stderr")," or logging) and\n",(0,a.kt)("inlineCode",{parentName:"p"},"fscanf")," are ",(0,a.kt)("strong",{parentName:"p"},"forbidden"),"."),(0,a.kt)("p",null,"In case you struggle and want to use one of those functions, the solution will be\npenalized by 50% of points."),(0,a.kt)("h3",{id:"bonus-part-075-k"},"Bonus part (0.75 K\u20a1)"),(0,a.kt)("p",null,"Bonus part of this assignment is to implement ",(0,a.kt)("inlineCode",{parentName:"p"},"count_anything")," rather than ",(0,a.kt)("inlineCode",{parentName:"p"},"count_ananas"),"."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Smaller hint: This task does not need dynamic allocation :) You just need one\ngood helper function and the right idea ;)")),(0,a.kt)("h2",{id:"task-no-2-weird-trees-1-k"},"Task no. 2: Weird trees (1 K\u20a1)"),(0,a.kt)("p",null,"In this task we are crossing our paths with ",(0,a.kt)("em",{parentName:"p"},"algorithms and data structures"),".\nYour task is to write a program that constructs tree from the file that is given\nas an argument and pretty-prints it."),(0,a.kt)("p",null,"Input file consists of lines, that include ",(0,a.kt)("inlineCode",{parentName:"p"},"key")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"rank")," in form ",(0,a.kt)("inlineCode",{parentName:"p"},"key;rank"),"\nor ",(0,a.kt)("inlineCode",{parentName:"p"},"nil"),". Why would we have ",(0,a.kt)("inlineCode",{parentName:"p"},"nil")," in a file? The file represents pre-order iteration\nthrough the tree. Leaves never have rank different than 0, so you can safely assume\n2 non-existing ",(0,a.kt)("inlineCode",{parentName:"p"},"nil"),"s in the input after you read such node ;)"),(0,a.kt)("table",null,(0,a.kt)("tr",null,(0,a.kt)("th",null,"Example input file"),(0,a.kt)("th",null,"Tree it represents")),(0,a.kt)("tr",null,(0,a.kt)("td",null,(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"8;4\n5;3\n3;2\n2;1\n1;0\nnil\n4;0\n7;1\n6;0\nnil\n11;2\n10;1\n9;0\nnil\n12;0\n"))),(0,a.kt)("td",null,(0,a.kt)("p",null,(0,a.kt)("img",{alt:"tree",src:n(4860).Z,width:"633",height:"684"}))))),(0,a.kt)("p",null,"In this task you are only provided with different trees in the ",(0,a.kt)("inlineCode",{parentName:"p"},"test-trees")," directory.\nImplementation and format of the pretty-print is totally up to you. :)"),(0,a.kt)("p",null,"Example of mine for the tree above:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"8 (rank = 4)\n+-- 5 (rank = 3)\n| +-- 3 (rank = 2)\n| | +-- 2 (rank = 1)\n| | | +-- 1 (rank = 0)\n| | +-- 4 (rank = 0)\n| +-- 7 (rank = 1)\n| +-- 6 (rank = 0)\n+-- 11 (rank = 2)\n +-- 10 (rank = 1)\n | +-- 9 (rank = 0)\n +-- 12 (rank = 0)\n")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Can you find out what are those trees? :)")),(0,a.kt)("h2",{id:"submitting"},"Submitting"),(0,a.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,a.kt)("hr",null))}m.isMDXComponent=!0},4860:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/tree-c9e37f87f9095c00fad33ea034485ce6.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9193],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),u=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return i.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),d=a,k=c["".concat(s,".").concat(d)]||c[d]||m[d]||r;return n?i.createElement(k,o(o({ref:t},p),{},{components:n})):i.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>r,metadata:()=>l,toc:()=>u});var i=n(7462),a=(n(7294),n(3905));const r={id:"seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n"},o="8th seminar bonus assignment",l={unversionedId:"bonuses/seminar-08",id:"bonuses/seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n",source:"@site/pb071/bonuses/08.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-08",permalink:"/pb071/bonuses/seminar-08",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/bonuses/08.md",tags:[],version:"current",lastUpdatedAt:1694111094,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n"},sidebar:"autogeneratedBar",previous:{title:"5th and 6th seminar",permalink:"/pb071/bonuses/seminar-05-06"},next:{title:"10th seminar",permalink:"/pb071/bonuses/seminar-10"}},s={},u=[{value:"Introduction",id:"introduction",level:2},{value:"Warning",id:"warning",level:2},{value:"Testing",id:"testing",level:2},{value:"Task no. 1: Counting (0.75 K\u20a1)",id:"task-no-1-counting-075-k",level:2},{value:"Requirements",id:"requirements",level:3},{value:"Bonus part (0.75 K\u20a1)",id:"bonus-part-075-k",level:3},{value:"Task no. 2: Weird trees (1 K\u20a1)",id:"task-no-2-weird-trees-1-k",level:2},{value:"Submitting",id:"submitting",level:2}],p={toc:u},c="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(c,(0,i.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"8th-seminar-bonus-assignment"},"8th seminar bonus assignment"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/08.tar.gz"},"Source")),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"In this bonus you can implement two tasks, one of them has a bonus part with generic\nsolution."),(0,a.kt)("p",null,"One is focused on counting ananas or in case of generic version any substring in\nthe file, but with a restriction on the function you use."),(0,a.kt)("p",null,"Other one has a more algorithmic spirit."),(0,a.kt)("p",null,"For this bonus you can get at maximum 2.5 K\u20a1."),(0,a.kt)("h2",{id:"warning"},"Warning"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"DO NOT COMMIT test data")," to your own git repository, since the tests include\nfiles that exceed 10MB by themselves. Even if they are on separate branch, they\ntake up the space."),(0,a.kt)("h2",{id:"testing"},"Testing"),(0,a.kt)("p",null,"For testing you are provided with python script (requires ",(0,a.kt)("inlineCode",{parentName:"p"},"click")," to be installed:\n",(0,a.kt)("inlineCode",{parentName:"p"},"pip3 install --user click"),") and ",(0,a.kt)("inlineCode",{parentName:"p"},"Makefile")," that provides following targets:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check-counting")," - runs the ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," tests"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check-counting-bonus")," - runs the ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," tests with bonus implemented"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check")," - runs both ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"counting-bonus")," tests"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"clean")," - removes output files from the test runs")),(0,a.kt)("h2",{id:"task-no-1-counting-075-k"},"Task no. 1: Counting (0.75 K\u20a1)"),(0,a.kt)("p",null,"Your first task is to make smallish program that counts occurences of specific\n(or given) word from file and writes the number to other file."),(0,a.kt)("p",null,"Usage of the program is:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"Usage: ./counting [string-to-be-counted]\n")),(0,a.kt)("p",null,"Arguments that are passed to the program represent:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"")," - path to the file where we count the words"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"")," - path to the file where we output the count"),(0,a.kt)("li",{parentName:"ul"},"(optional argument) ",(0,a.kt)("inlineCode",{parentName:"li"},"[string-to-be-counted]")," - in case you implement bonus,\notherwise we default to word ",(0,a.kt)("inlineCode",{parentName:"li"},"ananas")," ;)")),(0,a.kt)("p",null,"In skeleton you are given 3 empty, but documented, functions to implement."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"count_anything")," - function accepts input file and substring to be counted in\nthe file, returns the count."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"count_ananas")," - same as ",(0,a.kt)("inlineCode",{parentName:"li"},"count_anything"),", but specialized for ananases, the\ndefault implementation from the skeleton expects you to implement ",(0,a.kt)("inlineCode",{parentName:"li"},"count_anything"),"\nand therefore it just calls the other function."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"write_number")," - function that writes the number to the file, why would you\nneed the function is explained later :)")),(0,a.kt)("h3",{id:"requirements"},"Requirements"),(0,a.kt)("p",null,"For manipulation with the files you are only allowed to use ",(0,a.kt)("inlineCode",{parentName:"p"},"fopen"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"fclose"),",\n",(0,a.kt)("inlineCode",{parentName:"p"},"fgetc")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"fputc"),". Functions like ",(0,a.kt)("inlineCode",{parentName:"p"},"fprintf")," (except for ",(0,a.kt)("inlineCode",{parentName:"p"},"stderr")," or logging) and\n",(0,a.kt)("inlineCode",{parentName:"p"},"fscanf")," are ",(0,a.kt)("strong",{parentName:"p"},"forbidden"),"."),(0,a.kt)("p",null,"In case you struggle and want to use one of those functions, the solution will be\npenalized by 50% of points."),(0,a.kt)("h3",{id:"bonus-part-075-k"},"Bonus part (0.75 K\u20a1)"),(0,a.kt)("p",null,"Bonus part of this assignment is to implement ",(0,a.kt)("inlineCode",{parentName:"p"},"count_anything")," rather than ",(0,a.kt)("inlineCode",{parentName:"p"},"count_ananas"),"."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Smaller hint: This task does not need dynamic allocation :) You just need one\ngood helper function and the right idea ;)")),(0,a.kt)("h2",{id:"task-no-2-weird-trees-1-k"},"Task no. 2: Weird trees (1 K\u20a1)"),(0,a.kt)("p",null,"In this task we are crossing our paths with ",(0,a.kt)("em",{parentName:"p"},"algorithms and data structures"),".\nYour task is to write a program that constructs tree from the file that is given\nas an argument and pretty-prints it."),(0,a.kt)("p",null,"Input file consists of lines, that include ",(0,a.kt)("inlineCode",{parentName:"p"},"key")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"rank")," in form ",(0,a.kt)("inlineCode",{parentName:"p"},"key;rank"),"\nor ",(0,a.kt)("inlineCode",{parentName:"p"},"nil"),". Why would we have ",(0,a.kt)("inlineCode",{parentName:"p"},"nil")," in a file? The file represents pre-order iteration\nthrough the tree. Leaves never have rank different than 0, so you can safely assume\n2 non-existing ",(0,a.kt)("inlineCode",{parentName:"p"},"nil"),"s in the input after you read such node ;)"),(0,a.kt)("table",null,(0,a.kt)("tr",null,(0,a.kt)("th",null,"Example input file"),(0,a.kt)("th",null,"Tree it represents")),(0,a.kt)("tr",null,(0,a.kt)("td",null,(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"8;4\n5;3\n3;2\n2;1\n1;0\nnil\n4;0\n7;1\n6;0\nnil\n11;2\n10;1\n9;0\nnil\n12;0\n"))),(0,a.kt)("td",null,(0,a.kt)("p",null,(0,a.kt)("img",{alt:"tree",src:n(4860).Z,width:"633",height:"684"}))))),(0,a.kt)("p",null,"In this task you are only provided with different trees in the ",(0,a.kt)("inlineCode",{parentName:"p"},"test-trees")," directory.\nImplementation and format of the pretty-print is totally up to you. :)"),(0,a.kt)("p",null,"Example of mine for the tree above:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"8 (rank = 4)\n+-- 5 (rank = 3)\n| +-- 3 (rank = 2)\n| | +-- 2 (rank = 1)\n| | | +-- 1 (rank = 0)\n| | +-- 4 (rank = 0)\n| +-- 7 (rank = 1)\n| +-- 6 (rank = 0)\n+-- 11 (rank = 2)\n +-- 10 (rank = 1)\n | +-- 9 (rank = 0)\n +-- 12 (rank = 0)\n")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Can you find out what are those trees? :)")),(0,a.kt)("h2",{id:"submitting"},"Submitting"),(0,a.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,a.kt)("hr",null))}m.isMDXComponent=!0},4860:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/tree-c9e37f87f9095c00fad33ea034485ce6.png"}}]); \ No newline at end of file diff --git a/assets/js/2a09abcd.29ada0be.js b/assets/js/2a09abcd.ae41ee68.js similarity index 99% rename from assets/js/2a09abcd.29ada0be.js rename to assets/js/2a09abcd.ae41ee68.js index ad6e5f2..8071de9 100644 --- a/assets/js/2a09abcd.29ada0be.js +++ b/assets/js/2a09abcd.ae41ee68.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1246],{3905:(I,a,i)=>{i.d(a,{Zo:()=>g,kt:()=>b});var t=i(7294);function m(I,a,i){return a in I?Object.defineProperty(I,a,{value:i,enumerable:!0,configurable:!0,writable:!0}):I[a]=i,I}function n(I,a){var i=Object.keys(I);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(I);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(I,a).enumerable}))),i.push.apply(i,t)}return i}function e(I){for(var a=1;a=0||(m[i]=I[i]);return m}(I,a);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(I);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(I,i)&&(m[i]=I[i])}return m}var N=t.createContext({}),s=function(I){var a=t.useContext(N),i=a;return I&&(i="function"==typeof I?I(a):e(e({},a),I)),i},g=function(I){var a=s(I.components);return t.createElement(N.Provider,{value:a},I.children)},Z="mdxType",c={inlineCode:"code",wrapper:function(I){var a=I.children;return t.createElement(t.Fragment,{},a)}},G=t.forwardRef((function(I,a){var i=I.components,m=I.mdxType,n=I.originalType,N=I.parentName,g=l(I,["components","mdxType","originalType","parentName"]),Z=s(i),G=m,b=Z["".concat(N,".").concat(G)]||Z[G]||c[G]||n;return i?t.createElement(b,e(e({ref:a},g),{},{components:i})):t.createElement(b,e({ref:a},g))}));function b(I,a){var i=arguments,m=a&&a.mdxType;if("string"==typeof I||m){var n=i.length,e=new Array(n);e[0]=G;var l={};for(var N in a)hasOwnProperty.call(a,N)&&(l[N]=a[N]);l.originalType=I,l[Z]="string"==typeof I?I:m,e[1]=l;for(var s=2;s{i.r(a),i.d(a,{assets:()=>N,contentTitle:()=>e,default:()=>c,frontMatter:()=>n,metadata:()=>l,toc:()=>s});var t=i(7462),m=(i(7294),i(3905));const n={id:"bfs-tree",title:"Distance boundaries from BFS tree on undirected graphs",description:"Short explanation of distance boundaries deduced from a BFS tree.\n",tags:["graphs","bfs"],last_update:{date:new Date("2022-04-30T00:00:00.000Z")}},e=void 0,l={unversionedId:"graphs/bfs-tree",id:"graphs/bfs-tree",title:"Distance boundaries from BFS tree on undirected graphs",description:"Short explanation of distance boundaries deduced from a BFS tree.\n",source:"@site/ib002/10-graphs/2022-04-30-bfs-tree.md",sourceDirName:"10-graphs",slug:"/graphs/bfs-tree",permalink:"/ib002/graphs/bfs-tree",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/10-graphs/2022-04-30-bfs-tree.md",tags:[{label:"graphs",permalink:"/ib002/tags/graphs"},{label:"bfs",permalink:"/ib002/tags/bfs"}],version:"current",lastUpdatedAt:1651276800,formattedLastUpdatedAt:"Apr 30, 2022",frontMatter:{id:"bfs-tree",title:"Distance boundaries from BFS tree on undirected graphs",description:"Short explanation of distance boundaries deduced from a BFS tree.\n",tags:["graphs","bfs"],last_update:{date:"2022-04-30T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Iterative algorithms via iterators",permalink:"/ib002/graphs/iterative-and-iterators"}},N={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Lower bound",id:"lower-bound",level:2},{value:"Proof by contradiction",id:"proof-by-contradiction",level:2}],g={toc:s},Z="wrapper";function c(I){let{components:a,...n}=I;return(0,m.kt)(Z,(0,t.Z)({},g,n,{components:a,mdxType:"MDXLayout"}),(0,m.kt)("h2",{id:"introduction"},"Introduction"),(0,m.kt)("p",null,"As we have talked on the seminar, if we construct from some vertex ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"u")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"u")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"u")))))," BFS tree on an undirected graph, we can obtain:"),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},"lower bound of length of the shortest path between 2 vertices from the ",(0,m.kt)("em",{parentName:"li"},"height difference")),(0,m.kt)("li",{parentName:"ul"},"upper bound of length of the shortest path between 2 vertices from the ",(0,m.kt)("em",{parentName:"li"},"path through the root"))),(0,m.kt)("h2",{id:"lower-bound"},"Lower bound"),(0,m.kt)("p",null,"Consider the following graph:"),(0,m.kt)("p",null,(0,m.kt)("img",{src:i(6547).Z+"#gh-light-mode-only",width:"252",height:"539"}),"\n",(0,m.kt)("img",{src:i(1338).Z+"#gh-dark-mode-only",width:"252",height:"539"})),(0,m.kt)("p",null,"We run BFS from the vertex ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"a")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"a")))))," and obtain the following BFS tree:"),(0,m.kt)("p",null,(0,m.kt)("img",{src:i(6069).Z+"#gh-light-mode-only",width:"275",height:"347"}),"\n",(0,m.kt)("img",{src:i(6325).Z+"#gh-dark-mode-only",width:"275",height:"347"})),(0,m.kt)("p",null,"Let's consider pair of vertices ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e")))))," and ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h"))))),". For them we can safely lay, from the BFS tree, following properties:"),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},"lower bound: ",(0,m.kt)("span",{parentName:"li",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"2")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"2")))))),(0,m.kt)("li",{parentName:"ul"},"upper bound: ",(0,m.kt)("span",{parentName:"li",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"4")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"4")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"4"))))))),(0,m.kt)("p",null,"By having a look at the graph we started from, we can see that we have a path \u2039",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"j"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e, j, h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.05724em"}},"j"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h"))))),"\u203a that has a length 2. Apart from that we can also notice there is another path from ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e")))))," to ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h")))))," and that is \u2039",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"a"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"i"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"d"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e, a, c, i, d, h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"c"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"i"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"d"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h"))))),"\u203a. And that path has a length of ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"5")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"5")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"5"))))),". Doesn't this break our statements at the beginning? (",(0,m.kt)("em",{parentName:"p"},"I'm leaving that as an exercise ;)"),")"),(0,m.kt)("h2",{id:"proof-by-contradiction"},"Proof by contradiction"),(0,m.kt)("p",null,"Let's keep the same graph, but break the lower bound, i.e. I have gotten a lower bound ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"2")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"2"))))),", but \u201cthere must be a shorter path\u201d! ;)"),(0,m.kt)("p",null,"Now the more important question, is there a shorter path in that graph? The answer is no, there's no shorter path than the one with length ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"2")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"2"))))),". So what can we do about it? We'll add an edge to have a shorter path. Now we have gotten a lower bound of ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"2")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"2"))))),", which means the only shorter path we can construct has ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"1")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"1")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"1")))))," edge and that is \u2039",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e, h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h"))))),"\u203a (no intermediary vertices). Let's do this!"),(0,m.kt)("p",null,(0,m.kt)("img",{src:i(9907).Z+"#gh-light-mode-only",width:"252",height:"539"}),"\n",(0,m.kt)("img",{src:i(2830).Z+"#gh-dark-mode-only",width:"252",height:"539"})),(0,m.kt)("p",null,"Okay, so we have a graph that breaks the rule we have laid. However, we need to run BFS to obtain the new BFS tree, since we have changed the graph."),(0,m.kt)("admonition",{type:"tip"},(0,m.kt)("p",{parentName:"admonition"},"Do we need to run BFS after ",(0,m.kt)("strong",{parentName:"p"},"every")," change?"),(0,m.kt)("p",{parentName:"admonition"},"\xadI am leaving that as an exercise ;)")),(0,m.kt)("p",null,(0,m.kt)("img",{src:i(4570).Z+"#gh-light-mode-only",width:"371",height:"347"}),"\n",(0,m.kt)("img",{src:i(1722).Z+"#gh-dark-mode-only",width:"371",height:"347"})),(0,m.kt)("p",null,"Oops, we have gotten a new BFS tree, that has a height difference of 1."),(0,m.kt)("admonition",{type:"tip"},(0,m.kt)("p",{parentName:"admonition"},"Try to think about a way this can be generalized for shortening of minimal length 3 to minimal length 2 ;)")))}c.isMDXComponent=!0},1338:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMTg5cHQiIGhlaWdodD0iNDA0cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMTg5LjAwIDQwNC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCA0MDApIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC00MDAgMTg1LC00MDAgMTg1LDQgLTQsNCIvPgo8IS0tIGEgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMjYiIGN5PSItMzc4IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjYiIHk9Ii0zNzQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5jPC90ZXh0Pgo8L2c+CjwhLS0gYSYjNDU7JiM0NTtjIC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmEmIzQ1OyYjNDU7YzwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMTkuNiwtMzYwLjQxQzExNS4zNiwtMzQ5LjQxIDEwOS44MSwtMzM1LjAzIDEwNS41NCwtMzIzLjk2Ii8+CjwvZz4KPCEtLSBlIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmU8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTU0IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTU0IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZTwvdGV4dD4KPC9nPgo8IS0tIGEmIzQ1OyYjNDU7ZSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmIzQ1O2U8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI5LjE0LC0zNTkuODVDMTMwLjk4LC0zNDkuNDkgMTMzLjI3LC0zMzYuMDEgMTM1LC0zMjQgMTQyLjQ5LC0yNzEuOSAxNDkuMTgsLTIxMC4wMSAxNTIuMjQsLTE4MC40MyIvPgo8L2c+CjwhLS0gaSAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5pPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI3IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtpIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik04NC40MywtMjkwLjgzQzcyLjAyLC0yNzguNzcgNTQuMjcsLTI2MS41MSA0MS44LC0yNDkuMzgiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyYjNDU7YiAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5jJiM0NTsmIzQ1O2I8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTI4Ny43Qzk5LC0yNzYuODUgOTksLTI2Mi45MiA5OSwtMjUyLjEiLz4KPC9nPgo8IS0tIGogLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ajwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMjYiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjEyNiIgeT0iLTE0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ajwvdGV4dD4KPC9nPgo8IS0tIGUmIzQ1OyYjNDU7aiAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5lJiM0NTsmIzQ1O2o8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTUwLjYyLC0xNDMuODdDMTQ1LjI0LC0xMTYuNTggMTM0Ljc4LC02My41MiAxMjkuMzksLTM2LjE5Ii8+CjwvZz4KPCEtLSBkIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPmQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMzYiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIzNiIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmQ8L3RleHQ+CjwvZz4KPCEtLSBpJiM0NTsmIzQ1O2QgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aSYjNDU7JiM0NTtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI5LjE4LC0yMTYuMDVDMzAuNTcsLTIwNS4yMSAzMi4zOCwtMTkxLjE4IDMzLjc4LC0xODAuMjgiLz4KPC9nPgo8IS0tIGggLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmg8L3RleHQ+CjwvZz4KPCEtLSBiJiM0NTsmIzQ1O2ggLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YiYjNDU7JiM0NTtoPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC0yMTUuODdDOTksLTE4OC41OCA5OSwtMTM1LjUyIDk5LC0xMDguMTkiLz4KPC9nPgo8IS0tIGQmIzQ1OyYjNDU7aCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5kJiM0NTsmIzQ1O2g8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNDkuMzYsLTE0Ni4xNUM2MC4wNSwtMTM0LjI4IDc0Ljk3LC0xMTcuNyA4NS42NiwtMTA1LjgyIi8+CjwvZz4KPCEtLSBoJiM0NTsmIzQ1O2ogLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aCYjNDU7JiM0NTtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTEwNS40LC03Mi40MUMxMDkuNjQsLTYxLjQxIDExNS4xOSwtNDcuMDMgMTE5LjQ2LC0zNS45NiIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},6547:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMTg5cHQiIGhlaWdodD0iNDA0cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMTg5LjAwIDQwNC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCA0MDApIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtNDAwIDE4NSwtNDAwIDE4NSw0IC00LDQiLz4KPCEtLSBhIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmE8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTI2IiBjeT0iLTM3OCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTI2IiB5PSItMzc0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmM8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmIzQ1O2MgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7JiM0NTtjPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTExOS42LC0zNjAuNDFDMTE1LjM2LC0zNDkuNDEgMTA5LjgxLC0zMzUuMDMgMTA1LjU0LC0zMjMuOTYiLz4KPC9nPgo8IS0tIGUgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNTQiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNTQiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmU8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmIzQ1O2UgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7JiM0NTtlPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEyOS4xNCwtMzU5Ljg1QzEzMC45OCwtMzQ5LjQ5IDEzMy4yNywtMzM2LjAxIDEzNSwtMzI0IDE0Mi40OSwtMjcxLjkgMTQ5LjE4LC0yMTAuMDEgMTUyLjI0LC0xODAuNDMiLz4KPC9nPgo8IS0tIGkgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtpIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtMjkwLjgzQzcyLjAyLC0yNzguNzcgNTQuMjcsLTI2MS41MSA0MS44LC0yNDkuMzgiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5iPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtiIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7YjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMjg3LjdDOTksLTI3Ni44NSA5OSwtMjYyLjkyIDk5LC0yNTIuMSIvPgo8L2c+CjwhLS0gaiAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5qPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjEyNiIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTI2IiB5PSItMTQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmo8L3RleHQ+CjwvZz4KPCEtLSBlJiM0NTsmIzQ1O2ogLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+ZSYjNDU7JiM0NTtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE1MC42MiwtMTQzLjg3QzE0NS4yNCwtMTE2LjU4IDEzNC43OCwtNjMuNTIgMTI5LjM5LC0zNi4xOSIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjM2IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzYiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmQ8L3RleHQ+CjwvZz4KPCEtLSBpJiM0NTsmIzQ1O2QgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aSYjNDU7JiM0NTtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI5LjE4LC0yMTYuMDVDMzAuNTcsLTIwNS4yMSAzMi4zOCwtMTkxLjE4IDMzLjc4LC0xODAuMjgiLz4KPC9nPgo8IS0tIGggLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+aDwvdGV4dD4KPC9nPgo8IS0tIGImIzQ1OyYjNDU7aCAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5iJiM0NTsmIzQ1O2g8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTIxNS44N0M5OSwtMTg4LjU4IDk5LC0xMzUuNTIgOTksLTEwOC4xOSIvPgo8L2c+CjwhLS0gZCYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmQmIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik00OS4zNiwtMTQ2LjE1QzYwLjA1LC0xMzQuMjggNzQuOTcsLTExNy43IDg1LjY2LC0xMDUuODIiLz4KPC9nPgo8IS0tIGgmIzQ1OyYjNDU7aiAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5oJiM0NTsmIzQ1O2o8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTA1LjQsLTcyLjQxQzEwOS42NCwtNjEuNDEgMTE1LjE5LC00Ny4wMyAxMTkuNDYsLTM1Ljk2Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2830:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMTg5cHQiIGhlaWdodD0iNDA0cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMTg5LjAwIDQwNC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCA0MDApIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC00MDAgMTg1LC00MDAgMTg1LDQgLTQsNCIvPgo8IS0tIGEgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMjYiIGN5PSItMzc4IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjYiIHk9Ii0zNzQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5jPC90ZXh0Pgo8L2c+CjwhLS0gYSYjNDU7JiM0NTtjIC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmEmIzQ1OyYjNDU7YzwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMTkuNiwtMzYwLjQxQzExNS4zNiwtMzQ5LjQxIDEwOS44MSwtMzM1LjAzIDEwNS41NCwtMzIzLjk2Ii8+CjwvZz4KPCEtLSBlIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmU8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTU0IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTU0IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZTwvdGV4dD4KPC9nPgo8IS0tIGEmIzQ1OyYjNDU7ZSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmIzQ1O2U8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI5LjE0LC0zNTkuODVDMTMwLjk4LC0zNDkuNDkgMTMzLjI3LC0zMzYuMDEgMTM1LC0zMjQgMTQyLjQ5LC0yNzEuOSAxNDkuMTgsLTIxMC4wMSAxNTIuMjQsLTE4MC40MyIvPgo8L2c+CjwhLS0gaSAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5pPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI3IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtpIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik04NC40MywtMjkwLjgzQzcyLjAyLC0yNzguNzcgNTQuMjcsLTI2MS41MSA0MS44LC0yNDkuMzgiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyYjNDU7YiAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5jJiM0NTsmIzQ1O2I8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTI4Ny43Qzk5LC0yNzYuODUgOTksLTI2Mi45MiA5OSwtMjUyLjEiLz4KPC9nPgo8IS0tIGogLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ajwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMjYiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjEyNiIgeT0iLTE0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ajwvdGV4dD4KPC9nPgo8IS0tIGUmIzQ1OyYjNDU7aiAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5lJiM0NTsmIzQ1O2o8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTUwLjYyLC0xNDMuODdDMTQ1LjI0LC0xMTYuNTggMTM0Ljc4LC02My41MiAxMjkuMzksLTM2LjE5Ii8+CjwvZz4KPCEtLSBoIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPmg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5oPC90ZXh0Pgo8L2c+CjwhLS0gZSYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmUmIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNDIuMDcsLTE0NS44MUMxMzIuODQsLTEzNC4wNyAxMjAuMTMsLTExNy44OSAxMTAuOTEsLTEwNi4xNiIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjM1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzUiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5kPC90ZXh0Pgo8L2c+CjwhLS0gaSYjNDU7JiM0NTtkIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmkmIzQ1OyYjNDU7ZDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yOC45OCwtMjE1LjdDMzAuMjIsLTIwNC44NSAzMS44MSwtMTkwLjkyIDMzLjA1LC0xODAuMSIvPgo8L2c+CjwhLS0gYiYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmImIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMjE1Ljg3Qzk5LC0xODguNTggOTksLTEzNS41MiA5OSwtMTA4LjE5Ii8+CjwvZz4KPCEtLSBoJiM0NTsmIzQ1O2ogLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmgmIzQ1OyYjNDU7ajwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMDUuNCwtNzIuNDFDMTA5LjY0LC02MS40MSAxMTUuMTksLTQ3LjAzIDExOS40NiwtMzUuOTYiLz4KPC9nPgo8IS0tIGQmIzQ1OyYjNDU7aCAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5kJiM0NTsmIzQ1O2g8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNDguNTcsLTE0Ni4xNUM1OS40MywtMTM0LjI4IDc0LjU5LC0xMTcuNyA4NS40NSwtMTA1LjgyIi8+CjwvZz4KPC9nPgo8L3N2Zz4K"},9907:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMTg5cHQiIGhlaWdodD0iNDA0cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMTg5LjAwIDQwNC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCA0MDApIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtNDAwIDE4NSwtNDAwIDE4NSw0IC00LDQiLz4KPCEtLSBhIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmE8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTI2IiBjeT0iLTM3OCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTI2IiB5PSItMzc0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmM8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmIzQ1O2MgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7JiM0NTtjPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTExOS42LC0zNjAuNDFDMTE1LjM2LC0zNDkuNDEgMTA5LjgxLC0zMzUuMDMgMTA1LjU0LC0zMjMuOTYiLz4KPC9nPgo8IS0tIGUgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNTQiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNTQiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmU8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmIzQ1O2UgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7JiM0NTtlPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEyOS4xNCwtMzU5Ljg1QzEzMC45OCwtMzQ5LjQ5IDEzMy4yNywtMzM2LjAxIDEzNSwtMzI0IDE0Mi40OSwtMjcxLjkgMTQ5LjE4LC0yMTAuMDEgMTUyLjI0LC0xODAuNDMiLz4KPC9nPgo8IS0tIGkgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtpIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtMjkwLjgzQzcyLjAyLC0yNzguNzcgNTQuMjcsLTI2MS41MSA0MS44LC0yNDkuMzgiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5iPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtiIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7YjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMjg3LjdDOTksLTI3Ni44NSA5OSwtMjYyLjkyIDk5LC0yNTIuMSIvPgo8L2c+CjwhLS0gaiAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5qPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjEyNiIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTI2IiB5PSItMTQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmo8L3RleHQ+CjwvZz4KPCEtLSBlJiM0NTsmIzQ1O2ogLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+ZSYjNDU7JiM0NTtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE1MC42MiwtMTQzLjg3QzE0NS4yNCwtMTE2LjU4IDEzNC43OCwtNjMuNTIgMTI5LjM5LC0zNi4xOSIvPgo8L2c+CjwhLS0gaCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5oPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5oPC90ZXh0Pgo8L2c+CjwhLS0gZSYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmUmIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNDIuMDcsLTE0NS44MUMxMzIuODQsLTEzNC4wNyAxMjAuMTMsLTExNy44OSAxMTAuOTEsLTEwNi4xNiIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjM1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzUiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmQ8L3RleHQ+CjwvZz4KPCEtLSBpJiM0NTsmIzQ1O2QgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aSYjNDU7JiM0NTtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI4Ljk4LC0yMTUuN0MzMC4yMiwtMjA0Ljg1IDMxLjgxLC0xOTAuOTIgMzMuMDUsLTE4MC4xIi8+CjwvZz4KPCEtLSBiJiM0NTsmIzQ1O2ggLS0+CjxnIGlkPSJlZGdlOCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YiYjNDU7JiM0NTtoPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC0yMTUuODdDOTksLTE4OC41OCA5OSwtMTM1LjUyIDk5LC0xMDguMTkiLz4KPC9nPgo8IS0tIGgmIzQ1OyYjNDU7aiAtLT4KPGcgaWQ9ImVkZ2UxMCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aCYjNDU7JiM0NTtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEwNS40LC03Mi40MUMxMDkuNjQsLTYxLjQxIDExNS4xOSwtNDcuMDMgMTE5LjQ2LC0zNS45NiIvPgo8L2c+CjwhLS0gZCYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmQmIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik00OC41NywtMTQ2LjE1QzU5LjQzLC0xMzQuMjggNzQuNTksLTExNy43IDg1LjQ1LC0xMDUuODIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},6325:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjA2cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjA2LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMjAyLC0yNTYgMjAyLDQgLTQsNCIvPgo8IS0tIGEgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5jPC90ZXh0Pgo8L2c+CjwhLS0gYSYjNDU7Jmd0O2MgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7Jmd0O2M8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSBlIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmU8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZTwvdGV4dD4KPC9nPgo8IS0tIGEmIzQ1OyZndDtlIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmEmIzQ1OyZndDtlPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE0My4zNSwtMjE2Ljc2QzE0Ny43MSwtMjA4LjI4IDE1My4xNSwtMTk3LjcxIDE1OC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTYxLjIzLC0xODkuNjQgMTYyLjcsLTE3OS4xNSAxNTUuMDEsLTE4Ni40NCAxNjEuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gYiAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5iPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyZndDtiIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyZndDtiPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBpIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7Jmd0O2kgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YyYjNDU7Jmd0O2k8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBqIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmo8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmo8L3RleHQ+CjwvZz4KPCEtLSBlJiM0NTsmZ3Q7aiAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5lJiM0NTsmZ3Q7ajwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIGggLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii0xNC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmg8L3RleHQ+CjwvZz4KPCEtLSBiJiM0NTsmZ3Q7aCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5iJiM0NTsmZ3Q7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNywtNzEuN0MyNywtNjMuOTggMjcsLTU0LjcxIDI3LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzMC41LC00Ni4xIDI3LC0zNi4xIDIzLjUsLTQ2LjEgMzAuNSwtNDYuMSIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZDwvdGV4dD4KPC9nPgo8IS0tIGkmIzQ1OyZndDtkIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmkmIzQ1OyZndDtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},6069:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjA2cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjA2LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMjU2IDIwMiwtMjU2IDIwMiw0IC00LDQiLz4KPCEtLSBhIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmE8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmM8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmZ3Q7YyAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmZ3Q7YzwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMjYuNjUsLTIxNi43NkMxMjIuMjksLTIwOC4yOCAxMTYuODUsLTE5Ny43MSAxMTEuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjExNC45OSwtMTg2LjQ0IDEwNy4zLC0xNzkuMTUgMTA4Ljc3LC0xODkuNjQgMTE0Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIGUgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmU8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmZ3Q7ZSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmZ3Q7ZTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNDMuMzUsLTIxNi43NkMxNDcuNzEsLTIwOC4yOCAxNTMuMTUsLTE5Ny43MSAxNTguMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2MS4yMywtMTg5LjY0IDE2Mi43LC0xNzkuMTUgMTU1LjAxLC0xODYuNDQgMTYxLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyZndDtiIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyZndDtiPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBpIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmk8L3RleHQ+CjwvZz4KPCEtLSBjJiM0NTsmZ3Q7aSAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5jJiM0NTsmZ3Q7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIGogLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ajwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5qPC90ZXh0Pgo8L2c+CjwhLS0gZSYjNDU7Jmd0O2ogLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+ZSYjNDU7Jmd0O2o8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBoIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPmg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3IiB5PSItMTQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmg8L3RleHQ+CjwvZz4KPCEtLSBiJiM0NTsmZ3Q7aCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5iJiM0NTsmZ3Q7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNywtNzEuN0MyNywtNjMuOTggMjcsLTU0LjcxIDI3LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzMC41LC00Ni4xIDI3LC0zNi4xIDIzLjUsLTQ2LjEgMzAuNSwtNDYuMSIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5kPC90ZXh0Pgo8L2c+CjwhLS0gaSYjNDU7Jmd0O2QgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aSYjNDU7Jmd0O2Q8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTcxLjdDOTksLTYzLjk4IDk5LC01NC43MSA5OSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTQ2LjEgOTksLTM2LjEgOTUuNSwtNDYuMSAxMDIuNSwtNDYuMSIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},1722:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjc4cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjc4LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMjc0LC0yNTYgMjc0LDQgLTQsNCIvPgo8IS0tIGEgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5jPC90ZXh0Pgo8L2c+CjwhLS0gYSYjNDU7Jmd0O2MgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7Jmd0O2M8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSBlIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmU8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZTwvdGV4dD4KPC9nPgo8IS0tIGEmIzQ1OyZndDtlIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmEmIzQ1OyZndDtlPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE0My4zNSwtMjE2Ljc2QzE0Ny43MSwtMjA4LjI4IDE1My4xNSwtMTk3LjcxIDE1OC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTYxLjIzLC0xODkuNjQgMTYyLjcsLTE3OS4xNSAxNTUuMDEsLTE4Ni40NCAxNjEuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gYiAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5iPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyZndDtiIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyZndDtiPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBpIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7Jmd0O2kgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YyYjNDU7Jmd0O2k8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBoIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmg8L3RleHQ+CjwvZz4KPCEtLSBlJiM0NTsmZ3Q7aCAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5lJiM0NTsmZ3Q7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIGogLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ajwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ajwvdGV4dD4KPC9nPgo8IS0tIGUmIzQ1OyZndDtqIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmUmIzQ1OyZndDtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMy40NywtMTE0Ljg3IDIyOC4yLC0xMDUuMzggMjE4LjU5LC0xMDkuODUgMjIzLjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIGQgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmQ8L3RleHQ+CjwvZz4KPCEtLSBpJiM0NTsmZ3Q7ZCAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5pJiM0NTsmZ3Q7ZDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtNzEuN0M5OSwtNjMuOTggOTksLTU0LjcxIDk5LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMDIuNSwtNDYuMSA5OSwtMzYuMSA5NS41LC00Ni4xIDEwMi41LC00Ni4xIi8+CjwvZz4KPC9nPgo8L3N2Zz4K"},4570:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjc4cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjc4LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMjU2IDI3NCwtMjU2IDI3NCw0IC00LDQiLz4KPCEtLSBhIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmE8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmM8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmZ3Q7YyAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmZ3Q7YzwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMjYuNjUsLTIxNi43NkMxMjIuMjksLTIwOC4yOCAxMTYuODUsLTE5Ny43MSAxMTEuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjExNC45OSwtMTg2LjQ0IDEwNy4zLC0xNzkuMTUgMTA4Ljc3LC0xODkuNjQgMTE0Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIGUgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmU8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmZ3Q7ZSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmZ3Q7ZTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNDMuMzUsLTIxNi43NkMxNDcuNzEsLTIwOC4yOCAxNTMuMTUsLTE5Ny43MSAxNTguMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2MS4yMywtMTg5LjY0IDE2Mi43LC0xNzkuMTUgMTU1LjAxLC0xODYuNDQgMTYxLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyZndDtiIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyZndDtiPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBpIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmk8L3RleHQ+CjwvZz4KPCEtLSBjJiM0NTsmZ3Q7aSAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5jJiM0NTsmZ3Q7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIGggLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5oPC90ZXh0Pgo8L2c+CjwhLS0gZSYjNDU7Jmd0O2ggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+ZSYjNDU7Jmd0O2g8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBqIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPmo8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjQzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+ajwvdGV4dD4KPC9nPgo8IS0tIGUmIzQ1OyZndDtqIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmUmIzQ1OyZndDtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMy40NywtMTE0Ljg3IDIyOC4yLC0xMDUuMzggMjE4LjU5LC0xMDkuODUgMjIzLjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIGQgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+ZDwvdGV4dD4KPC9nPgo8IS0tIGkmIzQ1OyZndDtkIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmkmIzQ1OyZndDtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1246],{3905:(I,a,i)=>{i.d(a,{Zo:()=>g,kt:()=>b});var t=i(7294);function m(I,a,i){return a in I?Object.defineProperty(I,a,{value:i,enumerable:!0,configurable:!0,writable:!0}):I[a]=i,I}function n(I,a){var i=Object.keys(I);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(I);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(I,a).enumerable}))),i.push.apply(i,t)}return i}function e(I){for(var a=1;a=0||(m[i]=I[i]);return m}(I,a);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(I);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(I,i)&&(m[i]=I[i])}return m}var N=t.createContext({}),s=function(I){var a=t.useContext(N),i=a;return I&&(i="function"==typeof I?I(a):e(e({},a),I)),i},g=function(I){var a=s(I.components);return t.createElement(N.Provider,{value:a},I.children)},Z="mdxType",c={inlineCode:"code",wrapper:function(I){var a=I.children;return t.createElement(t.Fragment,{},a)}},G=t.forwardRef((function(I,a){var i=I.components,m=I.mdxType,n=I.originalType,N=I.parentName,g=l(I,["components","mdxType","originalType","parentName"]),Z=s(i),G=m,b=Z["".concat(N,".").concat(G)]||Z[G]||c[G]||n;return i?t.createElement(b,e(e({ref:a},g),{},{components:i})):t.createElement(b,e({ref:a},g))}));function b(I,a){var i=arguments,m=a&&a.mdxType;if("string"==typeof I||m){var n=i.length,e=new Array(n);e[0]=G;var l={};for(var N in a)hasOwnProperty.call(a,N)&&(l[N]=a[N]);l.originalType=I,l[Z]="string"==typeof I?I:m,e[1]=l;for(var s=2;s{i.r(a),i.d(a,{assets:()=>N,contentTitle:()=>e,default:()=>c,frontMatter:()=>n,metadata:()=>l,toc:()=>s});var t=i(7462),m=(i(7294),i(3905));const n={id:"bfs-tree",title:"Distance boundaries from BFS tree on undirected graphs",description:"Short explanation of distance boundaries deduced from a BFS tree.\n",tags:["graphs","bfs"],last_update:{date:new Date("2022-04-30T00:00:00.000Z")}},e=void 0,l={unversionedId:"graphs/bfs-tree",id:"graphs/bfs-tree",title:"Distance boundaries from BFS tree on undirected graphs",description:"Short explanation of distance boundaries deduced from a BFS tree.\n",source:"@site/ib002/10-graphs/2022-04-30-bfs-tree.md",sourceDirName:"10-graphs",slug:"/graphs/bfs-tree",permalink:"/ib002/graphs/bfs-tree",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/10-graphs/2022-04-30-bfs-tree.md",tags:[{label:"graphs",permalink:"/ib002/tags/graphs"},{label:"bfs",permalink:"/ib002/tags/bfs"}],version:"current",lastUpdatedAt:1651276800,formattedLastUpdatedAt:"Apr 30, 2022",frontMatter:{id:"bfs-tree",title:"Distance boundaries from BFS tree on undirected graphs",description:"Short explanation of distance boundaries deduced from a BFS tree.\n",tags:["graphs","bfs"],last_update:{date:"2022-04-30T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Iterative algorithms via iterators",permalink:"/ib002/graphs/iterative-and-iterators"}},N={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Lower bound",id:"lower-bound",level:2},{value:"Proof by contradiction",id:"proof-by-contradiction",level:2}],g={toc:s},Z="wrapper";function c(I){let{components:a,...n}=I;return(0,m.kt)(Z,(0,t.Z)({},g,n,{components:a,mdxType:"MDXLayout"}),(0,m.kt)("h2",{id:"introduction"},"Introduction"),(0,m.kt)("p",null,"As we have talked on the seminar, if we construct from some vertex ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"u")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"u")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"u")))))," BFS tree on an undirected graph, we can obtain:"),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},"lower bound of length of the shortest path between 2 vertices from the ",(0,m.kt)("em",{parentName:"li"},"height difference")),(0,m.kt)("li",{parentName:"ul"},"upper bound of length of the shortest path between 2 vertices from the ",(0,m.kt)("em",{parentName:"li"},"path through the root"))),(0,m.kt)("h2",{id:"lower-bound"},"Lower bound"),(0,m.kt)("p",null,"Consider the following graph:"),(0,m.kt)("p",null,(0,m.kt)("img",{src:i(6547).Z+"#gh-light-mode-only",width:"252",height:"539"}),"\n",(0,m.kt)("img",{src:i(1338).Z+"#gh-dark-mode-only",width:"252",height:"539"})),(0,m.kt)("p",null,"We run BFS from the vertex ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"a")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"a")))))," and obtain the following BFS tree:"),(0,m.kt)("p",null,(0,m.kt)("img",{src:i(6069).Z+"#gh-light-mode-only",width:"275",height:"347"}),"\n",(0,m.kt)("img",{src:i(6325).Z+"#gh-dark-mode-only",width:"275",height:"347"})),(0,m.kt)("p",null,"Let's consider pair of vertices ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e")))))," and ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h"))))),". For them we can safely lay, from the BFS tree, following properties:"),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},"lower bound: ",(0,m.kt)("span",{parentName:"li",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"2")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"2")))))),(0,m.kt)("li",{parentName:"ul"},"upper bound: ",(0,m.kt)("span",{parentName:"li",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"4")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"4")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"4"))))))),(0,m.kt)("p",null,"By having a look at the graph we started from, we can see that we have a path \u2039",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"j"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e, j, h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.05724em"}},"j"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h"))))),"\u203a that has a length 2. Apart from that we can also notice there is another path from ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e")))))," to ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h")))))," and that is \u2039",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"a"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"i"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"d"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e, a, c, i, d, h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"c"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"i"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"d"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h"))))),"\u203a. And that path has a length of ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"5")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"5")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"5"))))),". Doesn't this break our statements at the beginning? (",(0,m.kt)("em",{parentName:"p"},"I'm leaving that as an exercise ;)"),")"),(0,m.kt)("h2",{id:"proof-by-contradiction"},"Proof by contradiction"),(0,m.kt)("p",null,"Let's keep the same graph, but break the lower bound, i.e. I have gotten a lower bound ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"2")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"2"))))),", but \u201cthere must be a shorter path\u201d! ;)"),(0,m.kt)("p",null,"Now the more important question, is there a shorter path in that graph? The answer is no, there's no shorter path than the one with length ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"2")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"2"))))),". So what can we do about it? We'll add an edge to have a shorter path. Now we have gotten a lower bound of ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"2")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"2"))))),", which means the only shorter path we can construct has ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mn",{parentName:"mrow"},"1")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"1")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,m.kt)("span",{parentName:"span",className:"mord"},"1")))))," edge and that is \u2039",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"e"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"h")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"e, h")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"e"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"h"))))),"\u203a (no intermediary vertices). Let's do this!"),(0,m.kt)("p",null,(0,m.kt)("img",{src:i(9907).Z+"#gh-light-mode-only",width:"252",height:"539"}),"\n",(0,m.kt)("img",{src:i(2830).Z+"#gh-dark-mode-only",width:"252",height:"539"})),(0,m.kt)("p",null,"Okay, so we have a graph that breaks the rule we have laid. However, we need to run BFS to obtain the new BFS tree, since we have changed the graph."),(0,m.kt)("admonition",{type:"tip"},(0,m.kt)("p",{parentName:"admonition"},"Do we need to run BFS after ",(0,m.kt)("strong",{parentName:"p"},"every")," change?"),(0,m.kt)("p",{parentName:"admonition"},"\xadI am leaving that as an exercise ;)")),(0,m.kt)("p",null,(0,m.kt)("img",{src:i(4570).Z+"#gh-light-mode-only",width:"371",height:"347"}),"\n",(0,m.kt)("img",{src:i(1722).Z+"#gh-dark-mode-only",width:"371",height:"347"})),(0,m.kt)("p",null,"Oops, we have gotten a new BFS tree, that has a height difference of 1."),(0,m.kt)("admonition",{type:"tip"},(0,m.kt)("p",{parentName:"admonition"},"Try to think about a way this can be generalized for shortening of minimal length 3 to minimal length 2 ;)")))}c.isMDXComponent=!0},1338:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMTg5cHQiIGhlaWdodD0iNDA0cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMTg5LjAwIDQwNC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCA0MDApIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC00MDAgMTg1LC00MDAgMTg1LDQgLTQsNCIvPgo8IS0tIGEgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMjYiIGN5PSItMzc4IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjYiIHk9Ii0zNzQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5jPC90ZXh0Pgo8L2c+CjwhLS0gYSYjNDU7JiM0NTtjIC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmEmIzQ1OyYjNDU7YzwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMTkuNiwtMzYwLjQxQzExNS4zNiwtMzQ5LjQxIDEwOS44MSwtMzM1LjAzIDEwNS41NCwtMzIzLjk2Ii8+CjwvZz4KPCEtLSBlIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmU8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTU0IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTU0IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZTwvdGV4dD4KPC9nPgo8IS0tIGEmIzQ1OyYjNDU7ZSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmIzQ1O2U8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI5LjE0LC0zNTkuODVDMTMwLjk4LC0zNDkuNDkgMTMzLjI3LC0zMzYuMDEgMTM1LC0zMjQgMTQyLjQ5LC0yNzEuOSAxNDkuMTgsLTIxMC4wMSAxNTIuMjQsLTE4MC40MyIvPgo8L2c+CjwhLS0gaSAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5pPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI3IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtpIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik04NC40MywtMjkwLjgzQzcyLjAyLC0yNzguNzcgNTQuMjcsLTI2MS41MSA0MS44LC0yNDkuMzgiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyYjNDU7YiAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5jJiM0NTsmIzQ1O2I8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTI4Ny43Qzk5LC0yNzYuODUgOTksLTI2Mi45MiA5OSwtMjUyLjEiLz4KPC9nPgo8IS0tIGogLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ajwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMjYiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjEyNiIgeT0iLTE0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ajwvdGV4dD4KPC9nPgo8IS0tIGUmIzQ1OyYjNDU7aiAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5lJiM0NTsmIzQ1O2o8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTUwLjYyLC0xNDMuODdDMTQ1LjI0LC0xMTYuNTggMTM0Ljc4LC02My41MiAxMjkuMzksLTM2LjE5Ii8+CjwvZz4KPCEtLSBkIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPmQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMzYiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIzNiIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmQ8L3RleHQ+CjwvZz4KPCEtLSBpJiM0NTsmIzQ1O2QgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aSYjNDU7JiM0NTtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI5LjE4LC0yMTYuMDVDMzAuNTcsLTIwNS4yMSAzMi4zOCwtMTkxLjE4IDMzLjc4LC0xODAuMjgiLz4KPC9nPgo8IS0tIGggLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmg8L3RleHQ+CjwvZz4KPCEtLSBiJiM0NTsmIzQ1O2ggLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YiYjNDU7JiM0NTtoPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC0yMTUuODdDOTksLTE4OC41OCA5OSwtMTM1LjUyIDk5LC0xMDguMTkiLz4KPC9nPgo8IS0tIGQmIzQ1OyYjNDU7aCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5kJiM0NTsmIzQ1O2g8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNDkuMzYsLTE0Ni4xNUM2MC4wNSwtMTM0LjI4IDc0Ljk3LC0xMTcuNyA4NS42NiwtMTA1LjgyIi8+CjwvZz4KPCEtLSBoJiM0NTsmIzQ1O2ogLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aCYjNDU7JiM0NTtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTEwNS40LC03Mi40MUMxMDkuNjQsLTYxLjQxIDExNS4xOSwtNDcuMDMgMTE5LjQ2LC0zNS45NiIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},6547:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMTg5cHQiIGhlaWdodD0iNDA0cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMTg5LjAwIDQwNC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCA0MDApIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtNDAwIDE4NSwtNDAwIDE4NSw0IC00LDQiLz4KPCEtLSBhIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmE8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTI2IiBjeT0iLTM3OCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTI2IiB5PSItMzc0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmM8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmIzQ1O2MgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7JiM0NTtjPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTExOS42LC0zNjAuNDFDMTE1LjM2LC0zNDkuNDEgMTA5LjgxLC0zMzUuMDMgMTA1LjU0LC0zMjMuOTYiLz4KPC9nPgo8IS0tIGUgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNTQiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNTQiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmU8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmIzQ1O2UgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7JiM0NTtlPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEyOS4xNCwtMzU5Ljg1QzEzMC45OCwtMzQ5LjQ5IDEzMy4yNywtMzM2LjAxIDEzNSwtMzI0IDE0Mi40OSwtMjcxLjkgMTQ5LjE4LC0yMTAuMDEgMTUyLjI0LC0xODAuNDMiLz4KPC9nPgo8IS0tIGkgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtpIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtMjkwLjgzQzcyLjAyLC0yNzguNzcgNTQuMjcsLTI2MS41MSA0MS44LC0yNDkuMzgiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5iPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtiIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7YjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMjg3LjdDOTksLTI3Ni44NSA5OSwtMjYyLjkyIDk5LC0yNTIuMSIvPgo8L2c+CjwhLS0gaiAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5qPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjEyNiIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTI2IiB5PSItMTQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmo8L3RleHQ+CjwvZz4KPCEtLSBlJiM0NTsmIzQ1O2ogLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+ZSYjNDU7JiM0NTtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE1MC42MiwtMTQzLjg3QzE0NS4yNCwtMTE2LjU4IDEzNC43OCwtNjMuNTIgMTI5LjM5LC0zNi4xOSIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjM2IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzYiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmQ8L3RleHQ+CjwvZz4KPCEtLSBpJiM0NTsmIzQ1O2QgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aSYjNDU7JiM0NTtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI5LjE4LC0yMTYuMDVDMzAuNTcsLTIwNS4yMSAzMi4zOCwtMTkxLjE4IDMzLjc4LC0xODAuMjgiLz4KPC9nPgo8IS0tIGggLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+aDwvdGV4dD4KPC9nPgo8IS0tIGImIzQ1OyYjNDU7aCAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5iJiM0NTsmIzQ1O2g8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTIxNS44N0M5OSwtMTg4LjU4IDk5LC0xMzUuNTIgOTksLTEwOC4xOSIvPgo8L2c+CjwhLS0gZCYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmQmIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik00OS4zNiwtMTQ2LjE1QzYwLjA1LC0xMzQuMjggNzQuOTcsLTExNy43IDg1LjY2LC0xMDUuODIiLz4KPC9nPgo8IS0tIGgmIzQ1OyYjNDU7aiAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5oJiM0NTsmIzQ1O2o8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTA1LjQsLTcyLjQxQzEwOS42NCwtNjEuNDEgMTE1LjE5LC00Ny4wMyAxMTkuNDYsLTM1Ljk2Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2830:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMTg5cHQiIGhlaWdodD0iNDA0cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMTg5LjAwIDQwNC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCA0MDApIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC00MDAgMTg1LC00MDAgMTg1LDQgLTQsNCIvPgo8IS0tIGEgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMjYiIGN5PSItMzc4IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMjYiIHk9Ii0zNzQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5jPC90ZXh0Pgo8L2c+CjwhLS0gYSYjNDU7JiM0NTtjIC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmEmIzQ1OyYjNDU7YzwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMTkuNiwtMzYwLjQxQzExNS4zNiwtMzQ5LjQxIDEwOS44MSwtMzM1LjAzIDEwNS41NCwtMzIzLjk2Ii8+CjwvZz4KPCEtLSBlIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmU8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTU0IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTU0IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZTwvdGV4dD4KPC9nPgo8IS0tIGEmIzQ1OyYjNDU7ZSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmIzQ1O2U8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI5LjE0LC0zNTkuODVDMTMwLjk4LC0zNDkuNDkgMTMzLjI3LC0zMzYuMDEgMTM1LC0zMjQgMTQyLjQ5LC0yNzEuOSAxNDkuMTgsLTIxMC4wMSAxNTIuMjQsLTE4MC40MyIvPgo8L2c+CjwhLS0gaSAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5pPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI3IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtpIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik04NC40MywtMjkwLjgzQzcyLjAyLC0yNzguNzcgNTQuMjcsLTI2MS41MSA0MS44LC0yNDkuMzgiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyYjNDU7YiAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5jJiM0NTsmIzQ1O2I8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTI4Ny43Qzk5LC0yNzYuODUgOTksLTI2Mi45MiA5OSwtMjUyLjEiLz4KPC9nPgo8IS0tIGogLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ajwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMjYiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjEyNiIgeT0iLTE0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ajwvdGV4dD4KPC9nPgo8IS0tIGUmIzQ1OyYjNDU7aiAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5lJiM0NTsmIzQ1O2o8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTUwLjYyLC0xNDMuODdDMTQ1LjI0LC0xMTYuNTggMTM0Ljc4LC02My41MiAxMjkuMzksLTM2LjE5Ii8+CjwvZz4KPCEtLSBoIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPmg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5oPC90ZXh0Pgo8L2c+CjwhLS0gZSYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmUmIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNDIuMDcsLTE0NS44MUMxMzIuODQsLTEzNC4wNyAxMjAuMTMsLTExNy44OSAxMTAuOTEsLTEwNi4xNiIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjM1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzUiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5kPC90ZXh0Pgo8L2c+CjwhLS0gaSYjNDU7JiM0NTtkIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmkmIzQ1OyYjNDU7ZDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yOC45OCwtMjE1LjdDMzAuMjIsLTIwNC44NSAzMS44MSwtMTkwLjkyIDMzLjA1LC0xODAuMSIvPgo8L2c+CjwhLS0gYiYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmImIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMjE1Ljg3Qzk5LC0xODguNTggOTksLTEzNS41MiA5OSwtMTA4LjE5Ii8+CjwvZz4KPCEtLSBoJiM0NTsmIzQ1O2ogLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmgmIzQ1OyYjNDU7ajwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMDUuNCwtNzIuNDFDMTA5LjY0LC02MS40MSAxMTUuMTksLTQ3LjAzIDExOS40NiwtMzUuOTYiLz4KPC9nPgo8IS0tIGQmIzQ1OyYjNDU7aCAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5kJiM0NTsmIzQ1O2g8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNDguNTcsLTE0Ni4xNUM1OS40MywtMTM0LjI4IDc0LjU5LC0xMTcuNyA4NS40NSwtMTA1LjgyIi8+CjwvZz4KPC9nPgo8L3N2Zz4K"},9907:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMTg5cHQiIGhlaWdodD0iNDA0cHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMTg5LjAwIDQwNC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCA0MDApIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtNDAwIDE4NSwtNDAwIDE4NSw0IC00LDQiLz4KPCEtLSBhIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmE8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTI2IiBjeT0iLTM3OCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTI2IiB5PSItMzc0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmM8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmIzQ1O2MgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7JiM0NTtjPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTExOS42LC0zNjAuNDFDMTE1LjM2LC0zNDkuNDEgMTA5LjgxLC0zMzUuMDMgMTA1LjU0LC0zMjMuOTYiLz4KPC9nPgo8IS0tIGUgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNTQiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNTQiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmU8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmIzQ1O2UgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7JiM0NTtlPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEyOS4xNCwtMzU5Ljg1QzEzMC45OCwtMzQ5LjQ5IDEzMy4yNywtMzM2LjAxIDEzNSwtMzI0IDE0Mi40OSwtMjcxLjkgMTQ5LjE4LC0yMTAuMDEgMTUyLjI0LC0xODAuNDMiLz4KPC9nPgo8IS0tIGkgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtpIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtMjkwLjgzQzcyLjAyLC0yNzguNzcgNTQuMjcsLTI2MS41MSA0MS44LC0yNDkuMzgiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5iPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7JiM0NTtiIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyYjNDU7YjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMjg3LjdDOTksLTI3Ni44NSA5OSwtMjYyLjkyIDk5LC0yNTIuMSIvPgo8L2c+CjwhLS0gaiAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5qPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjEyNiIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTI2IiB5PSItMTQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmo8L3RleHQ+CjwvZz4KPCEtLSBlJiM0NTsmIzQ1O2ogLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+ZSYjNDU7JiM0NTtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE1MC42MiwtMTQzLjg3QzE0NS4yNCwtMTE2LjU4IDEzNC43OCwtNjMuNTIgMTI5LjM5LC0zNi4xOSIvPgo8L2c+CjwhLS0gaCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5oPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5oPC90ZXh0Pgo8L2c+CjwhLS0gZSYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmUmIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNDIuMDcsLTE0NS44MUMxMzIuODQsLTEzNC4wNyAxMjAuMTMsLTExNy44OSAxMTAuOTEsLTEwNi4xNiIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjM1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzUiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmQ8L3RleHQ+CjwvZz4KPCEtLSBpJiM0NTsmIzQ1O2QgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aSYjNDU7JiM0NTtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI4Ljk4LC0yMTUuN0MzMC4yMiwtMjA0Ljg1IDMxLjgxLC0xOTAuOTIgMzMuMDUsLTE4MC4xIi8+CjwvZz4KPCEtLSBiJiM0NTsmIzQ1O2ggLS0+CjxnIGlkPSJlZGdlOCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YiYjNDU7JiM0NTtoPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC0yMTUuODdDOTksLTE4OC41OCA5OSwtMTM1LjUyIDk5LC0xMDguMTkiLz4KPC9nPgo8IS0tIGgmIzQ1OyYjNDU7aiAtLT4KPGcgaWQ9ImVkZ2UxMCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aCYjNDU7JiM0NTtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTEwNS40LC03Mi40MUMxMDkuNjQsLTYxLjQxIDExNS4xOSwtNDcuMDMgMTE5LjQ2LC0zNS45NiIvPgo8L2c+CjwhLS0gZCYjNDU7JiM0NTtoIC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmQmIzQ1OyYjNDU7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik00OC41NywtMTQ2LjE1QzU5LjQzLC0xMzQuMjggNzQuNTksLTExNy43IDg1LjQ1LC0xMDUuODIiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},6325:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjA2cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjA2LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMjAyLC0yNTYgMjAyLDQgLTQsNCIvPgo8IS0tIGEgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5jPC90ZXh0Pgo8L2c+CjwhLS0gYSYjNDU7Jmd0O2MgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7Jmd0O2M8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSBlIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmU8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZTwvdGV4dD4KPC9nPgo8IS0tIGEmIzQ1OyZndDtlIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmEmIzQ1OyZndDtlPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE0My4zNSwtMjE2Ljc2QzE0Ny43MSwtMjA4LjI4IDE1My4xNSwtMTk3LjcxIDE1OC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTYxLjIzLC0xODkuNjQgMTYyLjcsLTE3OS4xNSAxNTUuMDEsLTE4Ni40NCAxNjEuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gYiAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5iPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyZndDtiIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyZndDtiPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBpIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7Jmd0O2kgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YyYjNDU7Jmd0O2k8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBqIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmo8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmo8L3RleHQ+CjwvZz4KPCEtLSBlJiM0NTsmZ3Q7aiAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5lJiM0NTsmZ3Q7ajwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIGggLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii0xNC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmg8L3RleHQ+CjwvZz4KPCEtLSBiJiM0NTsmZ3Q7aCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5iJiM0NTsmZ3Q7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNywtNzEuN0MyNywtNjMuOTggMjcsLTU0LjcxIDI3LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzMC41LC00Ni4xIDI3LC0zNi4xIDIzLjUsLTQ2LjEgMzAuNSwtNDYuMSIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZDwvdGV4dD4KPC9nPgo8IS0tIGkmIzQ1OyZndDtkIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmkmIzQ1OyZndDtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},6069:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjA2cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjA2LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMjU2IDIwMiwtMjU2IDIwMiw0IC00LDQiLz4KPCEtLSBhIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmE8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmM8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmZ3Q7YyAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmZ3Q7YzwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMjYuNjUsLTIxNi43NkMxMjIuMjksLTIwOC4yOCAxMTYuODUsLTE5Ny43MSAxMTEuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjExNC45OSwtMTg2LjQ0IDEwNy4zLC0xNzkuMTUgMTA4Ljc3LC0xODkuNjQgMTE0Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIGUgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmU8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmZ3Q7ZSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmZ3Q7ZTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNDMuMzUsLTIxNi43NkMxNDcuNzEsLTIwOC4yOCAxNTMuMTUsLTE5Ny43MSAxNTguMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2MS4yMywtMTg5LjY0IDE2Mi43LC0xNzkuMTUgMTU1LjAxLC0xODYuNDQgMTYxLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyZndDtiIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyZndDtiPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBpIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmk8L3RleHQ+CjwvZz4KPCEtLSBjJiM0NTsmZ3Q7aSAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5jJiM0NTsmZ3Q7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIGogLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ajwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5qPC90ZXh0Pgo8L2c+CjwhLS0gZSYjNDU7Jmd0O2ogLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+ZSYjNDU7Jmd0O2o8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBoIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPmg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3IiB5PSItMTQuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmg8L3RleHQ+CjwvZz4KPCEtLSBiJiM0NTsmZ3Q7aCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5iJiM0NTsmZ3Q7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNywtNzEuN0MyNywtNjMuOTggMjcsLTU0LjcxIDI3LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzMC41LC00Ni4xIDI3LC0zNi4xIDIzLjUsLTQ2LjEgMzAuNSwtNDYuMSIvPgo8L2c+CjwhLS0gZCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5kPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE0LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5kPC90ZXh0Pgo8L2c+CjwhLS0gaSYjNDU7Jmd0O2QgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+aSYjNDU7Jmd0O2Q8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTcxLjdDOTksLTYzLjk4IDk5LC01NC43MSA5OSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTQ2LjEgOTksLTM2LjEgOTUuNSwtNDYuMSAxMDIuNSwtNDYuMSIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},1722:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjc4cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjc4LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMjc0LC0yNTYgMjc0LDQgLTQsNCIvPgo8IS0tIGEgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9Ijk5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5jPC90ZXh0Pgo8L2c+CjwhLS0gYSYjNDU7Jmd0O2MgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YSYjNDU7Jmd0O2M8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSBlIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmU8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ZTwvdGV4dD4KPC9nPgo8IS0tIGEmIzQ1OyZndDtlIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmEmIzQ1OyZndDtlPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE0My4zNSwtMjE2Ljc2QzE0Ny43MSwtMjA4LjI4IDE1My4xNSwtMTk3LjcxIDE1OC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTYxLjIzLC0xODkuNjQgMTYyLjcsLTE3OS4xNSAxNTUuMDEsLTE4Ni40NCAxNjEuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gYiAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5iPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyZndDtiIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyZndDtiPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBpIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj5pPC90ZXh0Pgo8L2c+CjwhLS0gYyYjNDU7Jmd0O2kgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+YyYjNDU7Jmd0O2k8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBoIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmg8L3RleHQ+CjwvZz4KPCEtLSBlJiM0NTsmZ3Q7aCAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5lJiM0NTsmZ3Q7aDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIGogLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ajwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+ajwvdGV4dD4KPC9nPgo8IS0tIGUmIzQ1OyZndDtqIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmUmIzQ1OyZndDtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMy40NywtMTE0Ljg3IDIyOC4yLC0xMDUuMzggMjE4LjU5LC0xMDkuODUgMjIzLjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIGQgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPmQ8L3RleHQ+CjwvZz4KPCEtLSBpJiM0NTsmZ3Q7ZCAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5pJiM0NTsmZ3Q7ZDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtNzEuN0M5OSwtNjMuOTggOTksLTU0LjcxIDk5LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMDIuNSwtNDYuMSA5OSwtMzYuMSA5NS41LC00Ni4xIDEwMi41LC00Ni4xIi8+CjwvZz4KPC9nPgo8L3N2Zz4K"},4570:(I,a,i)=>{i.d(a,{Z:()=>t});const t="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iMjc4cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgMjc4LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMjU2IDI3NCwtMjU2IDI3NCw0IC00LDQiLz4KPCEtLSBhIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmE8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5hPC90ZXh0Pgo8L2c+CjwhLS0gYyAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5jPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9Ijk5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmM8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmZ3Q7YyAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmZ3Q7YzwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMjYuNjUsLTIxNi43NkMxMjIuMjksLTIwOC4yOCAxMTYuODUsLTE5Ny43MSAxMTEuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjExNC45OSwtMTg2LjQ0IDEwNy4zLC0xNzkuMTUgMTA4Ljc3LC0xODkuNjQgMTE0Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIGUgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmU8L3RleHQ+CjwvZz4KPCEtLSBhJiM0NTsmZ3Q7ZSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5hJiM0NTsmZ3Q7ZTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNDMuMzUsLTIxNi43NkMxNDcuNzEsLTIwOC4yOCAxNTMuMTUsLTE5Ny43MSAxNTguMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE2MS4yMywtMTg5LjY0IDE2Mi43LC0xNzkuMTUgMTU1LjAxLC0xODYuNDQgMTYxLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIGIgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+YjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+YjwvdGV4dD4KPC9nPgo8IS0tIGMmIzQ1OyZndDtiIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmMmIzQ1OyZndDtiPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBpIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPmk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPmk8L3RleHQ+CjwvZz4KPCEtLSBjJiM0NTsmZ3Q7aSAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5jJiM0NTsmZ3Q7aTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIGggLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+aDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj5oPC90ZXh0Pgo8L2c+CjwhLS0gZSYjNDU7Jmd0O2ggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+ZSYjNDU7Jmd0O2g8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBqIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPmo8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjQzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+ajwvdGV4dD4KPC9nPgo8IS0tIGUmIzQ1OyZndDtqIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmUmIzQ1OyZndDtqPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMy40NywtMTE0Ljg3IDIyOC4yLC0xMDUuMzggMjE4LjU5LC0xMDkuODUgMjIzLjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIGQgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ZDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii0xNC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+ZDwvdGV4dD4KPC9nPgo8IS0tIGkmIzQ1OyZndDtkIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPmkmIzQ1OyZndDtkPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="}}]); \ No newline at end of file diff --git a/assets/js/337bc122.cdd2fcf0.js b/assets/js/337bc122.53d298b4.js similarity index 58% rename from assets/js/337bc122.cdd2fcf0.js rename to assets/js/337bc122.53d298b4.js index 1b2883d..a026928 100644 --- a/assets/js/337bc122.cdd2fcf0.js +++ b/assets/js/337bc122.53d298b4.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1731],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>b});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=l(r),d=o,b=s["".concat(p,".").concat(d)]||s[d]||f[d]||a;return r?n.createElement(b,i(i({ref:t},u),{},{components:r})):n.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[s]="string"==typeof e?e:o,i[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"pb071-intro",title:"Introduction",slug:"/"},i=void 0,c={unversionedId:"pb071-intro",id:"pb071-intro",title:"Introduction",description:"",source:"@site/pb071/00-intro-pb071.md",sourceDirName:".",slug:"/",permalink:"/pb071/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/00-intro-pb071.md",tags:[],version:"current",lastUpdatedAt:1694110423,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"pb071-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Bonuses",permalink:"/pb071/category/bonuses"}},p={},l=[],u={toc:l},s="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1731],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>b});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=l(r),d=o,b=s["".concat(p,".").concat(d)]||s[d]||f[d]||i;return r?n.createElement(b,a(a({ref:t},u),{},{components:r})):n.createElement(b,a({ref:t},u))}));function b(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[s]="string"==typeof e?e:o,a[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const i={id:"pb071-intro",title:"Introduction",slug:"/"},a=void 0,c={unversionedId:"pb071-intro",id:"pb071-intro",title:"Introduction",description:"",source:"@site/pb071/00-intro-pb071.md",sourceDirName:".",slug:"/",permalink:"/pb071/",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/00-intro-pb071.md",tags:[],version:"current",lastUpdatedAt:1694111094,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"pb071-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Bonuses",permalink:"/pb071/category/bonuses"}},p={},l=[],u={toc:l},s="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/377f3aa1.4c98e03e.js b/assets/js/377f3aa1.27922c0d.js similarity index 99% rename from assets/js/377f3aa1.4c98e03e.js rename to assets/js/377f3aa1.27922c0d.js index 0dc3a78..a46b0d9 100644 --- a/assets/js/377f3aa1.4c98e03e.js +++ b/assets/js/377f3aa1.27922c0d.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1011],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>c});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),h=i,c=d["".concat(s,".").concat(h)]||d[h]||m[h]||o;return n?a.createElement(c,r(r({ref:t},u),{},{components:n})):a.createElement(c,r({ref:t},u))}));function c(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,r[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const o={title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15",slug:"aoc-2022/2nd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},r=void 0,l={permalink:"/blog/aoc-2022/2nd-week",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/02-week-2.md",source:"@site/blog/aoc-2022/02-week-2.md",title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15:00.000Z",formattedDate:"December 25, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:20.875,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15",slug:"aoc-2022/2nd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"Sort the matrix diagonally",permalink:"/blog/leetcode/sort-diagonally"},nextItem:{title:"1st week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/1st-week"}},s={authorsImageUrls:[void 0]},p=[{value:"Day 8: Treetop Tree House",id:"day-8-treetop-tree-house",level:2},{value:"Swapping indices",id:"swapping-indices",level:4},{value:"Indexing Vec",id:"indexing-vec",level:4},{value:"Issues",id:"issues",level:5},{value:"Checking bounds",id:"checking-bounds",level:4},{value:"Solution",id:"solution",level:3},{value:"Day 9: Rope Bridge",id:"day-9-rope-bridge",level:2},{value:"Solution",id:"solution-1",level:3},{value:"Day 10: Cathode-Ray Tube",id:"day-10-cathode-ray-tube",level:2},{value:"Solution",id:"solution-2",level:3},{value:"Day 11: Monkey in the Middle",id:"day-11-monkey-in-the-middle",level:2},{value:"Solution",id:"solution-3",level:3},{value:"Day 12: Hill Climbing Algorithm",id:"day-12-hill-climbing-algorithm",level:2},{value:"Solution",id:"solution-4",level:3},{value:"Day 13: Distress Signal",id:"day-13-distress-signal",level:2},{value:"Solution",id:"solution-5",level:3},{value:"Day 14: Regolith Reservoir",id:"day-14-regolith-reservoir",level:2},{value:"Solution",id:"solution-6",level:3},{value:"Post Mortem",id:"post-mortem",level:2},{value:"Indexing",id:"indexing",level:3},{value:"Cause of the problem",id:"cause-of-the-problem",level:4}],u={toc:p},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Let's go through the second week of ",(0,i.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,i.kt)("em",{parentName:"a"},"Advent of Code"))," in Rust."),(0,i.kt)("h2",{id:"day-8-treetop-tree-house"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/8"},"Day 8: Treetop Tree House")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"We get a forest and we want to know how many trees are visible from the outside.\nApart from that we want to find the best view.")),(0,i.kt)("p",null,"Nothing interesting. We are moving around 2D map though. And indexing can get a\nbit painful when doing so, let's refactor it a bit ;) During the preparation for\nthe AoC, I have written ",(0,i.kt)("inlineCode",{parentName:"p"},"Vector2D")," and now it's time to extend it with indexing\nof ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec")," of ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec"),"s. In my solution I was manipulating with indices in the following\nway:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"swapping them"),(0,i.kt)("li",{parentName:"ul"},"checking whether they are correct indices for the ",(0,i.kt)("inlineCode",{parentName:"li"},"Vec>")),(0,i.kt)("li",{parentName:"ul"},"indexing ",(0,i.kt)("inlineCode",{parentName:"li"},"Vec>")," with them")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"I'm getting familiar with Rust and starting to \u201cabuse\u201d it\u2026 While doing so, I'm\nalso uncovering some \u201cfeatures\u201d that I don't really like. Therefore I will mark\nall of my rants with ",(0,i.kt)("em",{parentName:"p"},"thicc")," ",(0,i.kt)("strong",{parentName:"p"},"\xab\u21af\xbb")," mark and will try to \u201clock\u201d them into their\nown \u201cbox of hell\u201d.")),(0,i.kt)("h4",{id:"swapping-indices"},"Swapping indices"),(0,i.kt)("p",null,"Relatively simple implementation, just take the values, swap them and return new\nvector."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"impl Vector2D {\n pub fn swap(&self) -> Self {\n Self {\n x: self.y,\n y: self.x,\n }\n }\n}\n")),(0,i.kt)("p",null,"Pretty straight-forward implementation, but let's talk about the ",(0,i.kt)("inlineCode",{parentName:"p"},"T: Copy"),". We\nneed to use it, since we are returning a ",(0,i.kt)("strong",{parentName:"p"},"new")," vector, with swapped ",(0,i.kt)("strong",{parentName:"p"},"values"),".\nIf we had values that cannot be copied, the only thing we could do, would be a\nvector of references (and it would also introduce a lifetime, to which we'll get\nlater on). This is pretty similar with the operations on sets from the first week."),(0,i.kt)("h4",{id:"indexing-vec"},"Indexing ",(0,i.kt)("inlineCode",{parentName:"h4"},"Vec")),(0,i.kt)("p",null,"I will start with the indexing, cause bound-checking is a bit more\u2026 complicated\nthan I would like to."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn index<'a, T, U>(v: &'a [Vec], idx: &Vector2D) -> &'a U\nwhere\n usize: TryFrom,\n >::Error: Debug,\n T: Copy,\n{\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\n &v[y][x]\n}\n")),(0,i.kt)("p",null,"Let's talk about this mess\u2026 Body of the function is probably the most easy part\nand should not be hard to understand, we just take the ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," and convert\nthem both to ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," type that can be used later on for indexing."),(0,i.kt)("p",null,"The type signature of the function is where the fun is at \ud83d\ude09 We are trying\nto convert unknown type to ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),", so we must bound the ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," as a type that can\nbe converted to ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),", that's how we got ",(0,i.kt)("inlineCode",{parentName:"p"},"usize: TryFrom")," which basically\nsays that ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," must implement ",(0,i.kt)("inlineCode",{parentName:"p"},"TryFrom")," trait and therefore allows us to\nconvert the indices to actual ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," indices. Using ",(0,i.kt)("inlineCode",{parentName:"p"},".unwrap()")," also forces us\nto bound the error that can occur when converting ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," into ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),", that's how\nwe get ",(0,i.kt)("inlineCode",{parentName:"p"},">::Error: Debug")," which loosely means"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"error during conversion of ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," into ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," must implement ",(0,i.kt)("inlineCode",{parentName:"p"},"Debug"),",\ni.e. can be printed in some way or other")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"T: Copy")," is required by ",(0,i.kt)("inlineCode",{parentName:"p"},".try_into()")," which takes ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," by-value."),(0,i.kt)("p",null,"And now we are left only with the first line of the definition."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"Skilled Rustaceans might notice that this implementation is rather flaky and can\nbreak in multiple places at once. I'll get back to it\u2026")),(0,i.kt)("p",null,"Let's split it in multiple parts:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"v: &'a [Vec]")," represents the 2D ",(0,i.kt)("inlineCode",{parentName:"li"},"Vec"),", we are indexing, ",(0,i.kt)("inlineCode",{parentName:"li"},"Vec")," implements\n",(0,i.kt)("inlineCode",{parentName:"li"},"Slice")," trait and ",(0,i.kt)("em",{parentName:"li"},"clippy")," recommends using ",(0,i.kt)("inlineCode",{parentName:"li"},"&[T]")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"&Vec"),", exact details\nare unknown to me"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"idx: &Vector2D")," represents the ",(0,i.kt)("em",{parentName:"li"},"indices")," which we use, we take them by\nreference to avoid an unnecessary copy"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"-> &'a U")," means that we are returning a ",(0,i.kt)("em",{parentName:"li"},"reference")," to some value of type ",(0,i.kt)("inlineCode",{parentName:"li"},"U"),".\nNow the question is what does the ",(0,i.kt)("inlineCode",{parentName:"li"},"'a")," mean, we can also see it as a generic\ntype declared along ",(0,i.kt)("inlineCode",{parentName:"li"},"T")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"U"),". And the answer is ",(0,i.kt)("em",{parentName:"li"},"relatively")," simple, ",(0,i.kt)("inlineCode",{parentName:"li"},"'a"),"\nrepresents a ",(0,i.kt)("em",{parentName:"li"},"lifetime"),". We take the ",(0,i.kt)("inlineCode",{parentName:"li"},"v")," by a reference and return a reference,\nborrow checker validates all of the ",(0,i.kt)("em",{parentName:"li"},"borrows")," (or references), so we need to\nspecify that our returned value has ",(0,i.kt)("em",{parentName:"li"},"the same lifetime")," as the vector we have\ntaken by a reference, i.e. returned reference must live at least as long as the\n",(0,i.kt)("inlineCode",{parentName:"li"},"v"),". This way we can \u201cbe sure\u201d that the returned reference is valid.")),(0,i.kt)("h5",{id:"issues"},"Issues"),(0,i.kt)("p",null,"First issue that our implementation has is the fact that we cannot get a mutable\nreference out of that function. This could be easily resolved by introducing new\nfunction, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"index_mut"),". Which I have actually done while writing this part:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn index_mut<'a, T, U>(v: &'a mut [Vec], idx: &Vector2D) -> &'a mut U\nwhere\n usize: TryFrom,\n >::Error: Debug,\n T: Copy,\n{\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\n &mut v[y][x]\n}\n")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("mdxAdmonitionTitle",{parentName:"admonition"},(0,i.kt)("strong",{parentName:"mdxAdmonitionTitle"},"\xab\u21af\xbb")," Why can't we use one function?"),(0,i.kt)("p",{parentName:"admonition"},"When we consider a ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec"),", we don't need to consider containers as ",(0,i.kt)("inlineCode",{parentName:"p"},"T"),", Rust\nimplements indexing as traits ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," that do the dirty work\nbehind syntactic sugar of ",(0,i.kt)("inlineCode",{parentName:"p"},"container[idx]"),"."),(0,i.kt)("p",{parentName:"admonition"},"However, implementing of traits is not allowed for ",(0,i.kt)("em",{parentName:"p"},"external")," types, i.e. types\nthat you haven't defined yourself. This means that you can implement indexing\nover containers that you have implemented yourself, but you cannot use your own\ntypes for indexing \u201cbuilt-in\u201d types."),(0,i.kt)("p",{parentName:"admonition"},"Another part of this rabbit hole is trait ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex")," that is of a relevance\nbecause of"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"impl Index for [T]\nwhere\n I: SliceIndex<[T]>\n\nimpl Index for Vec\nwhere\n I: SliceIndex<[T]>,\n A: Allocator\n\nimpl Index for [T; N]\nwhere\n [T]: Index\n")),(0,i.kt)("p",{parentName:"admonition"},"In other words, if your type implements ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex")," trait, it can be used\nfor indexing. As of now, this trait has all of its required methods experimental\nand is marked as ",(0,i.kt)("inlineCode",{parentName:"p"},"unsafe"),".")),(0,i.kt)("p",null,"Another problem is a requirement for indexing either ",(0,i.kt)("inlineCode",{parentName:"p"},"[Vec]")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec>"),".\nThis requirement could be countered by removing inner type ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec")," and constraining\nit by a trait ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," (or ",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," respectively) in a following way"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn index<'a, C, T>(v: &'a [C], idx: &Vector2D) -> &'a C::Output\nwhere\n usize: TryFrom,\n >::Error: Debug,\n T: Copy,\n C: Index\n{\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\n &v[y][x]\n}\n")),(0,i.kt)("p",null,"Given this, we can also give a more meaningful typename for indexing type, such\nas ",(0,i.kt)("inlineCode",{parentName:"p"},"I"),"."),(0,i.kt)("h4",{id:"checking-bounds"},"Checking bounds"),(0,i.kt)("p",null,"Now we can get to the boundary checks, it is very similar, but a more\u2026 dirty.\nFirst approach that came up was to convert the indices in ",(0,i.kt)("inlineCode",{parentName:"p"},"Vector2D")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),",\nbut when you add the indices up, e.g. when checking the neighbors, you can end\nup with negative values which, unlike in C++, causes an error (instead of underflow\nthat you can use to your advantage; you can easily guess how)."),(0,i.kt)("p",null,"So how can we approach this then? Well\u2026 we will convert the bounds instead of\nthe indices and that lead us to:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn in_range(v: &[Vec], idx: &Vector2D) -> bool\nwhere\n usize: TryInto,\n >::Error: Debug,\n T: PartialOrd + Copy,\n{\n idx.y >= 0.try_into().unwrap()\n && idx.y < v.len().try_into().unwrap()\n && idx.x >= 0.try_into().unwrap()\n && idx.x\n < v[TryInto::::try_into(idx.y).unwrap()]\n .len()\n .try_into()\n .unwrap()\n}\n")),(0,i.kt)("p",null,"You can tell that it's definitely a shitty code. Let's improve it now! We will\nget back to the original idea, but do it better. We know that we cannot convert\nnegative values into ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),", ",(0,i.kt)("strong",{parentName:"p"},"but")," we also know that conversion like that\nreturns a ",(0,i.kt)("inlineCode",{parentName:"p"},"Result")," which we can use to our advantage."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn in_range(v: &[Vec], idx: &Vector2D) -> bool\nwhere\n T: Copy,\n usize: TryFrom,\n{\n usize::try_from(idx.y)\n .and_then(|y| usize::try_from(idx.x).map(|x| y < v.len() && x < v[y].len()))\n .unwrap_or(false)\n}\n")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"Result")," is a type similar to ",(0,i.kt)("inlineCode",{parentName:"p"},"Either")," in Haskell and it allows us to chain\nmultiple operations on correct results or propagate the original error without\ndoing anything. Let's dissect it one-by-one."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"try_from")," is a method implemented in ",(0,i.kt)("inlineCode",{parentName:"p"},"TryFrom")," trait, that allows you to convert\ntypes and either successfully convert them or fail (with a reasonable error). This\nmethod returns ",(0,i.kt)("inlineCode",{parentName:"p"},"Result"),"."),(0,i.kt)("p",null,"We call ",(0,i.kt)("inlineCode",{parentName:"p"},"and_then")," on that ",(0,i.kt)("em",{parentName:"p"},"result"),", let's have a look at the type signature of\n",(0,i.kt)("inlineCode",{parentName:"p"},"and_then"),", IMO it explains more than enough:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn and_then(self, op: F) -> Result\nwhere\n F: FnOnce(T) -> Result\n")),(0,i.kt)("p",null,"OK\u2026 So it takes the result and a function and returns another result with\ndifferent value and different error. However we can see that the function, which\nrepresents an operation on a result, takes just the value, i.e. it doesn't care\nabout any previous error. To make it short:"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("inlineCode",{parentName:"p"},"and_then")," allows us to run an operation, which can fail, on the correct result")),(0,i.kt)("p",null,"We parsed a ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," index and now we try to convert the ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," index with ",(0,i.kt)("inlineCode",{parentName:"p"},"try_from"),"\nagain, but on that result we use ",(0,i.kt)("inlineCode",{parentName:"p"},"map")," rather than ",(0,i.kt)("inlineCode",{parentName:"p"},"and_then"),", why would that be?"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn map(self, op: F) -> Result\nwhere\n F: FnOnce(T) -> U\n")),(0,i.kt)("p",null,"Huh\u2026 ",(0,i.kt)("inlineCode",{parentName:"p"},"map")," performs an operation that ",(0,i.kt)("strong",{parentName:"p"},"cannot")," fail. And finally we use\n",(0,i.kt)("inlineCode",{parentName:"p"},"unwrap_or")," which takes the value from result, or in case of an error returns the\ndefault that we define."),(0,i.kt)("p",null,"How does this work then? If ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," is negative, the conversion fails and the error\npropagates all the way to ",(0,i.kt)("inlineCode",{parentName:"p"},"unwrap_or"),", if ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," can be a correct ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," value, then\nwe do the same with ",(0,i.kt)("inlineCode",{parentName:"p"},"x"),". If ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," is negative, we propagate the error as with ",(0,i.kt)("inlineCode",{parentName:"p"},"y"),",\nand if it's not, then we check whether it exceeds the higher bounds or not."),(0,i.kt)("h3",{id:"solution"},"Solution"),(0,i.kt)("p",null,"Relatively simple, you just need follow the rules and not get too smart, otherwise\nit will get back at you."),(0,i.kt)("h2",{id:"day-9-rope-bridge"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/9"},"Day 9: Rope Bridge")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"We get a rope with knots and we want to track how many different positions are\nvisited with the rope's tail.")),(0,i.kt)("p",null,"By this day, I have come to a conclusion that current skeleton for each day\ngenerates a lot of boilerplate. And even though it can be easily copied, it's\njust a waste of space and unnecessary code. Let's \u201csimplify\u201d this (on one end\nwhile creating monster on the other end). I've gone through what we need in the\npreparations for the AoC. Let's sum up our requirements:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"parsing"),(0,i.kt)("li",{parentName:"ul"},"part 1 & 2"),(0,i.kt)("li",{parentName:"ul"},"running on sample / input"),(0,i.kt)("li",{parentName:"ul"},"tests")),(0,i.kt)("p",null,"Parsing and implementation of both parts is code that changes each day and we\ncannot do anything about it. However running and testing can be simplified!"),(0,i.kt)("p",null,"Let's introduce and export a new module ",(0,i.kt)("inlineCode",{parentName:"p"},"solution")," that will take care of all of\nthis. We will start by introducing a trait for each day."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub trait Solution {\n fn parse_input>(pathname: P) -> Input;\n\n fn part_1(input: &Input) -> Output;\n fn part_2(input: &Input) -> Output;\n}\n")),(0,i.kt)("p",null,"This does a lot of work for us already, we have defined a trait and for each day\nwe will create a structure representing a specific day. That structure will also\nimplement the ",(0,i.kt)("inlineCode",{parentName:"p"},"Solution")," trait."),(0,i.kt)("p",null,"Now we need to get rid of the boilerplate, we can't get rid of the ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," function,\nbut we can at least move out the functionality."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'fn run(type_of_input: &str) -> Result<()>\nwhere\n Self: Sized,\n{\n tracing_subscriber::fmt()\n .with_env_filter(EnvFilter::from_default_env())\n .with_target(false)\n .with_file(true)\n .with_line_number(true)\n .without_time()\n .compact()\n .init();\n color_eyre::install()?;\n\n let input = Self::parse_input(format!("{}s/{}.txt", type_of_input, Self::day()));\n\n info!("Part 1: {}", Self::part_1(&input));\n info!("Part 2: {}", Self::part_2(&input));\n\n Ok(())\n}\n\nfn main() -> Result<()>\nwhere\n Self: Sized,\n{\n Self::run("input")\n}\n')),(0,i.kt)("p",null,"This is all part of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Solution")," trait, which can implement methods while being\ndependent on what is provided by the implementing types. In this case, we just\nneed to bound the ",(0,i.kt)("inlineCode",{parentName:"p"},"Output")," type to implement ",(0,i.kt)("inlineCode",{parentName:"p"},"Display")," that is necessary for the\n",(0,i.kt)("inlineCode",{parentName:"p"},"info!")," and format string there."),(0,i.kt)("p",null,"Now we can get to first of the nasty things we are going to do\u2026 And it is the\n",(0,i.kt)("inlineCode",{parentName:"p"},"day()")," method that you can see being used when constructing path to the input\nfile. That method will generate a name of the file, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"day01")," and we know that\nwe can ",(0,i.kt)("em",{parentName:"p"},"somehow")," deduce it from the structure name, given we name it reasonably."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'fn day() -> String {\n let mut day = String::from(type_name::().split("::").next().unwrap());\n day.make_ascii_lowercase();\n\n day.to_string()\n}\n')),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("mdxAdmonitionTitle",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"mdxAdmonitionTitle"},"type_name")),(0,i.kt)("p",{parentName:"admonition"},"This feature is still experimental and considered to be internal, it is not\nadvised to use it any production code.")),(0,i.kt)("p",null,"And now we can get to the nastiest stuff \ud83d\ude29 We will ",(0,i.kt)("strong",{parentName:"p"},"generate")," the tests!"),(0,i.kt)("p",null,"We want to be able to generate tests for sample input in a following way:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"test_sample!(day_01, Day01, 42, 69);\n")),(0,i.kt)("p",null,"There's not much we can do, so we will write a macro to generate the tests for us."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'#[macro_export]\nmacro_rules! test_sample {\n ($mod_name:ident, $day_struct:tt, $part_1:expr, $part_2:expr) => {\n #[cfg(test)]\n mod $mod_name {\n use super::*;\n\n #[test]\n fn test_part_1() {\n let sample =\n $day_struct::parse_input(&format!("samples/{}.txt", $day_struct::day()));\n assert_eq!($day_struct::part_1(&sample), $part_1);\n }\n\n #[test]\n fn test_part_2() {\n let sample =\n $day_struct::parse_input(&format!("samples/{}.txt", $day_struct::day()));\n assert_eq!($day_struct::part_2(&sample), $part_2);\n }\n }\n };\n}\n')),(0,i.kt)("p",null,"We have used it in a similar way as macros in C/C++, one of the things that we\ncan use to our advantage is defining \u201ctype\u201d of the parameters for the macro. All\nparameters have their name prefixed with ",(0,i.kt)("inlineCode",{parentName:"p"},"$")," sign and you can define various \u201cforms\u201d\nof your macro. Let's go through it!"),(0,i.kt)("p",null,"We have following parameters:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"$mod_name")," which represents the name for the module with tests, it is typed\nwith ",(0,i.kt)("inlineCode",{parentName:"li"},"ident")," which means that we want a valid identifier to be passed in."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"$day_struct")," represents the structure that will be used for tests, it is typed\nwith ",(0,i.kt)("inlineCode",{parentName:"li"},"tt")," which represents a ",(0,i.kt)("em",{parentName:"li"},"token tree"),", in our case it is a type."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"$part_X")," represents the expected output for the ",(0,i.kt)("inlineCode",{parentName:"li"},"X"),"th part and is of type ",(0,i.kt)("inlineCode",{parentName:"li"},"expr"),"\nwhich literally means an ",(0,i.kt)("em",{parentName:"li"},"expression"),".")),(0,i.kt)("p",null,"Apart from that we need to use ",(0,i.kt)("inlineCode",{parentName:"p"},"#[macro_export]")," to mark the macro as exported\nfor usage outside of the module. Now our skeleton looks like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'use aoc_2022::*;\n\ntype Input = String;\ntype Output = String;\n\nstruct DayXX;\nimpl Solution for DayXX {\n fn parse_input>(pathname: P) -> Input {\n file_to_string(pathname)\n }\n\n fn part_1(input: &Input) -> Output {\n todo!()\n }\n\n fn part_2(input: &Input) -> Output {\n todo!()\n }\n}\n\nfn main() -> Result<()> {\n // DayXX::run("sample")\n DayXX::main()\n}\n\n// test_sample!(day_XX, DayXX, , );\n')),(0,i.kt)("h3",{id:"solution-1"},"Solution"),(0,i.kt)("p",null,"Not much to talk about, it is relatively easy to simulate."),(0,i.kt)("h2",{id:"day-10-cathode-ray-tube"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/10"},"Day 10: Cathode-Ray Tube")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Emulating basic arithmetic operations on a CPU and drawing on CRT based on the\nCPU's accumulator.")),(0,i.kt)("p",null,"In this day I have discovered an issue with my design of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Solution")," trait.\nAnd the issue is caused by different types of ",(0,i.kt)("inlineCode",{parentName:"p"},"Output")," for the part 1 and part 2."),(0,i.kt)("p",null,"Problem is relatively simple and consists of simulating a CPU, I have approached\nit in a following way:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"fn evaluate_instructions(instructions: &[Instruction], mut out: Output) -> Output {\n instructions\n .iter()\n .fold(State::new(), |state, instruction| {\n state.execute(instruction, &mut out)\n });\n\n out\n}\n")),(0,i.kt)("p",null,"We just take the instructions, we have some state of the CPU and we execute the\ninstructions one-by-one. Perfect usage of the ",(0,i.kt)("inlineCode",{parentName:"p"},"fold")," (or ",(0,i.kt)("inlineCode",{parentName:"p"},"reduce")," as you may know\nit from other languages)."),(0,i.kt)("p",null,"You can also see that we have an ",(0,i.kt)("inlineCode",{parentName:"p"},"Output")," type, so the question is how can we fix\nthat problem. And the answer is very simple and ",(0,i.kt)("em",{parentName:"p"},"functional"),". Rust allows you to\nhave an ",(0,i.kt)("inlineCode",{parentName:"p"},"enumeration")," that can ",(0,i.kt)("em",{parentName:"p"},"bear")," some other values apart from the type itself."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"We could've seen something like this with the ",(0,i.kt)("inlineCode",{parentName:"p"},"Result")," type that can be\ndefined as"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"enum Result {\n Ok(T),\n Err(E)\n}\n")),(0,i.kt)("h6",{parentName:"admonition",id:"what-does-that-mean-though"},"What does that mean though?"),(0,i.kt)("p",{parentName:"admonition"},"When we have an ",(0,i.kt)("inlineCode",{parentName:"p"},"Ok")," value, it has the result itself, and when we get an ",(0,i.kt)("inlineCode",{parentName:"p"},"Err"),"\nvalue, it has the error. This also allows us to handle ",(0,i.kt)("em",{parentName:"p"},"results")," in a rather\npretty way:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'match do_something(x) {\n Ok(y) => {\n println!("SUCCESS: {}", y);\n },\n Err(y) => {\n eprintln!("ERROR: {}", y);\n }\n}\n'))),(0,i.kt)("p",null,"My solution has a following outline:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"fn execute(&self, i: &Instruction, output: &mut Output) -> State {\n // execute the instruction\n\n // collect results if necessary\n match output {\n Output::Part1(x) => self.execute_part_1(y, x),\n Output::Part2(x) => self.execute_part_2(y, x),\n }\n\n // return the obtained state\n new_state\n}\n")),(0,i.kt)("p",null,"You might think that it's a perfectly reasonable thing to do. Yes, ",(0,i.kt)("strong",{parentName:"p"},"but")," notice\nthat the ",(0,i.kt)("inlineCode",{parentName:"p"},"match")," statement doesn't ",(0,i.kt)("em",{parentName:"p"},"collect")," the changes in any way and also we\npass ",(0,i.kt)("inlineCode",{parentName:"p"},"output")," by ",(0,i.kt)("inlineCode",{parentName:"p"},"&mut"),", so it is shared across each ",(0,i.kt)("em",{parentName:"p"},"iteration")," of the ",(0,i.kt)("inlineCode",{parentName:"p"},"fold"),"."),(0,i.kt)("p",null,"The dirty and ingenious thing is that ",(0,i.kt)("inlineCode",{parentName:"p"},"x"),"s are passed by ",(0,i.kt)("inlineCode",{parentName:"p"},"&mut")," too and therefore\nthey are directly modified by the helper functions. To sum it up and let it sit"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"We are ",(0,i.kt)("strong",{parentName:"p"},"collecting")," the result ",(0,i.kt)("strong",{parentName:"p"},"into")," an ",(0,i.kt)("strong",{parentName:"p"},"enumeration")," that is ",(0,i.kt)("strong",{parentName:"p"},"shared"),"\nacross ",(0,i.kt)("strong",{parentName:"p"},"all")," iterations of ",(0,i.kt)("inlineCode",{parentName:"p"},"fold"),".")),(0,i.kt)("h3",{id:"solution-2"},"Solution"),(0,i.kt)("p",null,"Similar to ",(0,i.kt)("em",{parentName:"p"},"Day 9"),", but there are some technical details that can get you."),(0,i.kt)("h2",{id:"day-11-monkey-in-the-middle"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/11"},"Day 11: Monkey in the Middle")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Simulation of monkeys throwing stuff around and measuring your stress levels\nwhile your stuff is being passed around.")),(0,i.kt)("p",null,"I think I decided to use regular expressions here for the first time, cause\nparsing the input was a pain."),(0,i.kt)("p",null,"Also I didn't expect to implement Euclidean algorithm in Rust\u2026"),(0,i.kt)("h3",{id:"solution-3"},"Solution"),(0,i.kt)("p",null,"Again, we're just running a simulation. Though I must admit it was very easy to\nmake a small technical mistakes that could affect the final results very late."),(0,i.kt)("h2",{id:"day-12-hill-climbing-algorithm"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/12"},"Day 12: Hill Climbing Algorithm")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Finding shortest path up the hill and also shortest path down to the ground while\nalso rolling down the hill\u2026")),(0,i.kt)("p",null,"As I have said in the ",(0,i.kt)("em",{parentName:"p"},"tl;dr"),", we are looking for the shortest path, but the start\nand goal differ for the part 1 and 2. So I have decided to refactor my solution\nto a BFS algorithm that takes necessary parameters via functions:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"fn bfs(\n graph: &[Vec], start: &Position, has_edge: F, is_target: G\n) -> Option\nwhere\n F: Fn(&[Vec], &Position, &Position) -> bool,\n G: Fn(&[Vec], &Position) -> bool\n")),(0,i.kt)("p",null,"We pass the initial vertex from the caller and everything else is left to the BFS\nalgorithm, based on the ",(0,i.kt)("inlineCode",{parentName:"p"},"has_edge")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"is_target")," functions."),(0,i.kt)("p",null,"This was easy! And that is not very usual in Rust once you want to pass around\nfunctions. \ud83d\udc40"),(0,i.kt)("h3",{id:"solution-4"},"Solution"),(0,i.kt)("p",null,"Looking for the shortest path\u2026 Must be Dijkstra, right? ",(0,i.kt)("strong",{parentName:"p"},"Nope!")," Half of the\nReddit got jebaited though. In all fairness, nothing stops you from implementing\nthe Dijkstra's algorithm for finding the shortest path, ",(0,i.kt)("strong",{parentName:"p"},"but")," if you know that\nall connected vertices are in a unit (actually ",(0,i.kt)("span",{parentName:"p",className:"math math-inline"},(0,i.kt)("span",{parentName:"span",className:"katex"},(0,i.kt)("span",{parentName:"span",className:"katex-mathml"},(0,i.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,i.kt)("semantics",{parentName:"math"},(0,i.kt)("mrow",{parentName:"semantics"},(0,i.kt)("mi",{parentName:"mrow"},"d"),(0,i.kt)("mo",{parentName:"mrow"},"="),(0,i.kt)("mn",{parentName:"mrow"},"1")),(0,i.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"d = 1")))),(0,i.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,i.kt)("span",{parentName:"span",className:"base"},(0,i.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,i.kt)("span",{parentName:"span",className:"mord mathnormal"},"d"),(0,i.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.kt)("span",{parentName:"span",className:"mrel"},"="),(0,i.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,i.kt)("span",{parentName:"span",className:"base"},(0,i.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,i.kt)("span",{parentName:"span",className:"mord"},"1"))))),") distance from each other,\nthen you know that running Dijkstra is equivalent to running BFS, only with worse\ntime complexity, because of the priority heap instead of the queue."),(0,i.kt)("h2",{id:"day-13-distress-signal"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/13"},"Day 13: Distress Signal")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Processing packets with structured data from the distress signal.")),(0,i.kt)("p",null,"You can implement a lot of traits if you want to. It is ",(0,i.kt)("em",{parentName:"p"},"imperative")," to implement\nordering on the packets. I had a typo, so I also proceeded to implement a ",(0,i.kt)("inlineCode",{parentName:"p"},"Display"),"\ntrait for debugging purposes:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'impl Display for Packet {\n fn fmt(&self, f: &mut std::fmt::Formatter<\'_>) -> std::fmt::Result {\n match self {\n Packet::Integer(x) => write!(f, "{x}"),\n Packet::List(lst) => write!(f, "[{}]", lst.iter().map(|p| format!("{p}")).join(",")),\n }\n }\n}\n')),(0,i.kt)("h3",{id:"solution-5"},"Solution"),(0,i.kt)("p",null,"A lot of technical details\u2026 Parsing is nasty too\u2026"),(0,i.kt)("h2",{id:"day-14-regolith-reservoir"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/14"},"Day 14: Regolith Reservoir")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Let's simulate falling sand grain-by-grain.")),(0,i.kt)("p",null,"Again, both parts are relatively similar with minimal changes, so it is a good\nidea to refactor it a bit. Similar approach to the ",(0,i.kt)("a",{parentName:"p",href:"#day-12-hill-climbing-algorithm"},"BFS above"),". Also this is the\nfirst day where I ran into efficiency issues and had to redo my solution to speed\nit up just a bit."),(0,i.kt)("h3",{id:"solution-6"},"Solution"),(0,i.kt)("p",null,"Tedious."),(0,i.kt)("h2",{id:"post-mortem"},"Post Mortem"),(0,i.kt)("h3",{id:"indexing"},"Indexing"),(0,i.kt)("p",null,"I was asked about the indexing after publishing the blog. And truly it is rather\ncomplicated topic, especially after releasing ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex")," trait. I couldn't\nleave it be, so I tried to implement the ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," trait."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"I have also mentioned that the ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex")," trait is ",(0,i.kt)("inlineCode",{parentName:"p"},"unsafe"),", but truth be told,\nonly ",(0,i.kt)("em",{parentName:"p"},"unsafe")," part are the 2 methods that are named ",(0,i.kt)("inlineCode",{parentName:"p"},"*unchecked*"),". Anyways, I will\nbe implementing the ",(0,i.kt)("inlineCode",{parentName:"p"},"Index*")," traits for now, rather than the ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex"),".")),(0,i.kt)("p",null,"It's relatively straightforward\u2026"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"impl Index> for [C]\nwhere\n I: Copy + TryInto,\n >::Error: Debug,\n C: Index,\n{\n type Output = C::Output;\n\n fn index(&self, index: Vector2D) -> &Self::Output {\n let (x, y): (usize, usize) =\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\n &self[y][x]\n }\n}\n\nimpl IndexMut> for [C]\nwhere\n I: Copy + TryInto,\n >::Error: Debug,\n C: IndexMut,\n{\n fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output {\n let (x, y): (usize, usize) =\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\n &mut self[y][x]\n }\n}\n")),(0,i.kt)("p",null,"We can see a lot of similarities to the implementation of ",(0,i.kt)("inlineCode",{parentName:"p"},"index")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"index_mut"),"\nfunctions. In the end, they are 1:1, just wrapped in the trait that provides a\nsyntax sugar for ",(0,i.kt)("inlineCode",{parentName:"p"},"container[idx]"),"."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"I have also switched from using the ",(0,i.kt)("inlineCode",{parentName:"p"},"TryFrom")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"TryInto")," trait, since it better\nmatches what we are using, the ",(0,i.kt)("inlineCode",{parentName:"p"},".try_into")," rather than ",(0,i.kt)("inlineCode",{parentName:"p"},"usize::try_from"),"."),(0,i.kt)("p",{parentName:"admonition"},"Also implementing ",(0,i.kt)("inlineCode",{parentName:"p"},"TryFrom")," automatically provides you with a ",(0,i.kt)("inlineCode",{parentName:"p"},"TryInto")," trait,\nsince it is relatively easy to implement. Just compare the following:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub trait TryFrom: Sized {\n type Error;\n\n fn try_from(value: T) -> Result;\n}\n\npub trait TryInto: Sized {\n type Error;\n\n fn try_into(self) -> Result;\n}\n"))),(0,i.kt)("p",null,"OK, so we have our trait implemented, we should be able to use ",(0,i.kt)("inlineCode",{parentName:"p"},"container[index]"),",\nright? Yes\u2026 but actually no \ud83d\ude26"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"error[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\n --\x3e src/bin/day08.rs:26:18\n |\n26 | if trees[pos] > tallest {\n | ^^^ slice indices are of type `usize` or ranges of `usize`\n |\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\n\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\n --\x3e src/bin/day08.rs:30:28\n |\n30 | max(tallest, trees[pos])\n | ^^^ slice indices are of type `usize` or ranges of `usize`\n |\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\n\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\n --\x3e src/bin/day08.rs:52:28\n |\n52 | let max_height = trees[position];\n | ^^^^^^^^ slice indices are of type `usize` or ranges of `usize`\n |\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\n")),(0,i.kt)("p",null,"Why? We have it implemented for the slices (",(0,i.kt)("inlineCode",{parentName:"p"},"[C]"),"), why doesn't it work? Well,\nthe fun part consists of the fact that in other place, where we were using it,\nwe were passing the ",(0,i.kt)("inlineCode",{parentName:"p"},"&[Vec]"),", but this is coming from a helper functions that\ntake ",(0,i.kt)("inlineCode",{parentName:"p"},"&Vec>")," instead. And\u2026 we don't implement ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," for\nthose. Just for the slices. \ud83e\udd2f ",(0,i.kt)("em",{parentName:"p"},"What are we going to do about it?")),(0,i.kt)("p",null,"We can either start copy-pasting or be smarter about it\u2026 I choose to be smarter,\nso let's implement a macro! The only difference across the implementations are\nthe types of the outer containers. Implementation doesn't differ ",(0,i.kt)("strong",{parentName:"p"},"at all"),"!"),(0,i.kt)("p",null,"Implementing the macro can be done in a following way:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"macro_rules! generate_indices {\n ($container:ty) => {\n impl Index> for $container\n where\n I: Copy + TryInto,\n >::Error: Debug,\n C: Index,\n {\n type Output = C::Output;\n\n fn index(&self, index: Vector2D) -> &Self::Output {\n let (x, y): (usize, usize) =\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\n &self[y][x]\n }\n }\n\n impl IndexMut> for $container\n where\n I: Copy + TryInto,\n >::Error: Debug,\n C: IndexMut,\n {\n fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output {\n let (x, y): (usize, usize) =\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\n &mut self[y][x]\n }\n }\n };\n}\n")),(0,i.kt)("p",null,"And now we can simply do"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"generate_indices!(VecDeque);\ngenerate_indices!([C]);\ngenerate_indices!(Vec);\n// generate_indices!([C; N], const N: usize);\n")),(0,i.kt)("p",null,"The last type (I took the inspiration from the implementations of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," and\n",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," traits) is a bit problematic, because of the ",(0,i.kt)("inlineCode",{parentName:"p"},"const N: usize")," part,\nwhich I haven't managed to be able to parse. And that's how I got rid of the error."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"If I were to use 2D-indexing over ",(0,i.kt)("inlineCode",{parentName:"p"},"[C; N]")," slices, I'd probably just go with the\ncopy-paste, cause the cost of this \u201cmonstrosity\u201d outweighs the benefits of no DRY.")),(0,i.kt)("h4",{id:"cause-of-the-problem"},"Cause of the problem"),(0,i.kt)("p",null,"This issue is relatively funny. If you don't use any type aliases, just the raw\ntypes, you'll get suggested certain changes by the ",(0,i.kt)("em",{parentName:"p"},"clippy"),". For example if you\nconsider the following piece of code"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'fn get_sum(nums: &Vec) -> i32 {\n nums.iter().sum()\n}\n\nfn main() {\n let nums = vec![1, 2, 3];\n println!("Sum: {}", get_sum(&nums));\n}\n')),(0,i.kt)("p",null,"and you run ",(0,i.kt)("em",{parentName:"p"},"clippy")," on it, you will get"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Checking playground v0.0.1 (/playground)\nwarning: writing `&Vec` instead of `&[_]` involves a new object where a slice will do\n --\x3e src/main.rs:1:18\n |\n1 | fn get_sum(nums: &Vec) -> i32 {\n | ^^^^^^^^^ help: change this to: `&[i32]`\n |\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg\n = note: `#[warn(clippy::ptr_arg)]` on by default\n\nwarning: `playground` (bin "playground") generated 1 warning\n Finished dev [unoptimized + debuginfo] target(s) in 0.61s\n')),(0,i.kt)("p",null,"However, if you introduce a type alias, such as"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"type Numbers = Vec;\n")),(0,i.kt)("p",null,"Then ",(0,i.kt)("em",{parentName:"p"},"clippy")," won't say anything, cause there is literally nothing to suggest.\nHowever the outcome is not the same\u2026"))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1011],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>c});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),h=i,c=d["".concat(s,".").concat(h)]||d[h]||m[h]||o;return n?a.createElement(c,r(r({ref:t},u),{},{components:n})):a.createElement(c,r({ref:t},u))}));function c(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,r[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const o={title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15",slug:"aoc-2022/2nd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},r=void 0,l={permalink:"/blog/aoc-2022/2nd-week",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/02-week-2.md",source:"@site/blog/aoc-2022/02-week-2.md",title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15:00.000Z",formattedDate:"December 25, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:20.875,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15",slug:"aoc-2022/2nd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"Sort the matrix diagonally",permalink:"/blog/leetcode/sort-diagonally"},nextItem:{title:"1st week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/1st-week"}},s={authorsImageUrls:[void 0]},p=[{value:"Day 8: Treetop Tree House",id:"day-8-treetop-tree-house",level:2},{value:"Swapping indices",id:"swapping-indices",level:4},{value:"Indexing Vec",id:"indexing-vec",level:4},{value:"Issues",id:"issues",level:5},{value:"Checking bounds",id:"checking-bounds",level:4},{value:"Solution",id:"solution",level:3},{value:"Day 9: Rope Bridge",id:"day-9-rope-bridge",level:2},{value:"Solution",id:"solution-1",level:3},{value:"Day 10: Cathode-Ray Tube",id:"day-10-cathode-ray-tube",level:2},{value:"Solution",id:"solution-2",level:3},{value:"Day 11: Monkey in the Middle",id:"day-11-monkey-in-the-middle",level:2},{value:"Solution",id:"solution-3",level:3},{value:"Day 12: Hill Climbing Algorithm",id:"day-12-hill-climbing-algorithm",level:2},{value:"Solution",id:"solution-4",level:3},{value:"Day 13: Distress Signal",id:"day-13-distress-signal",level:2},{value:"Solution",id:"solution-5",level:3},{value:"Day 14: Regolith Reservoir",id:"day-14-regolith-reservoir",level:2},{value:"Solution",id:"solution-6",level:3},{value:"Post Mortem",id:"post-mortem",level:2},{value:"Indexing",id:"indexing",level:3},{value:"Cause of the problem",id:"cause-of-the-problem",level:4}],u={toc:p},d="wrapper";function m(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Let's go through the second week of ",(0,i.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,i.kt)("em",{parentName:"a"},"Advent of Code"))," in Rust."),(0,i.kt)("h2",{id:"day-8-treetop-tree-house"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/8"},"Day 8: Treetop Tree House")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"We get a forest and we want to know how many trees are visible from the outside.\nApart from that we want to find the best view.")),(0,i.kt)("p",null,"Nothing interesting. We are moving around 2D map though. And indexing can get a\nbit painful when doing so, let's refactor it a bit ;) During the preparation for\nthe AoC, I have written ",(0,i.kt)("inlineCode",{parentName:"p"},"Vector2D")," and now it's time to extend it with indexing\nof ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec")," of ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec"),"s. In my solution I was manipulating with indices in the following\nway:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"swapping them"),(0,i.kt)("li",{parentName:"ul"},"checking whether they are correct indices for the ",(0,i.kt)("inlineCode",{parentName:"li"},"Vec>")),(0,i.kt)("li",{parentName:"ul"},"indexing ",(0,i.kt)("inlineCode",{parentName:"li"},"Vec>")," with them")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"I'm getting familiar with Rust and starting to \u201cabuse\u201d it\u2026 While doing so, I'm\nalso uncovering some \u201cfeatures\u201d that I don't really like. Therefore I will mark\nall of my rants with ",(0,i.kt)("em",{parentName:"p"},"thicc")," ",(0,i.kt)("strong",{parentName:"p"},"\xab\u21af\xbb")," mark and will try to \u201clock\u201d them into their\nown \u201cbox of hell\u201d.")),(0,i.kt)("h4",{id:"swapping-indices"},"Swapping indices"),(0,i.kt)("p",null,"Relatively simple implementation, just take the values, swap them and return new\nvector."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"impl Vector2D {\n pub fn swap(&self) -> Self {\n Self {\n x: self.y,\n y: self.x,\n }\n }\n}\n")),(0,i.kt)("p",null,"Pretty straight-forward implementation, but let's talk about the ",(0,i.kt)("inlineCode",{parentName:"p"},"T: Copy"),". We\nneed to use it, since we are returning a ",(0,i.kt)("strong",{parentName:"p"},"new")," vector, with swapped ",(0,i.kt)("strong",{parentName:"p"},"values"),".\nIf we had values that cannot be copied, the only thing we could do, would be a\nvector of references (and it would also introduce a lifetime, to which we'll get\nlater on). This is pretty similar with the operations on sets from the first week."),(0,i.kt)("h4",{id:"indexing-vec"},"Indexing ",(0,i.kt)("inlineCode",{parentName:"h4"},"Vec")),(0,i.kt)("p",null,"I will start with the indexing, cause bound-checking is a bit more\u2026 complicated\nthan I would like to."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn index<'a, T, U>(v: &'a [Vec], idx: &Vector2D) -> &'a U\nwhere\n usize: TryFrom,\n >::Error: Debug,\n T: Copy,\n{\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\n &v[y][x]\n}\n")),(0,i.kt)("p",null,"Let's talk about this mess\u2026 Body of the function is probably the most easy part\nand should not be hard to understand, we just take the ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," and convert\nthem both to ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," type that can be used later on for indexing."),(0,i.kt)("p",null,"The type signature of the function is where the fun is at \ud83d\ude09 We are trying\nto convert unknown type to ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),", so we must bound the ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," as a type that can\nbe converted to ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),", that's how we got ",(0,i.kt)("inlineCode",{parentName:"p"},"usize: TryFrom")," which basically\nsays that ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," must implement ",(0,i.kt)("inlineCode",{parentName:"p"},"TryFrom")," trait and therefore allows us to\nconvert the indices to actual ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," indices. Using ",(0,i.kt)("inlineCode",{parentName:"p"},".unwrap()")," also forces us\nto bound the error that can occur when converting ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," into ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),", that's how\nwe get ",(0,i.kt)("inlineCode",{parentName:"p"},">::Error: Debug")," which loosely means"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"error during conversion of ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," into ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," must implement ",(0,i.kt)("inlineCode",{parentName:"p"},"Debug"),",\ni.e. can be printed in some way or other")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"T: Copy")," is required by ",(0,i.kt)("inlineCode",{parentName:"p"},".try_into()")," which takes ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," by-value."),(0,i.kt)("p",null,"And now we are left only with the first line of the definition."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"Skilled Rustaceans might notice that this implementation is rather flaky and can\nbreak in multiple places at once. I'll get back to it\u2026")),(0,i.kt)("p",null,"Let's split it in multiple parts:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"v: &'a [Vec]")," represents the 2D ",(0,i.kt)("inlineCode",{parentName:"li"},"Vec"),", we are indexing, ",(0,i.kt)("inlineCode",{parentName:"li"},"Vec")," implements\n",(0,i.kt)("inlineCode",{parentName:"li"},"Slice")," trait and ",(0,i.kt)("em",{parentName:"li"},"clippy")," recommends using ",(0,i.kt)("inlineCode",{parentName:"li"},"&[T]")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"&Vec"),", exact details\nare unknown to me"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"idx: &Vector2D")," represents the ",(0,i.kt)("em",{parentName:"li"},"indices")," which we use, we take them by\nreference to avoid an unnecessary copy"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"-> &'a U")," means that we are returning a ",(0,i.kt)("em",{parentName:"li"},"reference")," to some value of type ",(0,i.kt)("inlineCode",{parentName:"li"},"U"),".\nNow the question is what does the ",(0,i.kt)("inlineCode",{parentName:"li"},"'a")," mean, we can also see it as a generic\ntype declared along ",(0,i.kt)("inlineCode",{parentName:"li"},"T")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"U"),". And the answer is ",(0,i.kt)("em",{parentName:"li"},"relatively")," simple, ",(0,i.kt)("inlineCode",{parentName:"li"},"'a"),"\nrepresents a ",(0,i.kt)("em",{parentName:"li"},"lifetime"),". We take the ",(0,i.kt)("inlineCode",{parentName:"li"},"v")," by a reference and return a reference,\nborrow checker validates all of the ",(0,i.kt)("em",{parentName:"li"},"borrows")," (or references), so we need to\nspecify that our returned value has ",(0,i.kt)("em",{parentName:"li"},"the same lifetime")," as the vector we have\ntaken by a reference, i.e. returned reference must live at least as long as the\n",(0,i.kt)("inlineCode",{parentName:"li"},"v"),". This way we can \u201cbe sure\u201d that the returned reference is valid.")),(0,i.kt)("h5",{id:"issues"},"Issues"),(0,i.kt)("p",null,"First issue that our implementation has is the fact that we cannot get a mutable\nreference out of that function. This could be easily resolved by introducing new\nfunction, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"index_mut"),". Which I have actually done while writing this part:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn index_mut<'a, T, U>(v: &'a mut [Vec], idx: &Vector2D) -> &'a mut U\nwhere\n usize: TryFrom,\n >::Error: Debug,\n T: Copy,\n{\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\n &mut v[y][x]\n}\n")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("mdxAdmonitionTitle",{parentName:"admonition"},(0,i.kt)("strong",{parentName:"mdxAdmonitionTitle"},"\xab\u21af\xbb")," Why can't we use one function?"),(0,i.kt)("p",{parentName:"admonition"},"When we consider a ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec"),", we don't need to consider containers as ",(0,i.kt)("inlineCode",{parentName:"p"},"T"),", Rust\nimplements indexing as traits ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," that do the dirty work\nbehind syntactic sugar of ",(0,i.kt)("inlineCode",{parentName:"p"},"container[idx]"),"."),(0,i.kt)("p",{parentName:"admonition"},"However, implementing of traits is not allowed for ",(0,i.kt)("em",{parentName:"p"},"external")," types, i.e. types\nthat you haven't defined yourself. This means that you can implement indexing\nover containers that you have implemented yourself, but you cannot use your own\ntypes for indexing \u201cbuilt-in\u201d types."),(0,i.kt)("p",{parentName:"admonition"},"Another part of this rabbit hole is trait ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex")," that is of a relevance\nbecause of"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"impl Index for [T]\nwhere\n I: SliceIndex<[T]>\n\nimpl Index for Vec\nwhere\n I: SliceIndex<[T]>,\n A: Allocator\n\nimpl Index for [T; N]\nwhere\n [T]: Index\n")),(0,i.kt)("p",{parentName:"admonition"},"In other words, if your type implements ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex")," trait, it can be used\nfor indexing. As of now, this trait has all of its required methods experimental\nand is marked as ",(0,i.kt)("inlineCode",{parentName:"p"},"unsafe"),".")),(0,i.kt)("p",null,"Another problem is a requirement for indexing either ",(0,i.kt)("inlineCode",{parentName:"p"},"[Vec]")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec>"),".\nThis requirement could be countered by removing inner type ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec")," and constraining\nit by a trait ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," (or ",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," respectively) in a following way"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn index<'a, C, T>(v: &'a [C], idx: &Vector2D) -> &'a C::Output\nwhere\n usize: TryFrom,\n >::Error: Debug,\n T: Copy,\n C: Index\n{\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\n &v[y][x]\n}\n")),(0,i.kt)("p",null,"Given this, we can also give a more meaningful typename for indexing type, such\nas ",(0,i.kt)("inlineCode",{parentName:"p"},"I"),"."),(0,i.kt)("h4",{id:"checking-bounds"},"Checking bounds"),(0,i.kt)("p",null,"Now we can get to the boundary checks, it is very similar, but a more\u2026 dirty.\nFirst approach that came up was to convert the indices in ",(0,i.kt)("inlineCode",{parentName:"p"},"Vector2D")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),",\nbut when you add the indices up, e.g. when checking the neighbors, you can end\nup with negative values which, unlike in C++, causes an error (instead of underflow\nthat you can use to your advantage; you can easily guess how)."),(0,i.kt)("p",null,"So how can we approach this then? Well\u2026 we will convert the bounds instead of\nthe indices and that lead us to:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn in_range(v: &[Vec], idx: &Vector2D) -> bool\nwhere\n usize: TryInto,\n >::Error: Debug,\n T: PartialOrd + Copy,\n{\n idx.y >= 0.try_into().unwrap()\n && idx.y < v.len().try_into().unwrap()\n && idx.x >= 0.try_into().unwrap()\n && idx.x\n < v[TryInto::::try_into(idx.y).unwrap()]\n .len()\n .try_into()\n .unwrap()\n}\n")),(0,i.kt)("p",null,"You can tell that it's definitely a shitty code. Let's improve it now! We will\nget back to the original idea, but do it better. We know that we cannot convert\nnegative values into ",(0,i.kt)("inlineCode",{parentName:"p"},"usize"),", ",(0,i.kt)("strong",{parentName:"p"},"but")," we also know that conversion like that\nreturns a ",(0,i.kt)("inlineCode",{parentName:"p"},"Result")," which we can use to our advantage."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn in_range(v: &[Vec], idx: &Vector2D) -> bool\nwhere\n T: Copy,\n usize: TryFrom,\n{\n usize::try_from(idx.y)\n .and_then(|y| usize::try_from(idx.x).map(|x| y < v.len() && x < v[y].len()))\n .unwrap_or(false)\n}\n")),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"Result")," is a type similar to ",(0,i.kt)("inlineCode",{parentName:"p"},"Either")," in Haskell and it allows us to chain\nmultiple operations on correct results or propagate the original error without\ndoing anything. Let's dissect it one-by-one."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"try_from")," is a method implemented in ",(0,i.kt)("inlineCode",{parentName:"p"},"TryFrom")," trait, that allows you to convert\ntypes and either successfully convert them or fail (with a reasonable error). This\nmethod returns ",(0,i.kt)("inlineCode",{parentName:"p"},"Result"),"."),(0,i.kt)("p",null,"We call ",(0,i.kt)("inlineCode",{parentName:"p"},"and_then")," on that ",(0,i.kt)("em",{parentName:"p"},"result"),", let's have a look at the type signature of\n",(0,i.kt)("inlineCode",{parentName:"p"},"and_then"),", IMO it explains more than enough:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn and_then(self, op: F) -> Result\nwhere\n F: FnOnce(T) -> Result\n")),(0,i.kt)("p",null,"OK\u2026 So it takes the result and a function and returns another result with\ndifferent value and different error. However we can see that the function, which\nrepresents an operation on a result, takes just the value, i.e. it doesn't care\nabout any previous error. To make it short:"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},(0,i.kt)("inlineCode",{parentName:"p"},"and_then")," allows us to run an operation, which can fail, on the correct result")),(0,i.kt)("p",null,"We parsed a ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," index and now we try to convert the ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," index with ",(0,i.kt)("inlineCode",{parentName:"p"},"try_from"),"\nagain, but on that result we use ",(0,i.kt)("inlineCode",{parentName:"p"},"map")," rather than ",(0,i.kt)("inlineCode",{parentName:"p"},"and_then"),", why would that be?"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn map(self, op: F) -> Result\nwhere\n F: FnOnce(T) -> U\n")),(0,i.kt)("p",null,"Huh\u2026 ",(0,i.kt)("inlineCode",{parentName:"p"},"map")," performs an operation that ",(0,i.kt)("strong",{parentName:"p"},"cannot")," fail. And finally we use\n",(0,i.kt)("inlineCode",{parentName:"p"},"unwrap_or")," which takes the value from result, or in case of an error returns the\ndefault that we define."),(0,i.kt)("p",null,"How does this work then? If ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," is negative, the conversion fails and the error\npropagates all the way to ",(0,i.kt)("inlineCode",{parentName:"p"},"unwrap_or"),", if ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," can be a correct ",(0,i.kt)("inlineCode",{parentName:"p"},"usize")," value, then\nwe do the same with ",(0,i.kt)("inlineCode",{parentName:"p"},"x"),". If ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," is negative, we propagate the error as with ",(0,i.kt)("inlineCode",{parentName:"p"},"y"),",\nand if it's not, then we check whether it exceeds the higher bounds or not."),(0,i.kt)("h3",{id:"solution"},"Solution"),(0,i.kt)("p",null,"Relatively simple, you just need follow the rules and not get too smart, otherwise\nit will get back at you."),(0,i.kt)("h2",{id:"day-9-rope-bridge"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/9"},"Day 9: Rope Bridge")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"We get a rope with knots and we want to track how many different positions are\nvisited with the rope's tail.")),(0,i.kt)("p",null,"By this day, I have come to a conclusion that current skeleton for each day\ngenerates a lot of boilerplate. And even though it can be easily copied, it's\njust a waste of space and unnecessary code. Let's \u201csimplify\u201d this (on one end\nwhile creating monster on the other end). I've gone through what we need in the\npreparations for the AoC. Let's sum up our requirements:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"parsing"),(0,i.kt)("li",{parentName:"ul"},"part 1 & 2"),(0,i.kt)("li",{parentName:"ul"},"running on sample / input"),(0,i.kt)("li",{parentName:"ul"},"tests")),(0,i.kt)("p",null,"Parsing and implementation of both parts is code that changes each day and we\ncannot do anything about it. However running and testing can be simplified!"),(0,i.kt)("p",null,"Let's introduce and export a new module ",(0,i.kt)("inlineCode",{parentName:"p"},"solution")," that will take care of all of\nthis. We will start by introducing a trait for each day."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub trait Solution {\n fn parse_input>(pathname: P) -> Input;\n\n fn part_1(input: &Input) -> Output;\n fn part_2(input: &Input) -> Output;\n}\n")),(0,i.kt)("p",null,"This does a lot of work for us already, we have defined a trait and for each day\nwe will create a structure representing a specific day. That structure will also\nimplement the ",(0,i.kt)("inlineCode",{parentName:"p"},"Solution")," trait."),(0,i.kt)("p",null,"Now we need to get rid of the boilerplate, we can't get rid of the ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," function,\nbut we can at least move out the functionality."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'fn run(type_of_input: &str) -> Result<()>\nwhere\n Self: Sized,\n{\n tracing_subscriber::fmt()\n .with_env_filter(EnvFilter::from_default_env())\n .with_target(false)\n .with_file(true)\n .with_line_number(true)\n .without_time()\n .compact()\n .init();\n color_eyre::install()?;\n\n let input = Self::parse_input(format!("{}s/{}.txt", type_of_input, Self::day()));\n\n info!("Part 1: {}", Self::part_1(&input));\n info!("Part 2: {}", Self::part_2(&input));\n\n Ok(())\n}\n\nfn main() -> Result<()>\nwhere\n Self: Sized,\n{\n Self::run("input")\n}\n')),(0,i.kt)("p",null,"This is all part of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Solution")," trait, which can implement methods while being\ndependent on what is provided by the implementing types. In this case, we just\nneed to bound the ",(0,i.kt)("inlineCode",{parentName:"p"},"Output")," type to implement ",(0,i.kt)("inlineCode",{parentName:"p"},"Display")," that is necessary for the\n",(0,i.kt)("inlineCode",{parentName:"p"},"info!")," and format string there."),(0,i.kt)("p",null,"Now we can get to first of the nasty things we are going to do\u2026 And it is the\n",(0,i.kt)("inlineCode",{parentName:"p"},"day()")," method that you can see being used when constructing path to the input\nfile. That method will generate a name of the file, e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"day01")," and we know that\nwe can ",(0,i.kt)("em",{parentName:"p"},"somehow")," deduce it from the structure name, given we name it reasonably."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'fn day() -> String {\n let mut day = String::from(type_name::().split("::").next().unwrap());\n day.make_ascii_lowercase();\n\n day.to_string()\n}\n')),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("mdxAdmonitionTitle",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"mdxAdmonitionTitle"},"type_name")),(0,i.kt)("p",{parentName:"admonition"},"This feature is still experimental and considered to be internal, it is not\nadvised to use it any production code.")),(0,i.kt)("p",null,"And now we can get to the nastiest stuff \ud83d\ude29 We will ",(0,i.kt)("strong",{parentName:"p"},"generate")," the tests!"),(0,i.kt)("p",null,"We want to be able to generate tests for sample input in a following way:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"test_sample!(day_01, Day01, 42, 69);\n")),(0,i.kt)("p",null,"There's not much we can do, so we will write a macro to generate the tests for us."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'#[macro_export]\nmacro_rules! test_sample {\n ($mod_name:ident, $day_struct:tt, $part_1:expr, $part_2:expr) => {\n #[cfg(test)]\n mod $mod_name {\n use super::*;\n\n #[test]\n fn test_part_1() {\n let sample =\n $day_struct::parse_input(&format!("samples/{}.txt", $day_struct::day()));\n assert_eq!($day_struct::part_1(&sample), $part_1);\n }\n\n #[test]\n fn test_part_2() {\n let sample =\n $day_struct::parse_input(&format!("samples/{}.txt", $day_struct::day()));\n assert_eq!($day_struct::part_2(&sample), $part_2);\n }\n }\n };\n}\n')),(0,i.kt)("p",null,"We have used it in a similar way as macros in C/C++, one of the things that we\ncan use to our advantage is defining \u201ctype\u201d of the parameters for the macro. All\nparameters have their name prefixed with ",(0,i.kt)("inlineCode",{parentName:"p"},"$")," sign and you can define various \u201cforms\u201d\nof your macro. Let's go through it!"),(0,i.kt)("p",null,"We have following parameters:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"$mod_name")," which represents the name for the module with tests, it is typed\nwith ",(0,i.kt)("inlineCode",{parentName:"li"},"ident")," which means that we want a valid identifier to be passed in."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"$day_struct")," represents the structure that will be used for tests, it is typed\nwith ",(0,i.kt)("inlineCode",{parentName:"li"},"tt")," which represents a ",(0,i.kt)("em",{parentName:"li"},"token tree"),", in our case it is a type."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"$part_X")," represents the expected output for the ",(0,i.kt)("inlineCode",{parentName:"li"},"X"),"th part and is of type ",(0,i.kt)("inlineCode",{parentName:"li"},"expr"),"\nwhich literally means an ",(0,i.kt)("em",{parentName:"li"},"expression"),".")),(0,i.kt)("p",null,"Apart from that we need to use ",(0,i.kt)("inlineCode",{parentName:"p"},"#[macro_export]")," to mark the macro as exported\nfor usage outside of the module. Now our skeleton looks like:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'use aoc_2022::*;\n\ntype Input = String;\ntype Output = String;\n\nstruct DayXX;\nimpl Solution for DayXX {\n fn parse_input>(pathname: P) -> Input {\n file_to_string(pathname)\n }\n\n fn part_1(input: &Input) -> Output {\n todo!()\n }\n\n fn part_2(input: &Input) -> Output {\n todo!()\n }\n}\n\nfn main() -> Result<()> {\n // DayXX::run("sample")\n DayXX::main()\n}\n\n// test_sample!(day_XX, DayXX, , );\n')),(0,i.kt)("h3",{id:"solution-1"},"Solution"),(0,i.kt)("p",null,"Not much to talk about, it is relatively easy to simulate."),(0,i.kt)("h2",{id:"day-10-cathode-ray-tube"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/10"},"Day 10: Cathode-Ray Tube")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Emulating basic arithmetic operations on a CPU and drawing on CRT based on the\nCPU's accumulator.")),(0,i.kt)("p",null,"In this day I have discovered an issue with my design of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Solution")," trait.\nAnd the issue is caused by different types of ",(0,i.kt)("inlineCode",{parentName:"p"},"Output")," for the part 1 and part 2."),(0,i.kt)("p",null,"Problem is relatively simple and consists of simulating a CPU, I have approached\nit in a following way:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"fn evaluate_instructions(instructions: &[Instruction], mut out: Output) -> Output {\n instructions\n .iter()\n .fold(State::new(), |state, instruction| {\n state.execute(instruction, &mut out)\n });\n\n out\n}\n")),(0,i.kt)("p",null,"We just take the instructions, we have some state of the CPU and we execute the\ninstructions one-by-one. Perfect usage of the ",(0,i.kt)("inlineCode",{parentName:"p"},"fold")," (or ",(0,i.kt)("inlineCode",{parentName:"p"},"reduce")," as you may know\nit from other languages)."),(0,i.kt)("p",null,"You can also see that we have an ",(0,i.kt)("inlineCode",{parentName:"p"},"Output")," type, so the question is how can we fix\nthat problem. And the answer is very simple and ",(0,i.kt)("em",{parentName:"p"},"functional"),". Rust allows you to\nhave an ",(0,i.kt)("inlineCode",{parentName:"p"},"enumeration")," that can ",(0,i.kt)("em",{parentName:"p"},"bear")," some other values apart from the type itself."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"We could've seen something like this with the ",(0,i.kt)("inlineCode",{parentName:"p"},"Result")," type that can be\ndefined as"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"enum Result {\n Ok(T),\n Err(E)\n}\n")),(0,i.kt)("h6",{parentName:"admonition",id:"what-does-that-mean-though"},"What does that mean though?"),(0,i.kt)("p",{parentName:"admonition"},"When we have an ",(0,i.kt)("inlineCode",{parentName:"p"},"Ok")," value, it has the result itself, and when we get an ",(0,i.kt)("inlineCode",{parentName:"p"},"Err"),"\nvalue, it has the error. This also allows us to handle ",(0,i.kt)("em",{parentName:"p"},"results")," in a rather\npretty way:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'match do_something(x) {\n Ok(y) => {\n println!("SUCCESS: {}", y);\n },\n Err(y) => {\n eprintln!("ERROR: {}", y);\n }\n}\n'))),(0,i.kt)("p",null,"My solution has a following outline:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"fn execute(&self, i: &Instruction, output: &mut Output) -> State {\n // execute the instruction\n\n // collect results if necessary\n match output {\n Output::Part1(x) => self.execute_part_1(y, x),\n Output::Part2(x) => self.execute_part_2(y, x),\n }\n\n // return the obtained state\n new_state\n}\n")),(0,i.kt)("p",null,"You might think that it's a perfectly reasonable thing to do. Yes, ",(0,i.kt)("strong",{parentName:"p"},"but")," notice\nthat the ",(0,i.kt)("inlineCode",{parentName:"p"},"match")," statement doesn't ",(0,i.kt)("em",{parentName:"p"},"collect")," the changes in any way and also we\npass ",(0,i.kt)("inlineCode",{parentName:"p"},"output")," by ",(0,i.kt)("inlineCode",{parentName:"p"},"&mut"),", so it is shared across each ",(0,i.kt)("em",{parentName:"p"},"iteration")," of the ",(0,i.kt)("inlineCode",{parentName:"p"},"fold"),"."),(0,i.kt)("p",null,"The dirty and ingenious thing is that ",(0,i.kt)("inlineCode",{parentName:"p"},"x"),"s are passed by ",(0,i.kt)("inlineCode",{parentName:"p"},"&mut")," too and therefore\nthey are directly modified by the helper functions. To sum it up and let it sit"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"We are ",(0,i.kt)("strong",{parentName:"p"},"collecting")," the result ",(0,i.kt)("strong",{parentName:"p"},"into")," an ",(0,i.kt)("strong",{parentName:"p"},"enumeration")," that is ",(0,i.kt)("strong",{parentName:"p"},"shared"),"\nacross ",(0,i.kt)("strong",{parentName:"p"},"all")," iterations of ",(0,i.kt)("inlineCode",{parentName:"p"},"fold"),".")),(0,i.kt)("h3",{id:"solution-2"},"Solution"),(0,i.kt)("p",null,"Similar to ",(0,i.kt)("em",{parentName:"p"},"Day 9"),", but there are some technical details that can get you."),(0,i.kt)("h2",{id:"day-11-monkey-in-the-middle"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/11"},"Day 11: Monkey in the Middle")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Simulation of monkeys throwing stuff around and measuring your stress levels\nwhile your stuff is being passed around.")),(0,i.kt)("p",null,"I think I decided to use regular expressions here for the first time, cause\nparsing the input was a pain."),(0,i.kt)("p",null,"Also I didn't expect to implement Euclidean algorithm in Rust\u2026"),(0,i.kt)("h3",{id:"solution-3"},"Solution"),(0,i.kt)("p",null,"Again, we're just running a simulation. Though I must admit it was very easy to\nmake a small technical mistakes that could affect the final results very late."),(0,i.kt)("h2",{id:"day-12-hill-climbing-algorithm"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/12"},"Day 12: Hill Climbing Algorithm")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Finding shortest path up the hill and also shortest path down to the ground while\nalso rolling down the hill\u2026")),(0,i.kt)("p",null,"As I have said in the ",(0,i.kt)("em",{parentName:"p"},"tl;dr"),", we are looking for the shortest path, but the start\nand goal differ for the part 1 and 2. So I have decided to refactor my solution\nto a BFS algorithm that takes necessary parameters via functions:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"fn bfs(\n graph: &[Vec], start: &Position, has_edge: F, is_target: G\n) -> Option\nwhere\n F: Fn(&[Vec], &Position, &Position) -> bool,\n G: Fn(&[Vec], &Position) -> bool\n")),(0,i.kt)("p",null,"We pass the initial vertex from the caller and everything else is left to the BFS\nalgorithm, based on the ",(0,i.kt)("inlineCode",{parentName:"p"},"has_edge")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"is_target")," functions."),(0,i.kt)("p",null,"This was easy! And that is not very usual in Rust once you want to pass around\nfunctions. \ud83d\udc40"),(0,i.kt)("h3",{id:"solution-4"},"Solution"),(0,i.kt)("p",null,"Looking for the shortest path\u2026 Must be Dijkstra, right? ",(0,i.kt)("strong",{parentName:"p"},"Nope!")," Half of the\nReddit got jebaited though. In all fairness, nothing stops you from implementing\nthe Dijkstra's algorithm for finding the shortest path, ",(0,i.kt)("strong",{parentName:"p"},"but")," if you know that\nall connected vertices are in a unit (actually ",(0,i.kt)("span",{parentName:"p",className:"math math-inline"},(0,i.kt)("span",{parentName:"span",className:"katex"},(0,i.kt)("span",{parentName:"span",className:"katex-mathml"},(0,i.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,i.kt)("semantics",{parentName:"math"},(0,i.kt)("mrow",{parentName:"semantics"},(0,i.kt)("mi",{parentName:"mrow"},"d"),(0,i.kt)("mo",{parentName:"mrow"},"="),(0,i.kt)("mn",{parentName:"mrow"},"1")),(0,i.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"d = 1")))),(0,i.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,i.kt)("span",{parentName:"span",className:"base"},(0,i.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,i.kt)("span",{parentName:"span",className:"mord mathnormal"},"d"),(0,i.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,i.kt)("span",{parentName:"span",className:"mrel"},"="),(0,i.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,i.kt)("span",{parentName:"span",className:"base"},(0,i.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,i.kt)("span",{parentName:"span",className:"mord"},"1"))))),") distance from each other,\nthen you know that running Dijkstra is equivalent to running BFS, only with worse\ntime complexity, because of the priority heap instead of the queue."),(0,i.kt)("h2",{id:"day-13-distress-signal"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/13"},"Day 13: Distress Signal")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Processing packets with structured data from the distress signal.")),(0,i.kt)("p",null,"You can implement a lot of traits if you want to. It is ",(0,i.kt)("em",{parentName:"p"},"imperative")," to implement\nordering on the packets. I had a typo, so I also proceeded to implement a ",(0,i.kt)("inlineCode",{parentName:"p"},"Display"),"\ntrait for debugging purposes:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'impl Display for Packet {\n fn fmt(&self, f: &mut std::fmt::Formatter<\'_>) -> std::fmt::Result {\n match self {\n Packet::Integer(x) => write!(f, "{x}"),\n Packet::List(lst) => write!(f, "[{}]", lst.iter().map(|p| format!("{p}")).join(",")),\n }\n }\n}\n')),(0,i.kt)("h3",{id:"solution-5"},"Solution"),(0,i.kt)("p",null,"A lot of technical details\u2026 Parsing is nasty too\u2026"),(0,i.kt)("h2",{id:"day-14-regolith-reservoir"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/14"},"Day 14: Regolith Reservoir")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Let's simulate falling sand grain-by-grain.")),(0,i.kt)("p",null,"Again, both parts are relatively similar with minimal changes, so it is a good\nidea to refactor it a bit. Similar approach to the ",(0,i.kt)("a",{parentName:"p",href:"#day-12-hill-climbing-algorithm"},"BFS above"),". Also this is the\nfirst day where I ran into efficiency issues and had to redo my solution to speed\nit up just a bit."),(0,i.kt)("h3",{id:"solution-6"},"Solution"),(0,i.kt)("p",null,"Tedious."),(0,i.kt)("h2",{id:"post-mortem"},"Post Mortem"),(0,i.kt)("h3",{id:"indexing"},"Indexing"),(0,i.kt)("p",null,"I was asked about the indexing after publishing the blog. And truly it is rather\ncomplicated topic, especially after releasing ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex")," trait. I couldn't\nleave it be, so I tried to implement the ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," trait."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"I have also mentioned that the ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex")," trait is ",(0,i.kt)("inlineCode",{parentName:"p"},"unsafe"),", but truth be told,\nonly ",(0,i.kt)("em",{parentName:"p"},"unsafe")," part are the 2 methods that are named ",(0,i.kt)("inlineCode",{parentName:"p"},"*unchecked*"),". Anyways, I will\nbe implementing the ",(0,i.kt)("inlineCode",{parentName:"p"},"Index*")," traits for now, rather than the ",(0,i.kt)("inlineCode",{parentName:"p"},"SliceIndex"),".")),(0,i.kt)("p",null,"It's relatively straightforward\u2026"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"impl Index> for [C]\nwhere\n I: Copy + TryInto,\n >::Error: Debug,\n C: Index,\n{\n type Output = C::Output;\n\n fn index(&self, index: Vector2D) -> &Self::Output {\n let (x, y): (usize, usize) =\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\n &self[y][x]\n }\n}\n\nimpl IndexMut> for [C]\nwhere\n I: Copy + TryInto,\n >::Error: Debug,\n C: IndexMut,\n{\n fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output {\n let (x, y): (usize, usize) =\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\n &mut self[y][x]\n }\n}\n")),(0,i.kt)("p",null,"We can see a lot of similarities to the implementation of ",(0,i.kt)("inlineCode",{parentName:"p"},"index")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"index_mut"),"\nfunctions. In the end, they are 1:1, just wrapped in the trait that provides a\nsyntax sugar for ",(0,i.kt)("inlineCode",{parentName:"p"},"container[idx]"),"."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"I have also switched from using the ",(0,i.kt)("inlineCode",{parentName:"p"},"TryFrom")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"TryInto")," trait, since it better\nmatches what we are using, the ",(0,i.kt)("inlineCode",{parentName:"p"},".try_into")," rather than ",(0,i.kt)("inlineCode",{parentName:"p"},"usize::try_from"),"."),(0,i.kt)("p",{parentName:"admonition"},"Also implementing ",(0,i.kt)("inlineCode",{parentName:"p"},"TryFrom")," automatically provides you with a ",(0,i.kt)("inlineCode",{parentName:"p"},"TryInto")," trait,\nsince it is relatively easy to implement. Just compare the following:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub trait TryFrom: Sized {\n type Error;\n\n fn try_from(value: T) -> Result;\n}\n\npub trait TryInto: Sized {\n type Error;\n\n fn try_into(self) -> Result;\n}\n"))),(0,i.kt)("p",null,"OK, so we have our trait implemented, we should be able to use ",(0,i.kt)("inlineCode",{parentName:"p"},"container[index]"),",\nright? Yes\u2026 but actually no \ud83d\ude26"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"error[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\n --\x3e src/bin/day08.rs:26:18\n |\n26 | if trees[pos] > tallest {\n | ^^^ slice indices are of type `usize` or ranges of `usize`\n |\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\n\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\n --\x3e src/bin/day08.rs:30:28\n |\n30 | max(tallest, trees[pos])\n | ^^^ slice indices are of type `usize` or ranges of `usize`\n |\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\n\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\n --\x3e src/bin/day08.rs:52:28\n |\n52 | let max_height = trees[position];\n | ^^^^^^^^ slice indices are of type `usize` or ranges of `usize`\n |\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\n")),(0,i.kt)("p",null,"Why? We have it implemented for the slices (",(0,i.kt)("inlineCode",{parentName:"p"},"[C]"),"), why doesn't it work? Well,\nthe fun part consists of the fact that in other place, where we were using it,\nwe were passing the ",(0,i.kt)("inlineCode",{parentName:"p"},"&[Vec]"),", but this is coming from a helper functions that\ntake ",(0,i.kt)("inlineCode",{parentName:"p"},"&Vec>")," instead. And\u2026 we don't implement ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," for\nthose. Just for the slices. \ud83e\udd2f ",(0,i.kt)("em",{parentName:"p"},"What are we going to do about it?")),(0,i.kt)("p",null,"We can either start copy-pasting or be smarter about it\u2026 I choose to be smarter,\nso let's implement a macro! The only difference across the implementations are\nthe types of the outer containers. Implementation doesn't differ ",(0,i.kt)("strong",{parentName:"p"},"at all"),"!"),(0,i.kt)("p",null,"Implementing the macro can be done in a following way:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"macro_rules! generate_indices {\n ($container:ty) => {\n impl Index> for $container\n where\n I: Copy + TryInto,\n >::Error: Debug,\n C: Index,\n {\n type Output = C::Output;\n\n fn index(&self, index: Vector2D) -> &Self::Output {\n let (x, y): (usize, usize) =\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\n &self[y][x]\n }\n }\n\n impl IndexMut> for $container\n where\n I: Copy + TryInto,\n >::Error: Debug,\n C: IndexMut,\n {\n fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output {\n let (x, y): (usize, usize) =\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\n &mut self[y][x]\n }\n }\n };\n}\n")),(0,i.kt)("p",null,"And now we can simply do"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"generate_indices!(VecDeque);\ngenerate_indices!([C]);\ngenerate_indices!(Vec);\n// generate_indices!([C; N], const N: usize);\n")),(0,i.kt)("p",null,"The last type (I took the inspiration from the implementations of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," and\n",(0,i.kt)("inlineCode",{parentName:"p"},"IndexMut")," traits) is a bit problematic, because of the ",(0,i.kt)("inlineCode",{parentName:"p"},"const N: usize")," part,\nwhich I haven't managed to be able to parse. And that's how I got rid of the error."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"If I were to use 2D-indexing over ",(0,i.kt)("inlineCode",{parentName:"p"},"[C; N]")," slices, I'd probably just go with the\ncopy-paste, cause the cost of this \u201cmonstrosity\u201d outweighs the benefits of no DRY.")),(0,i.kt)("h4",{id:"cause-of-the-problem"},"Cause of the problem"),(0,i.kt)("p",null,"This issue is relatively funny. If you don't use any type aliases, just the raw\ntypes, you'll get suggested certain changes by the ",(0,i.kt)("em",{parentName:"p"},"clippy"),". For example if you\nconsider the following piece of code"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'fn get_sum(nums: &Vec) -> i32 {\n nums.iter().sum()\n}\n\nfn main() {\n let nums = vec![1, 2, 3];\n println!("Sum: {}", get_sum(&nums));\n}\n')),(0,i.kt)("p",null,"and you run ",(0,i.kt)("em",{parentName:"p"},"clippy")," on it, you will get"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Checking playground v0.0.1 (/playground)\nwarning: writing `&Vec` instead of `&[_]` involves a new object where a slice will do\n --\x3e src/main.rs:1:18\n |\n1 | fn get_sum(nums: &Vec) -> i32 {\n | ^^^^^^^^^ help: change this to: `&[i32]`\n |\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg\n = note: `#[warn(clippy::ptr_arg)]` on by default\n\nwarning: `playground` (bin "playground") generated 1 warning\n Finished dev [unoptimized + debuginfo] target(s) in 0.61s\n')),(0,i.kt)("p",null,"However, if you introduce a type alias, such as"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"type Numbers = Vec;\n")),(0,i.kt)("p",null,"Then ",(0,i.kt)("em",{parentName:"p"},"clippy")," won't say anything, cause there is literally nothing to suggest.\nHowever the outcome is not the same\u2026"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3da4b779.a33bbff3.js b/assets/js/3da4b779.f7a9f496.js similarity index 99% rename from assets/js/3da4b779.a33bbff3.js rename to assets/js/3da4b779.f7a9f496.js index 526c2be..c7ca349 100644 --- a/assets/js/3da4b779.a33bbff3.js +++ b/assets/js/3da4b779.f7a9f496.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2177],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>c});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=p(n),h=i,c=m["".concat(l,".").concat(h)]||m[h]||d[h]||o;return n?a.createElement(c,r(r({ref:t},u),{},{components:n})):a.createElement(c,r({ref:t},u))}));function c(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:i,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const o={title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14",slug:"aoc-2022/4th-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},r=void 0,s={permalink:"/blog/aoc-2022/4th-week",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/04-week-4.md",source:"@site/blog/aoc-2022/04-week-4.md",title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14:00.000Z",formattedDate:"July 7, 2023",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:15.175,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14",slug:"aoc-2022/4th-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"How can Copr help with broken dependencies",permalink:"/blog/2023/08/02/copr"},nextItem:{title:"3rd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/3rd-week"}},l={authorsImageUrls:[void 0]},p=[{value:"Day 22: Monkey Map",id:"day-22-monkey-map",level:2},{value:"Solution",id:"solution",level:3},{value:"Column iterator",id:"column-iterator",level:4},{value:"Walking around the map",id:"walking-around-the-map",level:4},{value:"Problems",id:"problems",level:4},{value:"Clippy",id:"clippy",level:4},{value:"Day 23: Unstable Diffusion",id:"day-23-unstable-diffusion",level:2},{value:"Solution",id:"solution-1",level:3},{value:"Day 24: Blizzard Basin",id:"day-24-blizzard-basin",level:2},{value:"Solution",id:"solution-2",level:3},{value:"Breakdown",id:"breakdown",level:4},{value:"Evaluating the blizzards",id:"evaluating-the-blizzards",level:4},{value:"Shortest-path algorithm",id:"shortest-path-algorithm",level:4},{value:"Min-heap",id:"min-heap",level:4},{value:"Day 25: Full of Hot Air",id:"day-25-full-of-hot-air",level:2},{value:"Solution",id:"solution-3",level:3},{value:"Converting from &str",id:"converting-from-str",level:4},{value:"Converting to String",id:"converting-to-string",level:4},{value:"Adjusting the code",id:"adjusting-the-code",level:4},{value:"Summary",id:"summary",level:2},{value:"Advent of Code",id:"advent-of-code",level:3},{value:"with Rust",id:"with-rust",level:3}],u={toc:p},m="wrapper";function d(e){let{components:t,...o}=e;return(0,i.kt)(m,(0,a.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Let's go through the fourth week of ",(0,i.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,i.kt)("em",{parentName:"a"},"Advent of Code"))," in Rust."),(0,i.kt)("h2",{id:"day-22-monkey-map"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/22"},"Day 22: Monkey Map")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Simulating a movement on a 2D map with given instructions. Map becomes a cube in\nthe 2nd part\u2026")),(0,i.kt)("admonition",{title:"Rant",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"This was the most obnoxious problem of this year\u2026 and a lot of Rust issues have\nbeen hit.")),(0,i.kt)("h3",{id:"solution"},"Solution"),(0,i.kt)("p",null,"It seems like a very simple problem to solve, but with very obnoxious changes in\nthe 2nd part and also it's relatively hard to decompose \xbbproperly\xab."),(0,i.kt)("h4",{id:"column-iterator"},"Column iterator"),(0,i.kt)("p",null,"In the first part of the problem it was needed to know the boundaries of each\nrow and column, since I stored them in ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec>")," and padded with spaces\nto ensure I have a rectangular 2D \u201carray\u201d. However when you wanted to go through\neach row and column to determine the boundaries, it was very easy to do for the\nrows (cause each row is a ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec")," element), but not for the columns, since they\nspan multiple rows."),(0,i.kt)("p",null,"For this use case I have implemented my own ",(0,i.kt)("em",{parentName:"p"},"column iterator"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub struct ColumnIterator<'a, T> {\n map: &'a [Vec],\n column: usize,\n\n i: usize,\n}\n\nimpl<'a, T> ColumnIterator<'a, T> {\n pub fn new(map: &'a [Vec], column: usize) -> ColumnIterator<'a, T> {\n Self { map, column, i: 0 }\n }\n}\n\nimpl<'a, T> Iterator for ColumnIterator<'a, T> {\n type Item = &'a T;\n\n fn next(&mut self) -> Option {\n if self.i >= self.map.len() {\n return None;\n }\n\n self.i += 1;\n Some(&self.map[self.i - 1][self.column])\n }\n}\n")),(0,i.kt)("p",null,"Given this piece of an iterator, it is very easy to factor out the common\nfunctionality between the rows and columns into:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let mut find_boundaries = |constructor: fn(usize) -> Orientation,\n iterator: &mut dyn Iterator,\n upper_bound,\n i| {\n let mut first_non_empty = iterator.enumerate().skip_while(|&(_, &c)| c == ' ');\n let start = first_non_empty.next().unwrap().0 as isize;\n\n let mut last_non_empty = first_non_empty.skip_while(|&(_, &c)| c != ' ');\n let end = last_non_empty.next().unwrap_or((upper_bound, &'_')).0 as isize;\n\n boundaries.insert(constructor(i), start..end);\n};\n")),(0,i.kt)("p",null,"And then use it as such:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"// construct all horizontal boundaries\n(0..map.len()).for_each(|row| {\n find_boundaries(\n Orientation::horizontal,\n &mut map[row].iter(),\n map[row].len(),\n row,\n );\n});\n\n// construct all vertical boundaries\n(0..map[0].len()).for_each(|col| {\n find_boundaries(\n Orientation::vertical,\n &mut ColumnIterator::new(&map, col),\n map.len(),\n col,\n );\n});\n")),(0,i.kt)("h4",{id:"walking-around-the-map"},"Walking around the map"),(0,i.kt)("p",null,"Once the 2nd part got introduced, you start to think about a way how not to\ncopy-paste a lot of stuff (I haven't avoided it anyways\u2026). In this problem, I've\nchosen to introduce a trait (i.e. ",(0,i.kt)("em",{parentName:"p"},"interface"),") for 2D and 3D walker."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"trait Wrap: Clone {\n type State;\n\n // simulation\n fn is_blocked(&self) -> bool;\n fn step(&mut self, steps: isize);\n fn turn_left(&mut self);\n fn turn_right(&mut self);\n\n // movement\n fn next(&self) -> (Self::State, Direction);\n\n // final answer\n fn answer(&self) -> Output;\n}\n")),(0,i.kt)("p",null,"Each walker maintains its own state and also provides the functions that are\nused during the simulation. The \u201cpromised\u201d methods are separated into:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"simulation"),"-related: that are used during the simulation from the ",(0,i.kt)("inlineCode",{parentName:"li"},".fold()")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"movement"),"-related: just a one method that holds most of the logic differences\nbetween 2D and 3D"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"final answer"),": which extracts the ",(0,i.kt)("em",{parentName:"li"},"proof of solution")," from the\nimplementation-specific walker")),(0,i.kt)("p",null,"Both 2D and 3D versions borrow the original input and therefore you must\nannotate the lifetime of it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"struct Wrap2D<'a> {\n input: &'a Input,\n position: Position,\n direction: Direction,\n}\nimpl<'a> Wrap2D<'a> {\n fn new(input: &'a Input) -> Wrap2D<'a> {\n// \u2026\n")),(0,i.kt)("h4",{id:"problems"},"Problems"),(0,i.kt)("p",null,"I have used a lot of closures for this problem and once I introduced a parameter\nthat was of unknown type (apart from the fact it implements a specific trait), I\ngot suggested a \u201cfix\u201d for the compilation error that resulted in something that\nwas not possible to parse, cause it, more than likely, violated the grammar."),(0,i.kt)("p",null,"In a similar fashion, I have been suggested changes that led to a code that\ndidn't make sense by just looking at it (there was no need to try the changes),\nfor example one suggested change in the closure parameter caused disapperance of\nthe parameter name. \ud83d\ude04"),(0,i.kt)("h4",{id:"clippy"},"Clippy"),(0,i.kt)("p",null,"I have to admit that Clippy was rather helpful here, I'll include two examples\nof rather smart suggestions."),(0,i.kt)("p",null,"When writing the parsing for this problem, the first thing I have spotted on the\n",(0,i.kt)("inlineCode",{parentName:"p"},"char")," was the ",(0,i.kt)("inlineCode",{parentName:"p"},".is_digit()")," function that takes a radix as a parameter. Clippy\nnoticed that I use ",(0,i.kt)("inlineCode",{parentName:"p"},"radix = 10")," and suggested switching to ",(0,i.kt)("inlineCode",{parentName:"p"},".is_ascii_digit()"),"\nthat does exactly the same thing:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"- .take_while(|c| c.is_digit(10))\n+ .take_while(|c| c.is_ascii_digit())\n")),(0,i.kt)("p",null,"Another useful suggestion appeared when working with the iterators and I wanted\nto get the ",(0,i.kt)("span",{parentName:"p",className:"math math-inline"},(0,i.kt)("span",{parentName:"span",className:"katex"},(0,i.kt)("span",{parentName:"span",className:"katex-mathml"},(0,i.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,i.kt)("semantics",{parentName:"math"},(0,i.kt)("mrow",{parentName:"semantics"},(0,i.kt)("mi",{parentName:"mrow"},"n")),(0,i.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,i.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,i.kt)("span",{parentName:"span",className:"base"},(0,i.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,i.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),"-th element from it. You know the ",(0,i.kt)("inlineCode",{parentName:"p"},".skip()"),", you know the\n",(0,i.kt)("inlineCode",{parentName:"p"},".next()"),", just \u201cslap\u201d them together and we're done for \ud83d\ude01 Well, I got\nsuggested to use ",(0,i.kt)("inlineCode",{parentName:"p"},".nth()")," that does exactly the combination of the two mentioned\nmethods on iterators:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"- match it.clone().skip(skip).next().unwrap() {\n+ match it.clone().nth(skip).unwrap() {\n")),(0,i.kt)("h2",{id:"day-23-unstable-diffusion"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/23"},"Day 23: Unstable Diffusion")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Simulating movement of elves around with a set of specific rules.")),(0,i.kt)("h3",{id:"solution-1"},"Solution"),(0,i.kt)("p",null,"There's not much to mention since it's just a cellular automaton simulation\n(even though the AoC rules for cellular automatons usually get out of hand\n\ud83d\ude09)."),(0,i.kt)("p",null,"Although I had a need to determine boundaries of the elves' positions and ended\nup with a nasty DRY violation. Knowing that you you're looking for maximum and\nminimum that are, of course, exactly the same except for initial values and\ncomparators, it looks like a rather simple fix, but typing in Rust is something\nelse, right? In the end I settled for a function that computes both boundaries\nwithout any duplication while using a closure:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"fn get_bounds(positions: &Input) -> (Vector2D, Vector2D) {\n let f = |init, cmp: &dyn Fn(isize, isize) -> isize| {\n positions\n .iter()\n .fold(Vector2D::new(init, init), |acc, elf| {\n Vector2D::new(cmp(acc.x(), elf.x()), cmp(acc.y(), elf.y()))\n })\n };\n\n (f(isize::MAX, &min::), f(isize::MIN, &max::))\n}\n")),(0,i.kt)("p",null,"This function returns a pair of 2D vectors that represent opposite points of the\nbounding rectangle of all elves."),(0,i.kt)("p",null,"You might ask why would we need a closure and the answer is that ",(0,i.kt)("inlineCode",{parentName:"p"},"positions"),"\ncannot be captured from within the nested function, only via closure. One more\nfun fact on top of that is the type of the comparator"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"&dyn Fn(isize, isize) -> isize\n")),(0,i.kt)("p",null,"Once we remove the ",(0,i.kt)("inlineCode",{parentName:"p"},"dyn")," keyword, compiler yells at us and also includes a way\nhow to get a more thorough explanation of the error by running"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"$ rustc --explain E0782\n")),(0,i.kt)("p",null,"which shows us"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"Trait objects must include the `dyn` keyword.\n\nErroneous code example:\n\n```\ntrait Foo {}\nfn test(arg: Box) {} // error!\n```\n\nTrait objects are a way to call methods on types that are not known until\nruntime but conform to some trait.\n\nTrait objects should be formed with `Box`, but in the code above\n`dyn` is left off.\n\nThis makes it harder to see that `arg` is a trait object and not a\nsimply a heap allocated type called `Foo`.\n\nTo fix this issue, add `dyn` before the trait name.\n\n```\ntrait Foo {}\nfn test(arg: Box) {} // ok!\n```\n\nThis used to be allowed before edition 2021, but is now an error.\n")),(0,i.kt)("admonition",{title:"Rant",type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"Not all of the explanations are helpful though, in some cases they might be even\nmore confusing than helpful, since they address ",(0,i.kt)("em",{parentName:"p"},"very simple")," use cases."),(0,i.kt)("p",{parentName:"admonition"},"As you can see, even in this case there are two sides to the explanations:"),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},"it explains why you need to use ",(0,i.kt)("inlineCode",{parentName:"li"},"dyn"),", but"),(0,i.kt)("li",{parentName:"ul"},"it still mentions that trait objects need to be heap-allocated via ",(0,i.kt)("inlineCode",{parentName:"li"},"Box"),"\nthat, as you can see in my snippet, ",(0,i.kt)("strong",{parentName:"li"},"does not")," apply here \ud83d\ude04 IMO it's\ncaused by the fact that we are borrowing it and therefore we don't need to\ncare about the size or whereabouts of it."))),(0,i.kt)("admonition",{title:"C++ parallel",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"If you dive into the explanation above, you can notice that the ",(0,i.kt)("inlineCode",{parentName:"p"},"Box"),"\npattern is very helpful for using types that are not known during compile-time.\nYou would use a very similar approach in C++ when parsing some data structure\nfrom input (let's say JSON for example)."),(0,i.kt)("p",{parentName:"admonition"},"On the other hand, in this case, it doesn't really make much sense, cause you\ncan clearly see that the types ",(0,i.kt)("strong",{parentName:"p"},"are known")," during the compile-time, which in\nC++ could be easily resolved by templating the helper function.")),(0,i.kt)("h2",{id:"day-24-blizzard-basin"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/24"},"Day 24: Blizzard Basin")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Navigating your way through a basin with series of blizzards that move around\nyou as you move.")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"It's second to last day and I went \u201c",(0,i.kt)("em",{parentName:"p"},"bonkers"),"\u201d on the Rust \ud83d\ude04 Proceed to\nread ",(0,i.kt)("em",{parentName:"p"},"Solution")," part on your own risk.")),(0,i.kt)("h3",{id:"solution-2"},"Solution"),(0,i.kt)("p",null,"You are given a map with blizzards all over the place and you're supposed to\nfind the minimum time it requires you to walk through the basin without getting\nin any of the blizzards."),(0,i.kt)("h4",{id:"breakdown"},"Breakdown"),(0,i.kt)("p",null,"Relatively simple, yet a bit annoying, approach can be taken. It's technically\na shortest-path algorithm implementation with some relaxation restrictions and\nbeing able to stay on one position for some time, so each ",(0,i.kt)("em",{parentName:"p"},"vertex")," of the graph\nis determined by the position on the map and the ",(0,i.kt)("em",{parentName:"p"},"timestamp"),". I have chosen to\nuse ",(0,i.kt)("inlineCode",{parentName:"p"},"Vector3D"),", since ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," attributes can be used for the position\nand, well, let's use ",(0,i.kt)("inlineCode",{parentName:"p"},"z")," for a timestamp, cause why not, right? \ud83d\ude09"),(0,i.kt)("h4",{id:"evaluating-the-blizzards"},"Evaluating the blizzards"),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"I think that this is the most perverted abuse of the traits in the whole 4 weeks\nof AoC in Rust\u2026")),(0,i.kt)("p",null,"The blizzards move along their respective directions in time and loop around in\ntheir respective row/column. Each vertex holds position ",(0,i.kt)("strong",{parentName:"p"},"and")," time, so we can\n",(0,i.kt)("em",{parentName:"p"},"just")," index the basin with the vertex itself, right? Yes, we can \ud83d\ude08"),(0,i.kt)("admonition",{title:"Fun fact",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"While writing this part, I've recognized unnecessary verbosity in the code and\ncleaned it up a bit. The changed version is shown here and the original was just\nmore verbose.")),(0,i.kt)("p",null,"I'll skip the boring parts of checking bounds and entry/exit of the basin \ud83d\ude09\nWe can easily calculate positions of the blizzards using a modular arithmetics:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"impl Index for Basin {\n type Output = char;\n\n fn index(&self, index: Position) -> &Self::Output {\n // \u2039skipped boring parts\u203a\n\n // We need to account for the loops of the blizzards\n let width = self.cols - 2;\n let height = self.rows - 2;\n\n let blizzard_origin = |size, d, t, i| ((i - 1 + size + d * (t % size)) % size + 1) as usize;\n [\n (\n index.y() as usize,\n blizzard_origin(width, -1, index.z(), index.x()),\n '>',\n ),\n (\n index.y() as usize,\n blizzard_origin(width, 1, index.z(), index.x()),\n '<',\n ),\n (\n blizzard_origin(height, -1, index.z(), index.y()),\n index.x() as usize,\n 'v',\n ),\n (\n blizzard_origin(height, 1, index.z(), index.y()),\n index.x() as usize,\n '^',\n ),\n ]\n .iter()\n .find_map(|&(y, x, direction)| {\n if self.map[y][x] == direction {\n Some(&self.map[y][x])\n } else {\n None\n }\n })\n .unwrap_or(&'.')\n }\n}\n")),(0,i.kt)("p",null,"As you can see, there is an expression for calculating the original position and\nit's used multiple times, so why not take it out to a lambda, right? \ud83d\ude09"),(0,i.kt)("p",null,"I couldn't get the ",(0,i.kt)("inlineCode",{parentName:"p"},"rustfmt")," to format the ",(0,i.kt)("inlineCode",{parentName:"p"},"for"),"-loop nicely, so I've just\ndecided to go with iterating over an elements of a slice. I have used, once\nagain, a combination of two functions (",(0,i.kt)("inlineCode",{parentName:"p"},"find_map")," in this case) to do 2 things\nat once and at the end, if we haven't found any blizzard, we just return the\nempty space."),(0,i.kt)("p",null,"I think it's a very ",(0,i.kt)("em",{parentName:"p"},"nice")," (and naughty) way how to use the ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," trait, don't\nyou think?"),(0,i.kt)("h4",{id:"shortest-path-algorithm"},"Shortest-path algorithm"),(0,i.kt)("p",null,"For the shortest path you can choose and adjust any of the common shortest-path\nalgorithms, in my case, I have decided to use ",(0,i.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/A*_search_algorithm"},(0,i.kt)("em",{parentName:"a"},"A","*"))," instead of Dijkstra's\nalgorithm, since it better reflects the ",(0,i.kt)("em",{parentName:"p"},"cost")," function."),(0,i.kt)("admonition",{title:"Comparison of costs",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"With the Dijkstra's algorithm I would proceed with the ",(0,i.kt)("inlineCode",{parentName:"p"},"time")," attribute used as\na priority for the queue."),(0,i.kt)("p",{parentName:"admonition"},"Whereas with the ",(0,i.kt)("em",{parentName:"p"},"A","*"),", I have chosen to use both time and Manhattan distance\nthat promotes vertices closer to the exit ",(0,i.kt)("strong",{parentName:"p"},"and")," with a minimum time taken.")),(0,i.kt)("p",null,"Cost function is, of course, a closure \ud83d\ude09"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let cost = |p: Position| p.z() as usize + exit.y().abs_diff(p.y()) + exit.x().abs_diff(p.x());\n")),(0,i.kt)("p",null,"And also for checking the possible moves from the current vertex, I have\nimplemented, yet another, closure that yields an iterator with the next moves:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let next_positions = |p| {\n [(0, 0, 1), (0, -1, 1), (0, 1, 1), (-1, 0, 1), (1, 0, 1)]\n .iter()\n .filter_map(move |&(x, y, t)| {\n let next_p = p + Vector3D::new(x, y, t);\n\n if basin[next_p] == '.' {\n Some(next_p)\n } else {\n None\n }\n })\n};\n")),(0,i.kt)("h4",{id:"min-heap"},"Min-heap"),(0,i.kt)("p",null,"In this case I had a need to use the priority queue taking the elements with the\nlowest cost as the prioritized ones. Rust only offers you the ",(0,i.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html"},(0,i.kt)("inlineCode",{parentName:"a"},"BinaryHeap"))," and\nthat is a max-heap. One of the ways how to achieve a min-heap is to put the\nelements in wrapped in a ",(0,i.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/cmp/struct.Reverse.html"},(0,i.kt)("inlineCode",{parentName:"a"},"Reverse"))," (as is even showed in the linked ",(0,i.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#min-heap"},"docs of\nthe ",(0,i.kt)("inlineCode",{parentName:"a"},"BinaryHeap")),"). However the wrapping affects the type of the heap and also\npopping the most prioritized elements yields values wrapped in the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reverse"),"."),(0,i.kt)("p",null,"For this purpose I have just taken the max-heap and wrapped it as a whole in a\nseparate structure providing just the desired methods:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"use std::cmp::{Ord, Reverse};\nuse std::collections::BinaryHeap;\n\npub struct MinHeap {\n heap: BinaryHeap>,\n}\n\nimpl MinHeap {\n pub fn new() -> MinHeap {\n MinHeap {\n heap: BinaryHeap::new(),\n }\n }\n\n pub fn push(&mut self, item: T) {\n self.heap.push(Reverse(item))\n }\n\n pub fn pop(&mut self) -> Option {\n self.heap.pop().map(|Reverse(x)| x)\n }\n}\n\nimpl Default for MinHeap {\n fn default() -> Self {\n Self::new()\n }\n}\n")),(0,i.kt)("p",null,"Rest is just the algorithm implementation which is not that interesting."),(0,i.kt)("h2",{id:"day-25-full-of-hot-air"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/25"},"Day 25: Full of Hot Air")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Playing around with a numbers in a ",(0,i.kt)("em",{parentName:"p"},"special")," base.")),(0,i.kt)("p",null,"Getting flashbacks to the ",(0,i.kt)("em",{parentName:"p"},"IB111 Foundations of Programming"),"\u2026 Very nice \u201cproblem\u201d\nwith a rather easy solution, as the last day always seems to be."),(0,i.kt)("h3",{id:"solution-3"},"Solution"),(0,i.kt)("p",null,"Implementing 2 functions, converting from the ",(0,i.kt)("em",{parentName:"p"},"SNAFU base")," and back to the ",(0,i.kt)("em",{parentName:"p"},"SNAFU"),"\n",(0,i.kt)("em",{parentName:"p"},"base")," representation. Let's do a bit more though! I have implemented two functions:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"from_snafu")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"to_snafu"))),(0,i.kt)("p",null,"Now it is apparent that all I do is number to string and string to number. Hmm\u2026\nthat sounds familiar, doesn't it? Let's introduce a structure for the SNAFU numbers\nand implement the traits that we need."),(0,i.kt)("p",null,"Let's start with a structure:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct SNAFU {\n value: i64,\n}\n")),(0,i.kt)("h4",{id:"converting-from-str"},"Converting from ",(0,i.kt)("inlineCode",{parentName:"h4"},"&str")),(0,i.kt)("p",null,"We will start by implementing the ",(0,i.kt)("inlineCode",{parentName:"p"},"FromStr")," trait that will help us parse our input.\nThis is rather simple, I can just take the ",(0,i.kt)("inlineCode",{parentName:"p"},"from_snafu")," function, copy-paste it\ninto the ",(0,i.kt)("inlineCode",{parentName:"p"},"from_str")," method and the number I get will be wrapped in ",(0,i.kt)("inlineCode",{parentName:"p"},"Result")," and\n",(0,i.kt)("inlineCode",{parentName:"p"},"SNAFU")," structure."),(0,i.kt)("h4",{id:"converting-to-string"},"Converting to ",(0,i.kt)("inlineCode",{parentName:"h4"},"String")),(0,i.kt)("p",null,"This is more fun. In some cases you need to implement only one trait and others\nare automatically implemented using that one trait. In our case, if you look in\nthe documentation, you can see that ",(0,i.kt)("inlineCode",{parentName:"p"},"ToString")," trait is automatically implemented\nfor any type that implements ",(0,i.kt)("inlineCode",{parentName:"p"},"Display")," trait."),(0,i.kt)("p",null,"Let's implement the ",(0,i.kt)("inlineCode",{parentName:"p"},"Display")," trait then. We should be able to use the ",(0,i.kt)("inlineCode",{parentName:"p"},"to_snafu"),"\nfunction and just take the ",(0,i.kt)("inlineCode",{parentName:"p"},"self.value")," from the ",(0,i.kt)("inlineCode",{parentName:"p"},"SNAFU")," structure."),(0,i.kt)("p",null,"And for the convenience of tests, we can also implement a rather simple ",(0,i.kt)("inlineCode",{parentName:"p"},"From"),"\ntrait for the ",(0,i.kt)("inlineCode",{parentName:"p"},"SNAFU"),"."),(0,i.kt)("h4",{id:"adjusting-the-code"},"Adjusting the code"),(0,i.kt)("p",null,"After those changes we need to adjust the code and tests."),(0,i.kt)("p",null,"Parsing of the input is very easy, before we have used the lines, now we parse\neverything:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"}," fn parse_input>(pathname: P) -> Input {\n- file_to_lines(pathname)\n+ file_to_structs(pathname)\n }\n")),(0,i.kt)("p",null,"Part 1 needs to be adjusted a bit too:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"}," fn part_1(input: &Input) -> Output {\n- to_snafu(input.iter().map(|s| from_snafu(s)).sum())\n+ SNAFU::from(input.iter().map(|s| s.value).sum::()).to_string()\n }\n")),(0,i.kt)("p",null,"You can also see that it simplifies the meaning a bit and it is more explicit than\nthe previous versions."),(0,i.kt)("p",null,"And for the tests:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"}," #[test]\n fn test_from() {\n- for (n, s) in EXAMPLES.iter() {\n- assert_eq!(from_snafu(s), *n);\n+ for (&n, s) in EXAMPLES.iter() {\n+ assert_eq!(s.parse::().unwrap().value, n);\n }\n }\n \n #[test]\n fn test_to() {\n- for (n, s) in EXAMPLES.iter() {\n- assert_eq!(to_snafu(*n), s.to_string());\n+ for (&n, s) in EXAMPLES.iter() {\n+ assert_eq!(SNAFU::from(n).to_string(), s.to_string());\n }\n")),(0,i.kt)("h2",{id:"summary"},"Summary"),(0,i.kt)("p",null,"Let's wrap the whole thing up! Keeping in mind both AoC and the Rust\u2026"),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Finished advent calendar :smile:",src:n(3321).Z,width:"2417",height:"1984"})),(0,i.kt)("h3",{id:"advent-of-code"},"Advent of Code"),(0,i.kt)("p",null,"This year was quite fun, even though most of the solutions and posts came in\nlater on (",(0,i.kt)("em",{parentName:"p"},"cough")," in '23 ",(0,i.kt)("em",{parentName:"p"},"cough"),"). Day 22 was the most obnoxious one\u2026 And also\nit feels like I used priority queues and tree data structures ",(0,i.kt)("strong",{parentName:"p"},"a lot")," \ud83d\udc40"),(0,i.kt)("h3",{id:"with-rust"},"with Rust"),(0,i.kt)("p",null,"I must admit that a lot of compiler warnings and errors were very useful. Even\nthough I still found some instances where they didn't help at all or cause even\nworse issues than I had. Compilation times have been addressed with the caching."),(0,i.kt)("p",null,"Building my first tree data structure in Rust has been a very \u201cinteresting\u201d\njourney. Being able to write a more generic BFS algorithm that allows you to not\nduplicate code while still mantaining the desired functionality contributes to\na very readable code."),(0,i.kt)("p",null,"I am definitely much more aware of the basic things that bloated Python is\nmissing, yet Rust has them\u2026"),(0,i.kt)("p",null,"Using explicit types and writing down placeholder functions with ",(0,i.kt)("inlineCode",{parentName:"p"},"todo!()"),"\nmacros is very pleasant, since it allows you to easily navigate the type system\nduring the development when you don't even need to be sure how are you going to\nput the smaller pieces together."),(0,i.kt)("p",null,"I have used a plethora of traits and also implemented some of them to either be\nidiomatic, or exploit the syntactic sugar they offer. Deriving the default trait\nimplementation is also very helpful in a lot of cases, e.g. debugging output,\ncopying, equality comparison, etc."),(0,i.kt)("p",null,"I confess to touching more \u201ccursed\u201d parts of the Rust, such as macros to\ndeclutter the copy-paste for tests or writing my own structures that need to\ncarry a lifetime for their own fields."),(0,i.kt)("p",null,"tl;dr Relatively pleasant language until you hit brick wall \ud83d\ude09"),(0,i.kt)("hr",null),(0,i.kt)("p",null,"See you next year! Maybe in Rust, maybe not \ud83d\ude43"))}d.isMDXComponent=!0},3321:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/calendar-f891b624f3e0efb34bba582100a7d8df.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2177],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>c});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=p(n),h=i,c=m["".concat(l,".").concat(h)]||m[h]||d[h]||o;return n?a.createElement(c,r(r({ref:t},u),{},{components:n})):a.createElement(c,r({ref:t},u))}));function c(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:i,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var a=n(7462),i=(n(7294),n(3905));const o={title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14",slug:"aoc-2022/4th-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},r=void 0,s={permalink:"/blog/aoc-2022/4th-week",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/04-week-4.md",source:"@site/blog/aoc-2022/04-week-4.md",title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14:00.000Z",formattedDate:"July 7, 2023",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:15.175,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14",slug:"aoc-2022/4th-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"How can Copr help with broken dependencies",permalink:"/blog/2023/08/02/copr"},nextItem:{title:"3rd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/3rd-week"}},l={authorsImageUrls:[void 0]},p=[{value:"Day 22: Monkey Map",id:"day-22-monkey-map",level:2},{value:"Solution",id:"solution",level:3},{value:"Column iterator",id:"column-iterator",level:4},{value:"Walking around the map",id:"walking-around-the-map",level:4},{value:"Problems",id:"problems",level:4},{value:"Clippy",id:"clippy",level:4},{value:"Day 23: Unstable Diffusion",id:"day-23-unstable-diffusion",level:2},{value:"Solution",id:"solution-1",level:3},{value:"Day 24: Blizzard Basin",id:"day-24-blizzard-basin",level:2},{value:"Solution",id:"solution-2",level:3},{value:"Breakdown",id:"breakdown",level:4},{value:"Evaluating the blizzards",id:"evaluating-the-blizzards",level:4},{value:"Shortest-path algorithm",id:"shortest-path-algorithm",level:4},{value:"Min-heap",id:"min-heap",level:4},{value:"Day 25: Full of Hot Air",id:"day-25-full-of-hot-air",level:2},{value:"Solution",id:"solution-3",level:3},{value:"Converting from &str",id:"converting-from-str",level:4},{value:"Converting to String",id:"converting-to-string",level:4},{value:"Adjusting the code",id:"adjusting-the-code",level:4},{value:"Summary",id:"summary",level:2},{value:"Advent of Code",id:"advent-of-code",level:3},{value:"with Rust",id:"with-rust",level:3}],u={toc:p},m="wrapper";function d(e){let{components:t,...o}=e;return(0,i.kt)(m,(0,a.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Let's go through the fourth week of ",(0,i.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,i.kt)("em",{parentName:"a"},"Advent of Code"))," in Rust."),(0,i.kt)("h2",{id:"day-22-monkey-map"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/22"},"Day 22: Monkey Map")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Simulating a movement on a 2D map with given instructions. Map becomes a cube in\nthe 2nd part\u2026")),(0,i.kt)("admonition",{title:"Rant",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"This was the most obnoxious problem of this year\u2026 and a lot of Rust issues have\nbeen hit.")),(0,i.kt)("h3",{id:"solution"},"Solution"),(0,i.kt)("p",null,"It seems like a very simple problem to solve, but with very obnoxious changes in\nthe 2nd part and also it's relatively hard to decompose \xbbproperly\xab."),(0,i.kt)("h4",{id:"column-iterator"},"Column iterator"),(0,i.kt)("p",null,"In the first part of the problem it was needed to know the boundaries of each\nrow and column, since I stored them in ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec>")," and padded with spaces\nto ensure I have a rectangular 2D \u201carray\u201d. However when you wanted to go through\neach row and column to determine the boundaries, it was very easy to do for the\nrows (cause each row is a ",(0,i.kt)("inlineCode",{parentName:"p"},"Vec")," element), but not for the columns, since they\nspan multiple rows."),(0,i.kt)("p",null,"For this use case I have implemented my own ",(0,i.kt)("em",{parentName:"p"},"column iterator"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"pub struct ColumnIterator<'a, T> {\n map: &'a [Vec],\n column: usize,\n\n i: usize,\n}\n\nimpl<'a, T> ColumnIterator<'a, T> {\n pub fn new(map: &'a [Vec], column: usize) -> ColumnIterator<'a, T> {\n Self { map, column, i: 0 }\n }\n}\n\nimpl<'a, T> Iterator for ColumnIterator<'a, T> {\n type Item = &'a T;\n\n fn next(&mut self) -> Option {\n if self.i >= self.map.len() {\n return None;\n }\n\n self.i += 1;\n Some(&self.map[self.i - 1][self.column])\n }\n}\n")),(0,i.kt)("p",null,"Given this piece of an iterator, it is very easy to factor out the common\nfunctionality between the rows and columns into:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let mut find_boundaries = |constructor: fn(usize) -> Orientation,\n iterator: &mut dyn Iterator,\n upper_bound,\n i| {\n let mut first_non_empty = iterator.enumerate().skip_while(|&(_, &c)| c == ' ');\n let start = first_non_empty.next().unwrap().0 as isize;\n\n let mut last_non_empty = first_non_empty.skip_while(|&(_, &c)| c != ' ');\n let end = last_non_empty.next().unwrap_or((upper_bound, &'_')).0 as isize;\n\n boundaries.insert(constructor(i), start..end);\n};\n")),(0,i.kt)("p",null,"And then use it as such:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"// construct all horizontal boundaries\n(0..map.len()).for_each(|row| {\n find_boundaries(\n Orientation::horizontal,\n &mut map[row].iter(),\n map[row].len(),\n row,\n );\n});\n\n// construct all vertical boundaries\n(0..map[0].len()).for_each(|col| {\n find_boundaries(\n Orientation::vertical,\n &mut ColumnIterator::new(&map, col),\n map.len(),\n col,\n );\n});\n")),(0,i.kt)("h4",{id:"walking-around-the-map"},"Walking around the map"),(0,i.kt)("p",null,"Once the 2nd part got introduced, you start to think about a way how not to\ncopy-paste a lot of stuff (I haven't avoided it anyways\u2026). In this problem, I've\nchosen to introduce a trait (i.e. ",(0,i.kt)("em",{parentName:"p"},"interface"),") for 2D and 3D walker."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"trait Wrap: Clone {\n type State;\n\n // simulation\n fn is_blocked(&self) -> bool;\n fn step(&mut self, steps: isize);\n fn turn_left(&mut self);\n fn turn_right(&mut self);\n\n // movement\n fn next(&self) -> (Self::State, Direction);\n\n // final answer\n fn answer(&self) -> Output;\n}\n")),(0,i.kt)("p",null,"Each walker maintains its own state and also provides the functions that are\nused during the simulation. The \u201cpromised\u201d methods are separated into:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"simulation"),"-related: that are used during the simulation from the ",(0,i.kt)("inlineCode",{parentName:"li"},".fold()")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"movement"),"-related: just a one method that holds most of the logic differences\nbetween 2D and 3D"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("em",{parentName:"li"},"final answer"),": which extracts the ",(0,i.kt)("em",{parentName:"li"},"proof of solution")," from the\nimplementation-specific walker")),(0,i.kt)("p",null,"Both 2D and 3D versions borrow the original input and therefore you must\nannotate the lifetime of it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"struct Wrap2D<'a> {\n input: &'a Input,\n position: Position,\n direction: Direction,\n}\nimpl<'a> Wrap2D<'a> {\n fn new(input: &'a Input) -> Wrap2D<'a> {\n// \u2026\n")),(0,i.kt)("h4",{id:"problems"},"Problems"),(0,i.kt)("p",null,"I have used a lot of closures for this problem and once I introduced a parameter\nthat was of unknown type (apart from the fact it implements a specific trait), I\ngot suggested a \u201cfix\u201d for the compilation error that resulted in something that\nwas not possible to parse, cause it, more than likely, violated the grammar."),(0,i.kt)("p",null,"In a similar fashion, I have been suggested changes that led to a code that\ndidn't make sense by just looking at it (there was no need to try the changes),\nfor example one suggested change in the closure parameter caused disapperance of\nthe parameter name. \ud83d\ude04"),(0,i.kt)("h4",{id:"clippy"},"Clippy"),(0,i.kt)("p",null,"I have to admit that Clippy was rather helpful here, I'll include two examples\nof rather smart suggestions."),(0,i.kt)("p",null,"When writing the parsing for this problem, the first thing I have spotted on the\n",(0,i.kt)("inlineCode",{parentName:"p"},"char")," was the ",(0,i.kt)("inlineCode",{parentName:"p"},".is_digit()")," function that takes a radix as a parameter. Clippy\nnoticed that I use ",(0,i.kt)("inlineCode",{parentName:"p"},"radix = 10")," and suggested switching to ",(0,i.kt)("inlineCode",{parentName:"p"},".is_ascii_digit()"),"\nthat does exactly the same thing:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"- .take_while(|c| c.is_digit(10))\n+ .take_while(|c| c.is_ascii_digit())\n")),(0,i.kt)("p",null,"Another useful suggestion appeared when working with the iterators and I wanted\nto get the ",(0,i.kt)("span",{parentName:"p",className:"math math-inline"},(0,i.kt)("span",{parentName:"span",className:"katex"},(0,i.kt)("span",{parentName:"span",className:"katex-mathml"},(0,i.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,i.kt)("semantics",{parentName:"math"},(0,i.kt)("mrow",{parentName:"semantics"},(0,i.kt)("mi",{parentName:"mrow"},"n")),(0,i.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,i.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,i.kt)("span",{parentName:"span",className:"base"},(0,i.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,i.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),"-th element from it. You know the ",(0,i.kt)("inlineCode",{parentName:"p"},".skip()"),", you know the\n",(0,i.kt)("inlineCode",{parentName:"p"},".next()"),", just \u201cslap\u201d them together and we're done for \ud83d\ude01 Well, I got\nsuggested to use ",(0,i.kt)("inlineCode",{parentName:"p"},".nth()")," that does exactly the combination of the two mentioned\nmethods on iterators:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"- match it.clone().skip(skip).next().unwrap() {\n+ match it.clone().nth(skip).unwrap() {\n")),(0,i.kt)("h2",{id:"day-23-unstable-diffusion"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/23"},"Day 23: Unstable Diffusion")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Simulating movement of elves around with a set of specific rules.")),(0,i.kt)("h3",{id:"solution-1"},"Solution"),(0,i.kt)("p",null,"There's not much to mention since it's just a cellular automaton simulation\n(even though the AoC rules for cellular automatons usually get out of hand\n\ud83d\ude09)."),(0,i.kt)("p",null,"Although I had a need to determine boundaries of the elves' positions and ended\nup with a nasty DRY violation. Knowing that you you're looking for maximum and\nminimum that are, of course, exactly the same except for initial values and\ncomparators, it looks like a rather simple fix, but typing in Rust is something\nelse, right? In the end I settled for a function that computes both boundaries\nwithout any duplication while using a closure:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"fn get_bounds(positions: &Input) -> (Vector2D, Vector2D) {\n let f = |init, cmp: &dyn Fn(isize, isize) -> isize| {\n positions\n .iter()\n .fold(Vector2D::new(init, init), |acc, elf| {\n Vector2D::new(cmp(acc.x(), elf.x()), cmp(acc.y(), elf.y()))\n })\n };\n\n (f(isize::MAX, &min::), f(isize::MIN, &max::))\n}\n")),(0,i.kt)("p",null,"This function returns a pair of 2D vectors that represent opposite points of the\nbounding rectangle of all elves."),(0,i.kt)("p",null,"You might ask why would we need a closure and the answer is that ",(0,i.kt)("inlineCode",{parentName:"p"},"positions"),"\ncannot be captured from within the nested function, only via closure. One more\nfun fact on top of that is the type of the comparator"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"&dyn Fn(isize, isize) -> isize\n")),(0,i.kt)("p",null,"Once we remove the ",(0,i.kt)("inlineCode",{parentName:"p"},"dyn")," keyword, compiler yells at us and also includes a way\nhow to get a more thorough explanation of the error by running"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"$ rustc --explain E0782\n")),(0,i.kt)("p",null,"which shows us"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"Trait objects must include the `dyn` keyword.\n\nErroneous code example:\n\n```\ntrait Foo {}\nfn test(arg: Box) {} // error!\n```\n\nTrait objects are a way to call methods on types that are not known until\nruntime but conform to some trait.\n\nTrait objects should be formed with `Box`, but in the code above\n`dyn` is left off.\n\nThis makes it harder to see that `arg` is a trait object and not a\nsimply a heap allocated type called `Foo`.\n\nTo fix this issue, add `dyn` before the trait name.\n\n```\ntrait Foo {}\nfn test(arg: Box) {} // ok!\n```\n\nThis used to be allowed before edition 2021, but is now an error.\n")),(0,i.kt)("admonition",{title:"Rant",type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"Not all of the explanations are helpful though, in some cases they might be even\nmore confusing than helpful, since they address ",(0,i.kt)("em",{parentName:"p"},"very simple")," use cases."),(0,i.kt)("p",{parentName:"admonition"},"As you can see, even in this case there are two sides to the explanations:"),(0,i.kt)("ul",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ul"},"it explains why you need to use ",(0,i.kt)("inlineCode",{parentName:"li"},"dyn"),", but"),(0,i.kt)("li",{parentName:"ul"},"it still mentions that trait objects need to be heap-allocated via ",(0,i.kt)("inlineCode",{parentName:"li"},"Box"),"\nthat, as you can see in my snippet, ",(0,i.kt)("strong",{parentName:"li"},"does not")," apply here \ud83d\ude04 IMO it's\ncaused by the fact that we are borrowing it and therefore we don't need to\ncare about the size or whereabouts of it."))),(0,i.kt)("admonition",{title:"C++ parallel",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"If you dive into the explanation above, you can notice that the ",(0,i.kt)("inlineCode",{parentName:"p"},"Box"),"\npattern is very helpful for using types that are not known during compile-time.\nYou would use a very similar approach in C++ when parsing some data structure\nfrom input (let's say JSON for example)."),(0,i.kt)("p",{parentName:"admonition"},"On the other hand, in this case, it doesn't really make much sense, cause you\ncan clearly see that the types ",(0,i.kt)("strong",{parentName:"p"},"are known")," during the compile-time, which in\nC++ could be easily resolved by templating the helper function.")),(0,i.kt)("h2",{id:"day-24-blizzard-basin"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/24"},"Day 24: Blizzard Basin")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Navigating your way through a basin with series of blizzards that move around\nyou as you move.")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"It's second to last day and I went \u201c",(0,i.kt)("em",{parentName:"p"},"bonkers"),"\u201d on the Rust \ud83d\ude04 Proceed to\nread ",(0,i.kt)("em",{parentName:"p"},"Solution")," part on your own risk.")),(0,i.kt)("h3",{id:"solution-2"},"Solution"),(0,i.kt)("p",null,"You are given a map with blizzards all over the place and you're supposed to\nfind the minimum time it requires you to walk through the basin without getting\nin any of the blizzards."),(0,i.kt)("h4",{id:"breakdown"},"Breakdown"),(0,i.kt)("p",null,"Relatively simple, yet a bit annoying, approach can be taken. It's technically\na shortest-path algorithm implementation with some relaxation restrictions and\nbeing able to stay on one position for some time, so each ",(0,i.kt)("em",{parentName:"p"},"vertex")," of the graph\nis determined by the position on the map and the ",(0,i.kt)("em",{parentName:"p"},"timestamp"),". I have chosen to\nuse ",(0,i.kt)("inlineCode",{parentName:"p"},"Vector3D"),", since ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," attributes can be used for the position\nand, well, let's use ",(0,i.kt)("inlineCode",{parentName:"p"},"z")," for a timestamp, cause why not, right? \ud83d\ude09"),(0,i.kt)("h4",{id:"evaluating-the-blizzards"},"Evaluating the blizzards"),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"I think that this is the most perverted abuse of the traits in the whole 4 weeks\nof AoC in Rust\u2026")),(0,i.kt)("p",null,"The blizzards move along their respective directions in time and loop around in\ntheir respective row/column. Each vertex holds position ",(0,i.kt)("strong",{parentName:"p"},"and")," time, so we can\n",(0,i.kt)("em",{parentName:"p"},"just")," index the basin with the vertex itself, right? Yes, we can \ud83d\ude08"),(0,i.kt)("admonition",{title:"Fun fact",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"While writing this part, I've recognized unnecessary verbosity in the code and\ncleaned it up a bit. The changed version is shown here and the original was just\nmore verbose.")),(0,i.kt)("p",null,"I'll skip the boring parts of checking bounds and entry/exit of the basin \ud83d\ude09\nWe can easily calculate positions of the blizzards using a modular arithmetics:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"impl Index for Basin {\n type Output = char;\n\n fn index(&self, index: Position) -> &Self::Output {\n // \u2039skipped boring parts\u203a\n\n // We need to account for the loops of the blizzards\n let width = self.cols - 2;\n let height = self.rows - 2;\n\n let blizzard_origin = |size, d, t, i| ((i - 1 + size + d * (t % size)) % size + 1) as usize;\n [\n (\n index.y() as usize,\n blizzard_origin(width, -1, index.z(), index.x()),\n '>',\n ),\n (\n index.y() as usize,\n blizzard_origin(width, 1, index.z(), index.x()),\n '<',\n ),\n (\n blizzard_origin(height, -1, index.z(), index.y()),\n index.x() as usize,\n 'v',\n ),\n (\n blizzard_origin(height, 1, index.z(), index.y()),\n index.x() as usize,\n '^',\n ),\n ]\n .iter()\n .find_map(|&(y, x, direction)| {\n if self.map[y][x] == direction {\n Some(&self.map[y][x])\n } else {\n None\n }\n })\n .unwrap_or(&'.')\n }\n}\n")),(0,i.kt)("p",null,"As you can see, there is an expression for calculating the original position and\nit's used multiple times, so why not take it out to a lambda, right? \ud83d\ude09"),(0,i.kt)("p",null,"I couldn't get the ",(0,i.kt)("inlineCode",{parentName:"p"},"rustfmt")," to format the ",(0,i.kt)("inlineCode",{parentName:"p"},"for"),"-loop nicely, so I've just\ndecided to go with iterating over an elements of a slice. I have used, once\nagain, a combination of two functions (",(0,i.kt)("inlineCode",{parentName:"p"},"find_map")," in this case) to do 2 things\nat once and at the end, if we haven't found any blizzard, we just return the\nempty space."),(0,i.kt)("p",null,"I think it's a very ",(0,i.kt)("em",{parentName:"p"},"nice")," (and naughty) way how to use the ",(0,i.kt)("inlineCode",{parentName:"p"},"Index")," trait, don't\nyou think?"),(0,i.kt)("h4",{id:"shortest-path-algorithm"},"Shortest-path algorithm"),(0,i.kt)("p",null,"For the shortest path you can choose and adjust any of the common shortest-path\nalgorithms, in my case, I have decided to use ",(0,i.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/A*_search_algorithm"},(0,i.kt)("em",{parentName:"a"},"A","*"))," instead of Dijkstra's\nalgorithm, since it better reflects the ",(0,i.kt)("em",{parentName:"p"},"cost")," function."),(0,i.kt)("admonition",{title:"Comparison of costs",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"With the Dijkstra's algorithm I would proceed with the ",(0,i.kt)("inlineCode",{parentName:"p"},"time")," attribute used as\na priority for the queue."),(0,i.kt)("p",{parentName:"admonition"},"Whereas with the ",(0,i.kt)("em",{parentName:"p"},"A","*"),", I have chosen to use both time and Manhattan distance\nthat promotes vertices closer to the exit ",(0,i.kt)("strong",{parentName:"p"},"and")," with a minimum time taken.")),(0,i.kt)("p",null,"Cost function is, of course, a closure \ud83d\ude09"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let cost = |p: Position| p.z() as usize + exit.y().abs_diff(p.y()) + exit.x().abs_diff(p.x());\n")),(0,i.kt)("p",null,"And also for checking the possible moves from the current vertex, I have\nimplemented, yet another, closure that yields an iterator with the next moves:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let next_positions = |p| {\n [(0, 0, 1), (0, -1, 1), (0, 1, 1), (-1, 0, 1), (1, 0, 1)]\n .iter()\n .filter_map(move |&(x, y, t)| {\n let next_p = p + Vector3D::new(x, y, t);\n\n if basin[next_p] == '.' {\n Some(next_p)\n } else {\n None\n }\n })\n};\n")),(0,i.kt)("h4",{id:"min-heap"},"Min-heap"),(0,i.kt)("p",null,"In this case I had a need to use the priority queue taking the elements with the\nlowest cost as the prioritized ones. Rust only offers you the ",(0,i.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html"},(0,i.kt)("inlineCode",{parentName:"a"},"BinaryHeap"))," and\nthat is a max-heap. One of the ways how to achieve a min-heap is to put the\nelements in wrapped in a ",(0,i.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/cmp/struct.Reverse.html"},(0,i.kt)("inlineCode",{parentName:"a"},"Reverse"))," (as is even showed in the linked ",(0,i.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#min-heap"},"docs of\nthe ",(0,i.kt)("inlineCode",{parentName:"a"},"BinaryHeap")),"). However the wrapping affects the type of the heap and also\npopping the most prioritized elements yields values wrapped in the ",(0,i.kt)("inlineCode",{parentName:"p"},"Reverse"),"."),(0,i.kt)("p",null,"For this purpose I have just taken the max-heap and wrapped it as a whole in a\nseparate structure providing just the desired methods:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"use std::cmp::{Ord, Reverse};\nuse std::collections::BinaryHeap;\n\npub struct MinHeap {\n heap: BinaryHeap>,\n}\n\nimpl MinHeap {\n pub fn new() -> MinHeap {\n MinHeap {\n heap: BinaryHeap::new(),\n }\n }\n\n pub fn push(&mut self, item: T) {\n self.heap.push(Reverse(item))\n }\n\n pub fn pop(&mut self) -> Option {\n self.heap.pop().map(|Reverse(x)| x)\n }\n}\n\nimpl Default for MinHeap {\n fn default() -> Self {\n Self::new()\n }\n}\n")),(0,i.kt)("p",null,"Rest is just the algorithm implementation which is not that interesting."),(0,i.kt)("h2",{id:"day-25-full-of-hot-air"},(0,i.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/25"},"Day 25: Full of Hot Air")),(0,i.kt)("admonition",{title:"tl;dr",type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Playing around with a numbers in a ",(0,i.kt)("em",{parentName:"p"},"special")," base.")),(0,i.kt)("p",null,"Getting flashbacks to the ",(0,i.kt)("em",{parentName:"p"},"IB111 Foundations of Programming"),"\u2026 Very nice \u201cproblem\u201d\nwith a rather easy solution, as the last day always seems to be."),(0,i.kt)("h3",{id:"solution-3"},"Solution"),(0,i.kt)("p",null,"Implementing 2 functions, converting from the ",(0,i.kt)("em",{parentName:"p"},"SNAFU base")," and back to the ",(0,i.kt)("em",{parentName:"p"},"SNAFU"),"\n",(0,i.kt)("em",{parentName:"p"},"base")," representation. Let's do a bit more though! I have implemented two functions:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"from_snafu")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"to_snafu"))),(0,i.kt)("p",null,"Now it is apparent that all I do is number to string and string to number. Hmm\u2026\nthat sounds familiar, doesn't it? Let's introduce a structure for the SNAFU numbers\nand implement the traits that we need."),(0,i.kt)("p",null,"Let's start with a structure:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\nstruct SNAFU {\n value: i64,\n}\n")),(0,i.kt)("h4",{id:"converting-from-str"},"Converting from ",(0,i.kt)("inlineCode",{parentName:"h4"},"&str")),(0,i.kt)("p",null,"We will start by implementing the ",(0,i.kt)("inlineCode",{parentName:"p"},"FromStr")," trait that will help us parse our input.\nThis is rather simple, I can just take the ",(0,i.kt)("inlineCode",{parentName:"p"},"from_snafu")," function, copy-paste it\ninto the ",(0,i.kt)("inlineCode",{parentName:"p"},"from_str")," method and the number I get will be wrapped in ",(0,i.kt)("inlineCode",{parentName:"p"},"Result")," and\n",(0,i.kt)("inlineCode",{parentName:"p"},"SNAFU")," structure."),(0,i.kt)("h4",{id:"converting-to-string"},"Converting to ",(0,i.kt)("inlineCode",{parentName:"h4"},"String")),(0,i.kt)("p",null,"This is more fun. In some cases you need to implement only one trait and others\nare automatically implemented using that one trait. In our case, if you look in\nthe documentation, you can see that ",(0,i.kt)("inlineCode",{parentName:"p"},"ToString")," trait is automatically implemented\nfor any type that implements ",(0,i.kt)("inlineCode",{parentName:"p"},"Display")," trait."),(0,i.kt)("p",null,"Let's implement the ",(0,i.kt)("inlineCode",{parentName:"p"},"Display")," trait then. We should be able to use the ",(0,i.kt)("inlineCode",{parentName:"p"},"to_snafu"),"\nfunction and just take the ",(0,i.kt)("inlineCode",{parentName:"p"},"self.value")," from the ",(0,i.kt)("inlineCode",{parentName:"p"},"SNAFU")," structure."),(0,i.kt)("p",null,"And for the convenience of tests, we can also implement a rather simple ",(0,i.kt)("inlineCode",{parentName:"p"},"From"),"\ntrait for the ",(0,i.kt)("inlineCode",{parentName:"p"},"SNAFU"),"."),(0,i.kt)("h4",{id:"adjusting-the-code"},"Adjusting the code"),(0,i.kt)("p",null,"After those changes we need to adjust the code and tests."),(0,i.kt)("p",null,"Parsing of the input is very easy, before we have used the lines, now we parse\neverything:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"}," fn parse_input>(pathname: P) -> Input {\n- file_to_lines(pathname)\n+ file_to_structs(pathname)\n }\n")),(0,i.kt)("p",null,"Part 1 needs to be adjusted a bit too:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"}," fn part_1(input: &Input) -> Output {\n- to_snafu(input.iter().map(|s| from_snafu(s)).sum())\n+ SNAFU::from(input.iter().map(|s| s.value).sum::()).to_string()\n }\n")),(0,i.kt)("p",null,"You can also see that it simplifies the meaning a bit and it is more explicit than\nthe previous versions."),(0,i.kt)("p",null,"And for the tests:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"}," #[test]\n fn test_from() {\n- for (n, s) in EXAMPLES.iter() {\n- assert_eq!(from_snafu(s), *n);\n+ for (&n, s) in EXAMPLES.iter() {\n+ assert_eq!(s.parse::().unwrap().value, n);\n }\n }\n \n #[test]\n fn test_to() {\n- for (n, s) in EXAMPLES.iter() {\n- assert_eq!(to_snafu(*n), s.to_string());\n+ for (&n, s) in EXAMPLES.iter() {\n+ assert_eq!(SNAFU::from(n).to_string(), s.to_string());\n }\n")),(0,i.kt)("h2",{id:"summary"},"Summary"),(0,i.kt)("p",null,"Let's wrap the whole thing up! Keeping in mind both AoC and the Rust\u2026"),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"Finished advent calendar :smile:",src:n(3321).Z,width:"2417",height:"1984"})),(0,i.kt)("h3",{id:"advent-of-code"},"Advent of Code"),(0,i.kt)("p",null,"This year was quite fun, even though most of the solutions and posts came in\nlater on (",(0,i.kt)("em",{parentName:"p"},"cough")," in '23 ",(0,i.kt)("em",{parentName:"p"},"cough"),"). Day 22 was the most obnoxious one\u2026 And also\nit feels like I used priority queues and tree data structures ",(0,i.kt)("strong",{parentName:"p"},"a lot")," \ud83d\udc40"),(0,i.kt)("h3",{id:"with-rust"},"with Rust"),(0,i.kt)("p",null,"I must admit that a lot of compiler warnings and errors were very useful. Even\nthough I still found some instances where they didn't help at all or cause even\nworse issues than I had. Compilation times have been addressed with the caching."),(0,i.kt)("p",null,"Building my first tree data structure in Rust has been a very \u201cinteresting\u201d\njourney. Being able to write a more generic BFS algorithm that allows you to not\nduplicate code while still mantaining the desired functionality contributes to\na very readable code."),(0,i.kt)("p",null,"I am definitely much more aware of the basic things that bloated Python is\nmissing, yet Rust has them\u2026"),(0,i.kt)("p",null,"Using explicit types and writing down placeholder functions with ",(0,i.kt)("inlineCode",{parentName:"p"},"todo!()"),"\nmacros is very pleasant, since it allows you to easily navigate the type system\nduring the development when you don't even need to be sure how are you going to\nput the smaller pieces together."),(0,i.kt)("p",null,"I have used a plethora of traits and also implemented some of them to either be\nidiomatic, or exploit the syntactic sugar they offer. Deriving the default trait\nimplementation is also very helpful in a lot of cases, e.g. debugging output,\ncopying, equality comparison, etc."),(0,i.kt)("p",null,"I confess to touching more \u201ccursed\u201d parts of the Rust, such as macros to\ndeclutter the copy-paste for tests or writing my own structures that need to\ncarry a lifetime for their own fields."),(0,i.kt)("p",null,"tl;dr Relatively pleasant language until you hit brick wall \ud83d\ude09"),(0,i.kt)("hr",null),(0,i.kt)("p",null,"See you next year! Maybe in Rust, maybe not \ud83d\ude43"))}d.isMDXComponent=!0},3321:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/calendar-f891b624f3e0efb34bba582100a7d8df.png"}}]); \ No newline at end of file diff --git a/assets/js/3de247b5.4bd0c3fd.js b/assets/js/3de247b5.ed11a74c.js similarity index 99% rename from assets/js/3de247b5.4bd0c3fd.js rename to assets/js/3de247b5.ed11a74c.js index ee57ce0..6417990 100644 --- a/assets/js/3de247b5.4bd0c3fd.js +++ b/assets/js/3de247b5.ed11a74c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3184],{3905:(I,M,i)=>{i.d(M,{Zo:()=>c,kt:()=>m});var N=i(7294);function T(I,M,i){return M in I?Object.defineProperty(I,M,{value:i,enumerable:!0,configurable:!0,writable:!0}):I[M]=i,I}function g(I,M){var i=Object.keys(I);if(Object.getOwnPropertySymbols){var N=Object.getOwnPropertySymbols(I);M&&(N=N.filter((function(M){return Object.getOwnPropertyDescriptor(I,M).enumerable}))),i.push.apply(i,N)}return i}function j(I){for(var M=1;M=0||(T[i]=I[i]);return T}(I,M);if(Object.getOwnPropertySymbols){var g=Object.getOwnPropertySymbols(I);for(N=0;N=0||Object.prototype.propertyIsEnumerable.call(I,i)&&(T[i]=I[i])}return T}var Z=N.createContext({}),D=function(I){var M=N.useContext(Z),i=M;return I&&(i="function"==typeof I?I(M):j(j({},M),I)),i},c=function(I){var M=D(I.components);return N.createElement(Z.Provider,{value:M},I.children)},l="mdxType",C={inlineCode:"code",wrapper:function(I){var M=I.children;return N.createElement(N.Fragment,{},M)}},G=N.forwardRef((function(I,M){var i=I.components,T=I.mdxType,g=I.originalType,Z=I.parentName,c=z(I,["components","mdxType","originalType","parentName"]),l=D(i),G=T,m=l["".concat(Z,".").concat(G)]||l[G]||C[G]||g;return i?N.createElement(m,j(j({ref:M},c),{},{components:i})):N.createElement(m,j({ref:M},c))}));function m(I,M){var i=arguments,T=M&&M.mdxType;if("string"==typeof I||T){var g=i.length,j=new Array(g);j[0]=G;var z={};for(var Z in M)hasOwnProperty.call(M,Z)&&(z[Z]=M[Z]);z.originalType=I,z[l]="string"==typeof I?I:T,j[1]=z;for(var D=2;D{i.r(M),i.d(M,{assets:()=>k,contentTitle:()=>n,default:()=>Y,frontMatter:()=>y,metadata:()=>e,toc:()=>O});var N=i(7462),T=i(7294),g=i(3905),j=i(6010),z=i(2466),Z=i(6550),D=i(1980),c=i(7392),l=i(12);function C(I){return function(I){return T.Children.map(I,(I=>{if(!I||(0,T.isValidElement)(I)&&function(I){const{props:M}=I;return!!M&&"object"==typeof M&&"value"in M}(I))return I;throw new Error(`Docusaurus error: Bad child <${"string"==typeof I.type?I.type:I.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}(I).map((I=>{let{props:{value:M,label:i,attributes:N,default:T}}=I;return{value:M,label:i,attributes:N,default:T}}))}function G(I){const{values:M,children:i}=I;return(0,T.useMemo)((()=>{const I=M??C(i);return function(I){const M=(0,c.l)(I,((I,M)=>I.value===M.value));if(M.length>0)throw new Error(`Docusaurus error: Duplicate values "${M.map((I=>I.value)).join(", ")}" found in . Every value needs to be unique.`)}(I),I}),[M,i])}function m(I){let{value:M,tabValues:i}=I;return i.some((I=>I.value===M))}function b(I){let{queryString:M=!1,groupId:i}=I;const N=(0,Z.k6)(),g=function(I){let{queryString:M=!1,groupId:i}=I;if("string"==typeof M)return M;if(!1===M)return null;if(!0===M&&!i)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return i??null}({queryString:M,groupId:i});return[(0,D._X)(g),(0,T.useCallback)((I=>{if(!g)return;const M=new URLSearchParams(N.location.search);M.set(g,I),N.replace({...N.location,search:M.toString()})}),[g,N])]}function S(I){const{defaultValue:M,queryString:i=!1,groupId:N}=I,g=G(I),[j,z]=(0,T.useState)((()=>function(I){let{defaultValue:M,tabValues:i}=I;if(0===i.length)throw new Error("Docusaurus error: the component requires at least one children component");if(M){if(!m({value:M,tabValues:i}))throw new Error(`Docusaurus error: The has a defaultValue "${M}" but none of its children has the corresponding value. Available values are: ${i.map((I=>I.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return M}const N=i.find((I=>I.default))??i[0];if(!N)throw new Error("Unexpected error: 0 tabValues");return N.value}({defaultValue:M,tabValues:g}))),[Z,D]=b({queryString:i,groupId:N}),[c,C]=function(I){let{groupId:M}=I;const i=function(I){return I?`docusaurus.tab.${I}`:null}(M),[N,g]=(0,l.Nk)(i);return[N,(0,T.useCallback)((I=>{i&&g.set(I)}),[i,g])]}({groupId:N}),S=(()=>{const I=Z??c;return m({value:I,tabValues:g})?I:null})();(0,T.useLayoutEffect)((()=>{S&&z(S)}),[S]);return{selectedValue:j,selectValue:(0,T.useCallback)((I=>{if(!m({value:I,tabValues:g}))throw new Error(`Can't select invalid tab value=${I}`);z(I),D(I),C(I)}),[D,C,g]),tabValues:g}}var L=i(2389);const t={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function x(I){let{className:M,block:i,selectedValue:g,selectValue:Z,tabValues:D}=I;const c=[],{blockElementScrollPositionUntilNextRender:l}=(0,z.o5)(),C=I=>{const M=I.currentTarget,i=c.indexOf(M),N=D[i].value;N!==g&&(l(M),Z(N))},G=I=>{let M=null;switch(I.key){case"Enter":C(I);break;case"ArrowRight":{const i=c.indexOf(I.currentTarget)+1;M=c[i]??c[0];break}case"ArrowLeft":{const i=c.indexOf(I.currentTarget)-1;M=c[i]??c[c.length-1];break}}M?.focus()};return T.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,j.Z)("tabs",{"tabs--block":i},M)},D.map((I=>{let{value:M,label:i,attributes:z}=I;return T.createElement("li",(0,N.Z)({role:"tab",tabIndex:g===M?0:-1,"aria-selected":g===M,key:M,ref:I=>c.push(I),onKeyDown:G,onClick:C},z,{className:(0,j.Z)("tabs__item",t.tabItem,z?.className,{"tabs__item--active":g===M})}),i??M)})))}function w(I){let{lazy:M,children:i,selectedValue:N}=I;const g=(Array.isArray(i)?i:[i]).filter(Boolean);if(M){const I=g.find((I=>I.props.value===N));return I?(0,T.cloneElement)(I,{className:"margin-top--md"}):null}return T.createElement("div",{className:"margin-top--md"},g.map(((I,M)=>(0,T.cloneElement)(I,{key:M,hidden:I.props.value!==N}))))}function s(I){const M=S(I);return T.createElement("div",{className:(0,j.Z)("tabs-container",t.tabList)},T.createElement(x,(0,N.Z)({},I,M)),T.createElement(w,(0,N.Z)({},I,M)))}function P(I){const M=(0,L.Z)();return T.createElement(s,(0,N.Z)({key:String(M)},I))}const d={tabItem:"tabItem_Ymn6"};function a(I){let{children:M,hidden:i,className:N}=I;return T.createElement("div",{role:"tabpanel",className:(0,j.Z)(d.tabItem,N),hidden:i},M)}const y={id:"rules",title:"On the rules of the red-black tree",description:"Shower thoughts on the rules of the red-black tree.\n",tags:["red-black trees","balanced trees"],last_update:{date:new Date("2023-06-10T00:00:00.000Z")}},n=void 0,e={unversionedId:"rb-trees/rules",id:"rb-trees/rules",title:"On the rules of the red-black tree",description:"Shower thoughts on the rules of the red-black tree.\n",source:"@site/ib002/08-rb-trees/2023-06-10-rules.md",sourceDirName:"08-rb-trees",slug:"/rb-trees/rules",permalink:"/ib002/rb-trees/rules",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/08-rb-trees/2023-06-10-rules.md",tags:[{label:"red-black trees",permalink:"/ib002/tags/red-black-trees"},{label:"balanced trees",permalink:"/ib002/tags/balanced-trees"}],version:"current",lastUpdatedAt:1686355200,formattedLastUpdatedAt:"Jun 10, 2023",frontMatter:{id:"rules",title:"On the rules of the red-black tree",description:"Shower thoughts on the rules of the red-black tree.\n",tags:["red-black trees","balanced trees"],last_update:{date:"2023-06-10T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f",permalink:"/ib002/rb-trees/applications"},next:{title:"Graphs",permalink:"/ib002/category/graphs"}},k={},O=[{value:"Introduction",id:"introduction",level:2},{value:"1\xaa Every node is either red or black.",id:"1\xaa-every-node-is-either-red-or-black",level:2},{value:"Do I really need the nodes to be explicitly colored?",id:"do-i-really-need-the-nodes-to-be-explicitly-colored",level:3},{value:"Black height",id:"black-height",level:4},{value:"Isomorphic trees",id:"isomorphic-trees",level:4},{value:"2\xaa The root is black.",id:"2\xaa-the-root-is-black",level:2},{value:"3\xaa Every leaf (nil) is black.",id:"3\xaa-every-leaf-nil-is-black",level:2},{value:"4\xaa If a node is red, then both its children are black.",id:"4\xaa-if-a-node-is-red-then-both-its-children-are-black",level:2},{value:"5\xaa For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.",id:"5\xaa-for-each-node-all-simple-paths-from-the-node-to-descendant-leaves-contain-the-same-number-of-black-nodes",level:2}],u={toc:O},U="wrapper";function Y(I){let{components:M,...T}=I;return(0,g.kt)(U,(0,N.Z)({},u,T,{components:M,mdxType:"MDXLayout"}),(0,g.kt)("h2",{id:"introduction"},"Introduction"),(0,g.kt)("p",null,"Have you ever thought about the red-black tree rules in more depth? Why are they\nformulated the way they are? How come they keep the tree balanced? Let's go through\neach of the red-black tree rules and try to change, break and contemplate about\nthem."),(0,g.kt)("p",null,"We expect that you are familiar with the following set of the rules",(0,g.kt)("sup",{parentName:"p",id:"fnref-1"},(0,g.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),":"),(0,g.kt)("ol",null,(0,g.kt)("li",{parentName:"ol"},"Every node is either red or black."),(0,g.kt)("li",{parentName:"ol"},"The root is black."),(0,g.kt)("li",{parentName:"ol"},"Every leaf (",(0,g.kt)("inlineCode",{parentName:"li"},"nil"),") is black."),(0,g.kt)("li",{parentName:"ol"},"If a node is red, then both its children are black."),(0,g.kt)("li",{parentName:"ol"},"For each node, all simple paths from the node to descendant leaves contain the\nsame number of black nodes.")),(0,g.kt)("p",null,"Each section will go into ",(0,g.kt)("em",{parentName:"p"},"reasonable")," details of each rule."),(0,g.kt)("h2",{id:"1\xaa-every-node-is-either-red-or-black"},"1\xaa Every node is either red or black."),(0,g.kt)("p",null,"OK\u2026 This one is very simple. It is just a definition and is used in all other\nrules. Not much to talk about here. Or is there?"),(0,g.kt)("h3",{id:"do-i-really-need-the-nodes-to-be-explicitly-colored"},"Do I really need the nodes to be explicitly colored?"),(0,g.kt)("p",null,"The answer is no. Balancing of the red-black trees is \u201cenforced\u201d by the 4th and\n5th rule in the enumeration above. There are many ways you can avoid using colors."),(0,g.kt)("h4",{id:"black-height"},"Black height"),(0,g.kt)("p",null,"We mentioned the 4th and 5th rule and that it enforces the balancing. What does\nit mean for us?"),(0,g.kt)("p",null,"Well, we definitely do not have to use the colors, which even as a ",(0,g.kt)("em",{parentName:"p"},"boolean")," flag\nwould take at least 1 byte of space (and usually even more), cause\u2026 well, it is\neasier for the CPU to work with words rather than single bits."),(0,g.kt)("p",null,"We could use the black height, couldn't we? It would mean more memory used, cause\nit should be ideally big and unsigned. Can we tell the color of a node from the\nblack height? Of course we can, if my child has the same black height as I do,\nit means that there was no black node added on the path between us and therefore\nmy child would be colored red."),(0,g.kt)("p",null,"Example of a red-black tree that keeps count of black nodes on paths to the\nleaves follows:"),(0,g.kt)("p",null,(0,g.kt)("img",{alt:"Red-black tree with black height",src:i(4866).Z+"#gh-light-mode-only",width:"923",height:"539"}),"\n",(0,g.kt)("img",{alt:"Red-black tree with black height",src:i(1185).Z+"#gh-dark-mode-only",width:"923",height:"539"})),(0,g.kt)("p",null,"We mark the ",(0,g.kt)("em",{parentName:"p"},"black heights")," in superscript. You can see that all leaves have the\nblack height equal to ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mn",{parentName:"mrow"},"1")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"1")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"1"))))),". Let's take a look at some of the interesting cases:"),(0,g.kt)("ul",null,(0,g.kt)("li",{parentName:"ul"},(0,g.kt)("p",{parentName:"li"},"If we take a look at the node with ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mtext",{parentName:"mrow"},"key"),(0,g.kt)("mo",{parentName:"mrow"},"="),(0,g.kt)("mn",{parentName:"mrow"},"9")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\text{key} = 9")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,g.kt)("span",{parentName:"span",className:"mord text"},(0,g.kt)("span",{parentName:"span",className:"mord"},"key")),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,g.kt)("span",{parentName:"span",className:"mrel"},"="),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"9"))))),", we can see that it is\ncoloured red and its black height is 1, because it is a leaf."),(0,g.kt)("p",{parentName:"li"},"Let's look at its parent (node with ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mtext",{parentName:"mrow"},"key"),(0,g.kt)("mo",{parentName:"mrow"},"="),(0,g.kt)("mn",{parentName:"mrow"},"8")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\text{key} = 8")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,g.kt)("span",{parentName:"span",className:"mord text"},(0,g.kt)("span",{parentName:"span",className:"mord"},"key")),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,g.kt)("span",{parentName:"span",className:"mrel"},"="),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"8"))))),"). On its left side it has\n",(0,g.kt)("inlineCode",{parentName:"p"},"nil")," and on its right side the ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mn",{parentName:"mrow"},"9")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"9")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"9"))))),". And its black height is still ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mn",{parentName:"mrow"},"1")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"1")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"1"))))),", cause\nexcept for the ",(0,g.kt)("inlineCode",{parentName:"p"},"nil")," leaves, there are no other black nodes."),(0,g.kt)("p",{parentName:"li"},"We can clearly see that if a node has the same black height as its parent, it\nis a red node.")),(0,g.kt)("li",{parentName:"ul"},(0,g.kt)("p",{parentName:"li"},"Now let's take a look at the root with ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mtext",{parentName:"mrow"},"key"),(0,g.kt)("mo",{parentName:"mrow"},"="),(0,g.kt)("mn",{parentName:"mrow"},"3")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\text{key} = 3")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,g.kt)("span",{parentName:"span",className:"mord text"},(0,g.kt)("span",{parentName:"span",className:"mord"},"key")),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,g.kt)("span",{parentName:"span",className:"mrel"},"="),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"3"))))),". It has a black height\nof 3. Both of its children are black nodes and have black height of 2."),(0,g.kt)("p",{parentName:"li"},"We can see that if a node has its height 1 lower than its parent, it is a black\nnode."),(0,g.kt)("p",{parentName:"li"},"The reasoning behind it is rather simple, we count the black nodes all the way\nto the leaves, therefore if my parent has a higher black height, it means that\non the path from me to my parent there is a black node, but the only node added\nis me, therefore I must be black."))),(0,g.kt)("h4",{id:"isomorphic-trees"},"Isomorphic trees"),(0,g.kt)("p",null,"One of the other ways to avoid using color is storing the red-black tree in some\nisomorphic tree. The structure of 2-3-4 tree allows us to avoid using the color\ncompletely. This is a bit different approach, cause we would be basically using\ndifferent tree, so we keep this note in just as a \u201chack\u201d."),(0,g.kt)("h2",{id:"2\xaa-the-root-is-black"},"2\xaa The root is black."),(0,g.kt)("p",null,"This rule might seem like a very important one, but overall is not. You can safely\nomit this rule, but you also need to deal with the consequences."),(0,g.kt)("p",null,"Let's refresh our memory with the algorithm of ",(0,g.kt)("em",{parentName:"p"},"insert fixup"),":"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre"},"WHILE z.p.color == Red\n IF z.p == z.p.p.left\n y = z.p.p.right\n\n IF y.color == Red\n z.p.color = Black\n y.color = Black\n z.p.p.color = Red\n z = z.p.p\n ELSE\n IF z == z.p.right\n z = z.p\n Left-Rotate(T, z)\n z.p.color = Black\n z.p.p.color = Red\n Right-Rotate(T, z.p.p)\n ELSE (same as above with \u201cright\u201d and \u201cleft\u201d exchanged)\n\nT.root.color = Black\n")),(0,g.kt)("admonition",{type:"tip"},(0,g.kt)("p",{parentName:"admonition"},"If you have tried to implement any of the more complex data structures, such as\nred-black trees, etc., in a statically typed language that also checks you for\n",(0,g.kt)("inlineCode",{parentName:"p"},"NULL"),"-correctness (e.g. ",(0,g.kt)("em",{parentName:"p"},"mypy")," or even C# with nullable reference types), you\nmight have run into numerous issues in the cases where you are 100% sure that you\ncannot obtain ",(0,g.kt)("inlineCode",{parentName:"p"},"NULL")," because of the invariants, but the static type checking\ndoesn't know that."),(0,g.kt)("p",{parentName:"admonition"},"The issue we hit with the ",(0,g.kt)("em",{parentName:"p"},"insert fixup")," is very similar.")),(0,g.kt)("p",null,"You might not realize the issue at the first sight, but the algorithm described\nwith the pseudocode above expects that the root of the red-black tree is black by\nboth relying on the invariant in the algorithm and afterwards by enforcing the\nblack root property."),(0,g.kt)("p",null,"If we decide to omit this condition, we need to address it in the pseudocodes\naccordingly."),(0,g.kt)("table",null,(0,g.kt)("thead",{parentName:"table"},(0,g.kt)("tr",{parentName:"thead"},(0,g.kt)("th",{parentName:"tr",align:"center"},"Usual algorithm with black root"),(0,g.kt)("th",{parentName:"tr",align:"center"},"Allowing red root"))),(0,g.kt)("tbody",{parentName:"table"},(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"1\xaa insertion",src:i(5018).Z+"#gh-light-mode-only",width:"179",height:"155"}),(0,g.kt)("img",{alt:"1\xaa insertion",src:i(4241).Z+"#gh-dark-mode-only",width:"179",height:"155"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"1\xaa insertion",src:i(2227).Z+"#gh-light-mode-only",width:"179",height:"155"}),(0,g.kt)("img",{alt:"1\xaa insertion",src:i(3591).Z+"#gh-dark-mode-only",width:"179",height:"155"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"2\xaa insertion",src:i(8491).Z+"#gh-light-mode-only",width:"227",height:"251"}),(0,g.kt)("img",{alt:"2\xaa insertion",src:i(9232).Z+"#gh-dark-mode-only",width:"227",height:"251"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"2\xaa insertion",src:i(6805).Z+"#gh-light-mode-only",width:"227",height:"251"}),(0,g.kt)("img",{alt:"2\xaa insertion",src:i(7690).Z+"#gh-dark-mode-only",width:"227",height:"251"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"3\xaa insertion",src:i(4485).Z+"#gh-light-mode-only",width:"371",height:"251"}),(0,g.kt)("img",{alt:"3\xaa insertion",src:i(3559).Z+"#gh-dark-mode-only",width:"371",height:"251"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"3\xaa insertion",src:i(7676).Z+"#gh-light-mode-only",width:"371",height:"251"}),(0,g.kt)("img",{alt:"3\xaa insertion",src:i(9861).Z+"#gh-dark-mode-only",width:"371",height:"251"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"4\xaa insertion",src:i(3037).Z+"#gh-light-mode-only",width:"419",height:"347"}),(0,g.kt)("img",{alt:"4\xaa insertion",src:i(9034).Z+"#gh-dark-mode-only",width:"419",height:"347"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"4\xaa insertion",src:i(7632).Z+"#gh-light-mode-only",width:"419",height:"347"}),(0,g.kt)("img",{alt:"4\xaa insertion",src:i(4110).Z+"#gh-dark-mode-only",width:"419",height:"347"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"5\xaa insertion",src:i(4961).Z+"#gh-light-mode-only",width:"419",height:"347"}),(0,g.kt)("img",{alt:"5\xaa insertion",src:i(4236).Z+"#gh-dark-mode-only",width:"419",height:"347"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"5\xaa insertion",src:i(7109).Z+"#gh-light-mode-only",width:"419",height:"347"}),(0,g.kt)("img",{alt:"5\xaa insertion",src:i(9418).Z+"#gh-dark-mode-only",width:"419",height:"347"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"6\xaa insertion",src:i(6061).Z+"#gh-light-mode-only",width:"563",height:"347"}),(0,g.kt)("img",{alt:"6\xaa insertion",src:i(376).Z+"#gh-dark-mode-only",width:"563",height:"347"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"6\xaa insertion",src:i(8998).Z+"#gh-light-mode-only",width:"563",height:"347"}),(0,g.kt)("img",{alt:"6\xaa insertion",src:i(3533).Z+"#gh-dark-mode-only",width:"563",height:"347"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"7\xaa insertion",src:i(7115).Z+"#gh-light-mode-only",width:"563",height:"443"}),(0,g.kt)("img",{alt:"7\xaa insertion",src:i(9010).Z+"#gh-dark-mode-only",width:"563",height:"443"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"7\xaa insertion",src:i(2366).Z+"#gh-light-mode-only",width:"563",height:"443"}),(0,g.kt)("img",{alt:"7\xaa insertion",src:i(4269).Z+"#gh-dark-mode-only",width:"563",height:"443"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"8\xaa insertion",src:i(7239).Z+"#gh-light-mode-only",width:"635",height:"443"}),(0,g.kt)("img",{alt:"8\xaa insertion",src:i(2399).Z+"#gh-dark-mode-only",width:"635",height:"443"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"8\xaa insertion",src:i(3927).Z+"#gh-light-mode-only",width:"635",height:"443"}),(0,g.kt)("img",{alt:"8\xaa insertion",src:i(122).Z+"#gh-dark-mode-only",width:"635",height:"443"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"9\xaa insertion",src:i(1461).Z+"#gh-light-mode-only",width:"755",height:"443"}),(0,g.kt)("img",{alt:"9\xaa insertion",src:i(2705).Z+"#gh-dark-mode-only",width:"755",height:"443"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"9\xaa insertion",src:i(5509).Z+"#gh-light-mode-only",width:"755",height:"443"}),(0,g.kt)("img",{alt:"9\xaa insertion",src:i(2476).Z+"#gh-dark-mode-only",width:"755",height:"443"}))))),(0,g.kt)("h2",{id:"3\xaa-every-leaf-nil-is-black"},"3\xaa Every leaf (",(0,g.kt)("inlineCode",{parentName:"h2"},"nil"),") is black."),(0,g.kt)("p",null,"Now, this rule is a funny one. What does this imply and can I interpret this in\nsome other way? Let's go through some of the possible ways I can look at this and\nhow would they affect the other rules and balancing."),(0,g.kt)("p",null,"We will experiment with the following tree:\n",(0,g.kt)("img",{src:i(6034).Z+"#gh-light-mode-only",width:"899",height:"539"}),"\n",(0,g.kt)("img",{src:i(4254).Z+"#gh-dark-mode-only",width:"899",height:"539"})),(0,g.kt)("p",null,"We should start by counting the black nodes from root to the ",(0,g.kt)("inlineCode",{parentName:"p"},"nil")," leaves based\non the rules. We have multiple similar paths, so we will pick only the interesting\nones."),(0,g.kt)("ol",null,(0,g.kt)("li",{parentName:"ol"},"What happens if we do not count the ",(0,g.kt)("inlineCode",{parentName:"li"},"nil")," leaves?"),(0,g.kt)("li",{parentName:"ol"},"What happens if we consider leaves the nodes with ",(0,g.kt)("em",{parentName:"li"},"no descendants"),", i.e. both\nof node's children are ",(0,g.kt)("inlineCode",{parentName:"li"},"nil"),"?"),(0,g.kt)("li",{parentName:"ol"},"What happens if we do not count the ",(0,g.kt)("inlineCode",{parentName:"li"},"nil")," leaves, but consider nodes with at\nleast one ",(0,g.kt)("inlineCode",{parentName:"li"},"nil")," descendant as leaves?")),(0,g.kt)("table",null,(0,g.kt)("thead",{parentName:"table"},(0,g.kt)("tr",{parentName:"thead"},(0,g.kt)("th",{parentName:"tr",align:"right"},"path"),(0,g.kt)("th",{parentName:"tr",align:"right"},"black nodes"),(0,g.kt)("th",{parentName:"tr",align:"right"},"1\xaa idea"),(0,g.kt)("th",{parentName:"tr",align:"right"},"2\xaa idea"),(0,g.kt)("th",{parentName:"tr",align:"right"},"3\xaa idea"))),(0,g.kt)("tbody",{parentName:"table"},(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"right"},(0,g.kt)("inlineCode",{parentName:"td"},"3 \u2192 1 \u2192 0 \u2192 nil")),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3"),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3")),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"right"},(0,g.kt)("inlineCode",{parentName:"td"},"3 \u2192 5 \u2192 7 \u2192 8 \u2192 nil")),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3"),(0,g.kt)("td",{parentName:"tr",align:"right"},"-"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3")),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"right"},(0,g.kt)("inlineCode",{parentName:"td"},"3 \u2192 5 \u2192 7 \u2192 8 \u2192 9 \u2192 nil")),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3"),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3")))),(0,g.kt)("p",null,"First idea is very easy to execute and it is also very easy to argue about its\ncorrectness. It is correct, because we just subtract one from each of the paths.\nThis affects ",(0,g.kt)("strong",{parentName:"p"},"all")," paths and therefore results in global decrease by one."),(0,g.kt)("p",null,"Second idea is a bit more complicated. We count the ",(0,g.kt)("inlineCode",{parentName:"p"},"nil"),"s, so the count is ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mn",{parentName:"mrow"},"4")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"4")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"4"))))),"\nas it should be. However, there is one difference. Second path no longer satisfies\nthe condition of a ",(0,g.kt)("em",{parentName:"p"},"leaf"),". Technically it relaxes the 5th rule, because we leave\nout some of the nodes. We should probably avoid that."),(0,g.kt)("admonition",{type:"caution"},(0,g.kt)("p",{parentName:"admonition"},"With the second idea, you may also feel that we are \u201cbending\u201d the rules a bit,\nespecially the definition of the \u201cleaf\u201d nodes."),(0,g.kt)("p",{parentName:"admonition"},"Given the definition of the red-black tree, where ",(0,g.kt)("inlineCode",{parentName:"p"},"nil")," is considered to be an\nexternal node, we have decided that bending it a bit just to stir a thought about\nit won't hurt anybody. \ud83d\ude09")),(0,g.kt)("h2",{id:"4\xaa-if-a-node-is-red-then-both-its-children-are-black"},"4\xaa If a node is red, then both its children are black."),(0,g.kt)("p",null,"This rule might seem rather silly on the first look, but there are 2 important\nfunctions:"),(0,g.kt)("ol",null,(0,g.kt)("li",{parentName:"ol"},"it allows the algorithms to ",(0,g.kt)("em",{parentName:"li"},"\u201cnotice\u201d")," that something went wrong (i.e. the\ntree needs to be rebalanced), and"),(0,g.kt)("li",{parentName:"ol"},"it holds the balancing and height of the tree ",(0,g.kt)("em",{parentName:"li"},"\u201cin check\u201d")," (with the help of\nthe 5th rule).")),(0,g.kt)("p",null,"When we have a look at the algorithms that are used for fixing up the red-black\ntree after an insertion or deletion, we will notice that all the algorithms need\nis the color of the node. "),(0,g.kt)("blockquote",null,(0,g.kt)("p",{parentName:"blockquote"},"How come it is the only thing that we need?\nHow come such na\xefve thing can be enough?")),(0,g.kt)("p",null,"Let's say we perform an insertion into the tree\u2026 We go with the usual and pretty\nprimitive insertion into the binary-search tree and then, if needed, we \u201cfix up\u201d\nbroken invariants. ",(0,g.kt)("em",{parentName:"p"},"How can that be enough?")," With each insertion and deletion we\nmaintain the invariants, therefore if we break them with one operation, there's\nonly one path on which the invariants were ",(0,g.kt)("em",{parentName:"p"},"felled"),". If we know that rest of the\ntree is correct, it allows us to fix the issues just by propagating it to the\nroot and ",(0,g.kt)("em",{parentName:"p"},"abusing")," the siblings (which are, of course, correct red-black\nsubtrees) to fix or at least partially mitigate the issues and propagate them\nfurther."),(0,g.kt)("p",null,"Let's assume that we do not enforce this rule, you can see how it breaks the\nbalancing of the tree below."),(0,g.kt)(P,{mdxType:"Tabs"},(0,g.kt)(a,{value:"enforcing",label:"Enforcing this rule",mdxType:"TabItem"},(0,g.kt)("p",null,(0,g.kt)("img",{src:i(2815).Z+"#gh-light-mode-only",width:"755",height:"347"}),"\n",(0,g.kt)("img",{src:i(6754).Z+"#gh-dark-mode-only",width:"755",height:"347"}))),(0,g.kt)(a,{value:"omitting",label:"Omitting this rule",mdxType:"TabItem"},(0,g.kt)("p",null,(0,g.kt)("img",{src:i(8800).Z+"#gh-light-mode-only",width:"803",height:"443"}),"\n",(0,g.kt)("img",{src:i(9183).Z+"#gh-dark-mode-only",width:"803",height:"443"})))),(0,g.kt)("p",null,"We can create a ",(0,g.kt)("strong",{parentName:"p"},"big")," subtree with only red nodes and ",(0,g.kt)("strong",{parentName:"p"},"even")," when keeping\nthe rest of the rules maintained, it will break the time complexity. It stops us\nfrom \u201chacking\u201d the black height requirement laid by the 5th rule."),(0,g.kt)("h2",{id:"5\xaa-for-each-node-all-simple-paths-from-the-node-to-descendant-leaves-contain-the-same-number-of-black-nodes"},"5\xaa For each node, all simple paths from the node to descendant leaves contain the same number of black nodes."),(0,g.kt)("p",null,"As it was mentioned, with the 4th rule they hold the balancing of the red-black\ntree."),(0,g.kt)("admonition",{type:"tip"},(0,g.kt)("p",{parentName:"admonition"},"An important observation here is the fact that the red-black tree is a\n",(0,g.kt)("strong",{parentName:"p"},"height"),"-balanced tree.")),(0,g.kt)("p",null,"Enforcing this rule (together with the 4th rule) keeps the tree balanced:"),(0,g.kt)("ol",null,(0,g.kt)("li",{parentName:"ol"},"4th rule makes sure we can't \u201chack\u201d this requirement."),(0,g.kt)("li",{parentName:"ol"},"This rule ensures that we have \u201csimilar\u201d",(0,g.kt)("sup",{parentName:"li",id:"fnref-2"},(0,g.kt)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2"))," length to each of the leaves.")),(0,g.kt)("admonition",{title:"AVL tree",type:"tip"},(0,g.kt)("p",{parentName:"admonition"},"You might have heard about an ",(0,g.kt)("em",{parentName:"p"},"AVL tree")," before. It is the first self-balanced\ntree to be ever introduced and works in a very similar nature as the red-black\ntree, the only difference is that it does not deal with the ",(0,g.kt)("em",{parentName:"p"},"black height"),", but\nthe height in general."),(0,g.kt)("p",{parentName:"admonition"},"If you were to compare AVL with the red-black tree, you can say that AVL is much\nmore strict while red-black tree can still maintain the same asymptotic time\ncomplexity for the operations, but having more relaxed rules.")),(0,g.kt)("div",{className:"footnotes"},(0,g.kt)("hr",{parentName:"div"}),(0,g.kt)("ol",{parentName:"div"},(0,g.kt)("li",{parentName:"ol",id:"fn-1"},"CORMEN, Thomas. Introduction to algorithms. Cambridge, Mass: MIT Press, 2009. isbn 9780262033848.",(0,g.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,g.kt)("li",{parentName:"ol",id:"fn-2"},"red nodes still exist",(0,g.kt)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")))))}Y.isMDXComponent=!0},4254:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rb_dark-2917b0f8de62597646b619102f126a53.svg"},1185:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rb_height_dark-921b2d98d9fe1e579474faf36486f281.svg"},4866:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rb_height_light-0aff6e7a40a9f601e0dd1114e43e43b1.svg"},6034:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rb_light-9889570d993cf4a78a1bcccfbd76eab4.svg"},6754:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iNTY2cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgNTY2LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgNTYyLC0yNTYgNTYyLDQgLTQsNCIvPgo8IS0tIE5vZGUodmFsdWU9MywgcmFuaz0yKSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTMsIHJhbms9Mik8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMjc5IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjc5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MzwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjIwNyIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTEsIHJhbms9MSkgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0xLCByYW5rPTEpPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI2NC40MywtMjE4LjgzQzI1NC4yNSwtMjA4Ljk0IDI0MC40OCwtMTk1LjU1IDIyOC45NywtMTg0LjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIzMS40MSwtMTgxLjg1IDIyMS44LC0xNzcuMzggMjI2LjUzLC0xODYuODcgMjMxLjQxLC0xODEuODUiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NSwgcmFuaz0xKSAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTUsIHJhbms9MSk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMzUxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzUxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NTwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MywgcmFuaz0yKSYjNDU7Jmd0O05vZGUodmFsdWU9NSwgcmFuaz0xKSAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTUsIHJhbms9MSk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjkzLjU3LC0yMTguODNDMzAzLjc1LC0yMDguOTQgMzE3LjUyLC0xOTUuNTUgMzI5LjAzLC0xODQuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMzMxLjQ3LC0xODYuODcgMzM2LjIsLTE3Ny4zOCAzMjYuNTksLTE4MS44NSAzMzEuNDcsLTE4Ni44NyIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0wLCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjA8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTEsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTAsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0xLCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0wLCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE4OC4xOSwtMTQ4LjgxQzE3MSwtMTM3LjY3IDE0NS4zOCwtMTIxLjA2IDEyNi4wMSwtMTA4LjUiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTI3Ljg5LC0xMDUuNTYgMTE3LjYsLTEwMy4wNSAxMjQuMDgsLTExMS40MyAxMjcuODksLTEwNS41NiIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0yLCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyMDciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MjwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9MiwgcmFuaz0wKSAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTIsIHJhbms9MCk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjA3LC0xNDMuN0MyMDcsLTEzNS45OCAyMDcsLTEyNi43MSAyMDcsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyMTAuNSwtMTE4LjEgMjA3LC0xMDguMSAyMDMuNSwtMTE4LjEgMjEwLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTQsIHJhbms9MCkgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+Tm9kZSh2YWx1ZT00LCByYW5rPTApPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIzNTEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjM1MSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NDwvdGV4dD4KPC9nPgo8IS0tIG5pbDYgLS0+CjxnIGlkPSJub2RlMTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT00LCByYW5rPTApJiM0NTsmZ3Q7bmlsNiAtLT4KPGcgaWQ9ImVkZ2UxMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT00LCByYW5rPTApJiM0NTsmZ3Q7bmlsNjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zNDIuNjUsLTcyLjc2QzMzOC4yOSwtNjQuMjggMzMyLjg1LC01My43MSAzMjcuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMzMwLjk5LC00Mi40NCAzMjMuMywtMzUuMTUgMzI0Ljc3LC00NS42NCAzMzAuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBuaWw3IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw3PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjM4NyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDcgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDc8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMzU5LjM1LC03Mi43NkMzNjMuNzEsLTY0LjI4IDM2OS4xNSwtNTMuNzEgMzc0LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjM3Ny4yMywtNDUuNjQgMzc4LjcsLTM1LjE1IDM3MS4wMSwtNDIuNDQgMzc3LjIzLC00NS42NCIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT03LCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iNDU5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI0NTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjc8L3RleHQ+CjwvZz4KPCEtLSBuaWw4IC0tPgo8ZyBpZD0ibm9kZTE0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjQ1OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0O25pbDggLS0+CjxnIGlkPSJlZGdlMTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0O25pbDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNDU5LC03MS43QzQ1OSwtNjMuOTggNDU5LC01NC43MSA0NTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjQ2Mi41LC00Ni4xIDQ1OSwtMzYuMSA0NTUuNSwtNDYuMSA0NjIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gbmlsOSAtLT4KPGcgaWQ9Im5vZGUxNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsOTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI1MzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw5IC0tPgo8ZyBpZD0iZWRnZTE0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw5PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTQ3My41NywtNzQuODNDNDgzLjc1LC02NC45NCA0OTcuNTIsLTUxLjU1IDUwOS4wMywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iNTExLjQ3LC00Mi44NyA1MTYuMiwtMzMuMzggNTA2LjU5LC0zNy44NSA1MTEuNDcsLTQyLjg3Ii8+CjwvZz4KPCEtLSBuaWwyIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwyIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTc0LjgzQzc0LjI1LC02NC45NCA2MC40OCwtNTEuNTUgNDguOTcsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjUxLjQxLC0zNy44NSA0MS44LC0zMy4zOCA0Ni41MywtNDIuODcgNTEuNDEsLTM3Ljg1Ii8+CjwvZz4KPCEtLSBuaWwzIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDM8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwzIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDM8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTcxLjdDOTksLTYzLjk4IDk5LC01NC43MSA5OSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTQ2LjEgOTksLTM2LjEgOTUuNSwtNDYuMSAxMDIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gbmlsNCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw0IC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTk4LjY1LC03Mi43NkMxOTQuMjksLTY0LjI4IDE4OC44NSwtNTMuNzEgMTgzLjk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE4Ni45OSwtNDIuNDQgMTc5LjMsLTM1LjE1IDE4MC43NywtNDUuNjQgMTg2Ljk5LC00Mi40NCIvPgo8L2c+CjwhLS0gbmlsNSAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNDMiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw1IC0tPgo8ZyBpZD0iZWRnZTEwIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw1PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIxNS4zNSwtNzIuNzZDMjE5LjcxLC02NC4yOCAyMjUuMTUsLTUzLjcxIDIzMC4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyMzMuMjMsLTQ1LjY0IDIzNC43LC0zNS4xNSAyMjcuMDEsLTQyLjQ0IDIzMy4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9NCwgcmFuaz0wKSAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTQsIHJhbms9MCk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMzUxLC0xNDMuN0MzNTEsLTEzNS45OCAzNTEsLTEyNi43MSAzNTEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzNTQuNSwtMTE4LjEgMzUxLC0xMDguMSAzNDcuNSwtMTE4LjEgMzU0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTcsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT01LCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT03LCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0zNjkuODEsLTE0OC44MUMzODcsLTEzNy42NyA0MTIuNjIsLTEyMS4wNiA0MzEuOTksLTEwOC41Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSI0MzMuOTIsLTExMS40MyA0NDAuNCwtMTAzLjA1IDQzMC4xMSwtMTA1LjU2IDQzMy45MiwtMTExLjQzIi8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2815:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iNTY2cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgNTY2LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMjU2IDU2MiwtMjU2IDU2Miw0IC00LDQiLz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjI3OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3OSIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MzwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjIwNyIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MywgcmFuaz0yKSYjNDU7Jmd0O05vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjY0LjQzLC0yMTguODNDMjU0LjI1LC0yMDguOTQgMjQwLjQ4LC0xOTUuNTUgMjI4Ljk3LC0xODQuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjMxLjQxLC0xODEuODUgMjIxLjgsLTE3Ny4zOCAyMjYuNTMsLTE4Ni44NyAyMzEuNDEsLTE4MS44NSIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT01LCByYW5rPTEpIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9NSwgcmFuaz0xKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIzNTEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIzNTEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTUsIHJhbms9MSkgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT01LCByYW5rPTEpPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI5My41NywtMjE4LjgzQzMwMy43NSwtMjA4Ljk0IDMxNy41MiwtMTk1LjU1IDMyOS4wMywtMTg0LjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMzMS40NywtMTg2Ljg3IDMzNi4yLC0xNzcuMzggMzI2LjU5LC0xODEuODUgMzMxLjQ3LC0xODYuODciLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MCwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTAsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjA8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTEsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTAsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0xLCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0wLCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE4OC4xOSwtMTQ4LjgxQzE3MSwtMTM3LjY3IDE0NS4zOCwtMTIxLjA2IDEyNi4wMSwtMTA4LjUiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTI3Ljg5LC0xMDUuNTYgMTE3LjYsLTEwMy4wNSAxMjQuMDgsLTExMS40MyAxMjcuODksLTEwNS41NiIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0yLCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyMDciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0xLCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0yLCByYW5rPTApIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9MiwgcmFuaz0wKTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMDcsLTE0My43QzIwNywtMTM1Ljk4IDIwNywtMTI2LjcxIDIwNywtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMC41LC0xMTguMSAyMDcsLTEwOC4xIDIwMy41LC0xMTguMSAyMTAuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTQsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjM1MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzUxIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjQ8L3RleHQ+CjwvZz4KPCEtLSBuaWw2IC0tPgo8ZyBpZD0ibm9kZTEyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjMxNSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDYgLS0+CjxnIGlkPSJlZGdlMTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDY8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzQyLjY1LC03Mi43NkMzMzguMjksLTY0LjI4IDMzMi44NSwtNTMuNzEgMzI3Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMzMC45OSwtNDIuNDQgMzIzLjMsLTM1LjE1IDMyNC43NywtNDUuNjQgMzMwLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gbmlsNyAtLT4KPGcgaWQ9Im5vZGUxMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNzwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIzODciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTQsIHJhbms9MCkmIzQ1OyZndDtuaWw3IC0tPgo8ZyBpZD0iZWRnZTEyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTQsIHJhbms9MCkmIzQ1OyZndDtuaWw3PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTM1OS4zNSwtNzIuNzZDMzYzLjcxLC02NC4yOCAzNjkuMTUsLTUzLjcxIDM3NC4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNzcuMjMsLTQ1LjY0IDM3OC43LC0zNS4xNSAzNzEuMDEsLTQyLjQ0IDM3Ny4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NywgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTcsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjQ1OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNDU5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjc8L3RleHQ+CjwvZz4KPCEtLSBuaWw4IC0tPgo8ZyBpZD0ibm9kZTE0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjQ1OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0O25pbDggLS0+CjxnIGlkPSJlZGdlMTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0O25pbDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNDU5LC03MS43QzQ1OSwtNjMuOTggNDU5LC01NC43MSA0NTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjQ2Mi41LC00Ni4xIDQ1OSwtMzYuMSA0NTUuNSwtNDYuMSA0NjIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gbmlsOSAtLT4KPGcgaWQ9Im5vZGUxNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsOTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI1MzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw5IC0tPgo8ZyBpZD0iZWRnZTE0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw5PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTQ3My41NywtNzQuODNDNDgzLjc1LC02NC45NCA0OTcuNTIsLTUxLjU1IDUwOS4wMywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTExLjQ3LC00Mi44NyA1MTYuMiwtMzMuMzggNTA2LjU5LC0zNy44NSA1MTEuNDcsLTQyLjg3Ii8+CjwvZz4KPCEtLSBuaWwyIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwyIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNODQuNDMsLTc0LjgzQzc0LjI1LC02NC45NCA2MC40OCwtNTEuNTUgNDguOTcsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjUxLjQxLC0zNy44NSA0MS44LC0zMy4zOCA0Ni41MywtNDIuODcgNTEuNDEsLTM3Ljg1Ii8+CjwvZz4KPCEtLSBuaWwzIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDM8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwzIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDM8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTcxLjdDOTksLTYzLjk4IDk5LC01NC43MSA5OSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTQ2LjEgOTksLTM2LjEgOTUuNSwtNDYuMSAxMDIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gbmlsNCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw0IC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTk4LjY1LC03Mi43NkMxOTQuMjksLTY0LjI4IDE4OC44NSwtNTMuNzEgMTgzLjk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE4Ni45OSwtNDIuNDQgMTc5LjMsLTM1LjE1IDE4MC43NywtNDUuNjQgMTg2Ljk5LC00Mi40NCIvPgo8L2c+CjwhLS0gbmlsNSAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNDMiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw1IC0tPgo8ZyBpZD0iZWRnZTEwIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw1PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTIxNS4zNSwtNzIuNzZDMjE5LjcxLC02NC4yOCAyMjUuMTUsLTUzLjcxIDIzMC4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyMzMuMjMsLTQ1LjY0IDIzNC43LC0zNS4xNSAyMjcuMDEsLTQyLjQ0IDIzMy4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9NCwgcmFuaz0wKSAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTQsIHJhbms9MCk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzUxLC0xNDMuN0MzNTEsLTEzNS45OCAzNTEsLTEyNi43MSAzNTEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNTQuNSwtMTE4LjEgMzUxLC0xMDguMSAzNDcuNSwtMTE4LjEgMzU0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTcsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT01LCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT03LCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0zNjkuODEsLTE0OC44MUMzODcsLTEzNy42NyA0MTIuNjIsLTEyMS4wNiA0MzEuOTksLTEwOC41Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iNDMzLjkyLC0xMTEuNDMgNDQwLjQsLTEwMy4wNSA0MzAuMTEsLTEwNS41NiA0MzMuOTIsLTExMS40MyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},9183:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/incorrect_dark-d9c04aed74f7d364c3c3b1855b769ab0.svg"},8800:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iNjAycHQiIGhlaWdodD0iMzMycHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgNjAyLjAwIDMzMi4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzMjgpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzI4IDU5OCwtMzI4IDU5OCw0IC00LDQiLz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjI3OSIgY3k9Ii0zMDYiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3OSIgeT0iLTMwMi4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MzwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjIyNSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIyNSIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MywgcmFuaz0yKSYjNDU7Jmd0O05vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjY3LjAyLC0yODkuNDZDMjYwLjAyLC0yODAuNCAyNTEuMDYsLTI2OC43OSAyNDMuMjEsLTI1OC42MSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNDUuODMsLTI1Ni4yNyAyMzYuOTUsLTI1MC40OSAyNDAuMjksLTI2MC41NSAyNDUuODMsLTI1Ni4yNyIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT01LCByYW5rPTEpIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9NSwgcmFuaz0xKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIzMzMiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIzMzMiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTUsIHJhbms9MSkgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT01LCByYW5rPTEpPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI5MC45OCwtMjg5LjQ2QzI5Ny45OCwtMjgwLjQgMzA2Ljk0LC0yNjguNzkgMzE0Ljc5LC0yNTguNjEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzE3LjcxLC0yNjAuNTUgMzIxLjA1LC0yNTAuNDkgMzEyLjE3LC0yNTYuMjcgMzE3LjcxLC0yNjAuNTUiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MCwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTAsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MDwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9MCwgcmFuaz0wKSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTAsIHJhbms9MCk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjA0Ljc2LC0yMjEuNzVDMTg0LC0yMTAuMjIgMTUxLjUyLC0xOTIuMTggMTI4LjAyLC0xNzkuMTIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTI5LjY0LC0xNzYuMDIgMTE5LjE5LC0xNzQuMjIgMTI2LjI0LC0xODIuMTMgMTI5LjY0LC0xNzYuMDIiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MiwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTIsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjI1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjI1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0xLCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0yLCByYW5rPTApIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9MiwgcmFuaz0wKTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMjUsLTIxNS43QzIyNSwtMjA3Ljk4IDIyNSwtMTk4LjcxIDIyNSwtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyOC41LC0xOTAuMSAyMjUsLTE4MC4xIDIyMS41LC0xOTAuMSAyMjguNSwtMTkwLjEiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTQsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjMzMyIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMzMyIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NDwvdGV4dD4KPC9nPgo8IS0tIG5pbDYgLS0+CjxnIGlkPSJub2RlMTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT00LCByYW5rPTApJiM0NTsmZ3Q7bmlsNiAtLT4KPGcgaWQ9ImVkZ2UxMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT00LCByYW5rPTApJiM0NTsmZ3Q7bmlsNjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMjguNjQsLTE0NC4wNUMzMjYuNjEsLTEzNi4xNCAzMjQuMTQsLTEyNi41NCAzMjEuODYsLTExNy42OSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzMjUuMiwtMTE2LjYgMzE5LjMyLC0xMDcuNzkgMzE4LjQyLC0xMTguMzUgMzI1LjIsLTExNi42Ii8+CjwvZz4KPCEtLSBuaWw3IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw3PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjM4NyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDcgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDc8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzQ0Ljk4LC0xNDUuNDZDMzUxLjk4LC0xMzYuNCAzNjAuOTQsLTEyNC43OSAzNjguNzksLTExNC42MSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNzEuNzEsLTExNi41NSAzNzUuMDUsLTEwNi40OSAzNjYuMTcsLTExMi4yNyAzNzEuNzEsLTExNi41NSIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT03LCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iNDU5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNDU5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj43PC90ZXh0Pgo8L2c+CjwhLS0gbmlsOCAtLT4KPGcgaWQ9Im5vZGUxNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI0NTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw4IC0tPgo8ZyBpZD0iZWRnZTEzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTQ1OSwtMTQzLjdDNDU5LC0xMzUuOTggNDU5LC0xMjYuNzEgNDU5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNDYyLjUsLTExOC4xIDQ1OSwtMTA4LjEgNDU1LjUsLTExOC4xIDQ2Mi41LC0xMTguMSIvPgo8L2c+CjwhLS0gOCAtLT4KPGcgaWQ9Im5vZGUxNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iNTMxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI1MzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+ODwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0OzggLS0+CjxnIGlkPSJlZGdlMTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0Ozg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTQ3My41NywtMTQ2LjgzQzQ4My43NSwtMTM2Ljk0IDQ5Ny41MiwtMTIzLjU1IDUwOS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iNTExLjQ3LC0xMTQuODcgNTE2LjIsLTEwNS4zOCA1MDYuNTksLTEwOS44NSA1MTEuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gbmlsMiAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWwyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0wLCByYW5rPTApJiM0NTsmZ3Q7bmlsMiAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBuaWwzIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDM8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwzIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDM8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBuaWw0IC0tPgo8ZyBpZD0ibm9kZTEwIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDQgLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0yLCByYW5rPTApJiM0NTsmZ3Q7bmlsNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMTMuMDIsLTE0NS40NkMyMDYuMDIsLTEzNi40IDE5Ny4wNiwtMTI0Ljc5IDE4OS4yMSwtMTE0LjYxIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE5MS44MywtMTEyLjI3IDE4Mi45NSwtMTA2LjQ5IDE4Ni4yOSwtMTE2LjU1IDE5MS44MywtMTEyLjI3Ii8+CjwvZz4KPCEtLSBuaWw1IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw1PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDUgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDU8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjI5LjM2LC0xNDQuMDVDMjMxLjM5LC0xMzYuMTQgMjMzLjg2LC0xMjYuNTQgMjM2LjE0LC0xMTcuNjkiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjM5LjU4LC0xMTguMzUgMjM4LjY4LC0xMDcuNzkgMjMyLjgsLTExNi42IDIzOS41OCwtMTE4LjM1Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTQsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT01LCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT00LCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTMzMywtMjE1LjdDMzMzLC0yMDcuOTggMzMzLC0xOTguNzEgMzMzLC0xOTAuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzM2LjUsLTE5MC4xIDMzMywtMTgwLjEgMzI5LjUsLTE5MC4xIDMzNi41LC0xOTAuMSIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT01LCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT03LCByYW5rPTApIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9NywgcmFuaz0wKTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMzUzLjI0LC0yMjEuNzVDMzc0LC0yMTAuMjIgNDA2LjQ4LC0xOTIuMTggNDI5Ljk4LC0xNzkuMTIiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSI0MzEuNzYsLTE4Mi4xMyA0MzguODEsLTE3NC4yMiA0MjguMzYsLTE3Ni4wMiA0MzEuNzYsLTE4Mi4xMyIvPgo8L2c+CjwhLS0gbmlsOSAtLT4KPGcgaWQ9Im5vZGUxNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsOTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI0OTUiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBuaWwxMCAtLT4KPGcgaWQ9Im5vZGUxNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsMTA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iNTY3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gOCYjNDU7Jmd0O25pbDkgLS0+CjxnIGlkPSJlZGdlMTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjgmIzQ1OyZndDtuaWw5PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTUyMi42NSwtNzIuNzZDNTE4LjI5LC02NC4yOCA1MTIuODUsLTUzLjcxIDUwNy45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MTAuOTksLTQyLjQ0IDUwMy4zLC0zNS4xNSA1MDQuNzcsLTQ1LjY0IDUxMC45OSwtNDIuNDQiLz4KPC9nPgo8IS0tIDgmIzQ1OyZndDtuaWwxMCAtLT4KPGcgaWQ9ImVkZ2UxNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+OCYjNDU7Jmd0O25pbDEwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTUzOS4zNSwtNzIuNzZDNTQzLjcxLC02NC4yOCA1NDkuMTUsLTUzLjcxIDU1NC4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1NTcuMjMsLTQ1LjY0IDU1OC43LC0zNS4xNSA1NTEuMDEsLTQyLjQ0IDU1Ny4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},4241:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjEzNHB0IiBoZWlnaHQ9IjExNnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDEzNC4wMCAxMTYuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTEyKSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTExMiAxMzAsLTExMiAxMzAsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTU0LjY1LC03Mi43NkM1MC4yOSwtNjQuMjggNDQuODUsLTUzLjcxIDM5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjQyLjk5LC00Mi40NCAzNS4zLC0zNS4xNSAzNi43NywtNDUuNjQgNDIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNzEuMzUsLTcyLjc2Qzc1LjcxLC02NC4yOCA4MS4xNSwtNTMuNzEgODYuMDQsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iODkuMjMsLTQ1LjY0IDkwLjcsLTM1LjE1IDgzLjAxLC00Mi40NCA4OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},5018:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjEzNHB0IiBoZWlnaHQ9IjExNnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDEzNC4wMCAxMTYuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTEyKSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xMTIgMTMwLC0xMTIgMTMwLDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iNjMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjYzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTU0LjY1LC03Mi43NkM1MC4yOSwtNjQuMjggNDQuODUsLTUzLjcxIDM5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjQyLjk5LC00Mi40NCAzNS4zLC0zNS4xNSAzNi43NywtNDUuNjQgNDIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuMzUsLTcyLjc2Qzc1LjcxLC02NC4yOCA4MS4xNSwtNTMuNzEgODYuMDQsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iODkuMjMsLTQ1LjY0IDkwLjcsLTM1LjE1IDgzLjAxLC00Mi40NCA4OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},9232:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjE3MHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDE3MC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTE4NCAxNjYsLTE4NCAxNjYsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik05MC42NSwtMTQ0Ljc2Qzg2LjI5LC0xMzYuMjggODAuODUsLTEyNS43MSA3NS45NiwtMTE2LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9Ijc4Ljk5LC0xMTQuNDQgNzEuMywtMTA3LjE1IDcyLjc3LC0xMTcuNjQgNzguOTksLTExNC40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjEzNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMDcuMzUsLTE0NC43NkMxMTEuNzEsLTEzNi4yOCAxMTcuMTUsLTEyNS43MSAxMjIuMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEyNS4yMywtMTE3LjY0IDEyNi43LC0xMDcuMTUgMTE5LjAxLC0xMTQuNDQgMTI1LjIzLC0xMTcuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O0wxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},8491:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjE3MHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDE3MC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xODQgMTY2LC0xODQgMTY2LDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NTwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTkwLjY1LC0xNDQuNzZDODYuMjksLTEzNi4yOCA4MC44NSwtMTI1LjcxIDc1Ljk2LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9Ijc4Ljk5LC0xMTQuNDQgNzEuMywtMTA3LjE1IDcyLjc3LC0xMTcuNjQgNzguOTksLTExNC40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjEzNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMDcuMzUsLTE0NC43NkMxMTEuNzEsLTEzNi4yOCAxMTcuMTUsLTEyNS43MSAxMjIuMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEyNS4yMywtMTE3LjY0IDEyNi43LC0xMDcuMTUgMTE5LjAxLC0xMTQuNDQgMTI1LjIzLC0xMTcuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O0wxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},3559:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjI3OHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDI3OC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTE4NCAyNzQsLTE4NCAyNzQsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTI2LjY1LC0xNDQuNzZDMTIyLjI5LC0xMzYuMjggMTE2Ljg1LC0xMjUuNzEgMTExLjk2LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTE0Ljk5LC0xMTQuNDQgMTA3LjMsLTEwNy4xNSAxMDguNzcsLTExNy42NCAxMTQuOTksLTExNC40NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTQzLjM1LC0xNDQuNzZDMTQ3LjcxLC0xMzYuMjggMTUzLjE1LC0xMjUuNzEgMTU4LjA0LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTYxLjIzLC0xMTcuNjQgMTYyLjcsLTEwNy4xNSAxNTUuMDEsLTExNC40NCAxNjEuMjMsLTExNy42NCIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtMMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC03MS43QzE3MSwtNjMuOTggMTcxLC01NC43MSAxNzEsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC00Ni4xIDE3MSwtMzYuMSAxNjcuNSwtNDYuMSAxNzQuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xODUuNTcsLTc0LjgzQzE5NS43NSwtNjQuOTQgMjA5LjUyLC01MS41NSAyMjEuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMy40NywtNDIuODcgMjI4LjIsLTMzLjM4IDIxOC41OSwtMzcuODUgMjIzLjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},4485:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjI3OHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDI3OC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xODQgMjc0LC0xODQgMjc0LDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xMjYuNjUsLTE0NC43NkMxMjIuMjksLTEzNi4yOCAxMTYuODUsLTEyNS43MSAxMTEuOTYsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTE0Ljk5LC0xMTQuNDQgMTA3LjMsLTEwNy4xNSAxMDguNzcsLTExNy42NCAxMTQuOTksLTExNC40NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xNDMuMzUsLTE0NC43NkMxNDcuNzEsLTEzNi4yOCAxNTMuMTUsLTEyNS43MSAxNTguMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTYxLjIzLC0xMTcuNjQgMTYyLjcsLTEwNy4xNSAxNTUuMDEsLTExNC40NCAxNjEuMjMsLTExNy42NCIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtMMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC03MS43QzE3MSwtNjMuOTggMTcxLC01NC43MSAxNzEsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC00Ni4xIDE3MSwtMzYuMSAxNjcuNSwtNDYuMSAxNzQuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xODUuNTcsLTc0LjgzQzE5NS43NSwtNjQuOTQgMjA5LjUyLC01MS41NSAyMjEuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMy40NywtNDIuODcgMjI4LjIsLTMzLjM4IDIxOC41OSwtMzcuODUgMjIzLjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},9034:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiAzMTAsLTI1NiAzMTAsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NTwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNDMuMzUsLTIxNi43NkMxNDcuNzEsLTIwOC4yOCAxNTMuMTUsLTE5Ny43MSAxNTguMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE2MS4yMywtMTg5LjY0IDE2Mi43LC0xNzkuMTUgMTU1LjAxLC0xODYuNDQgMTYxLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O0wxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjUxLjQxLC0xMDkuODUgNDEuOCwtMTA1LjM4IDQ2LjUzLC0xMTQuODcgNTEuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC0xNDMuN0M5OSwtMTM1Ljk4IDk5LC0xMjYuNzEgOTksLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMDIuNSwtMTE4LjEgOTksLTEwOC4xIDk1LjUsLTExOC4xIDEwMi41LC0xMTguMSIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xODwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMjMuNDcsLTExNC44NyAyMjguMiwtMTA1LjM4IDIxOC41OSwtMTA5Ljg1IDIyMy40NywtMTE0Ljg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjA3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIzNC42NSwtNzIuNzZDMjMwLjI5LC02NC4yOCAyMjQuODUsLTUzLjcxIDIxOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyMjIuOTksLTQyLjQ0IDIxNS4zLC0zNS4xNSAyMTYuNzcsLTQ1LjY0IDIyMi45OSwtNDIuNDQiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlOSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjUxLjM1LC03Mi43NkMyNTUuNzEsLTY0LjI4IDI2MS4xNSwtNTMuNzEgMjY2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjI2OS4yMywtNDUuNjQgMjcwLjcsLTM1LjE1IDI2My4wMSwtNDIuNDQgMjY5LjIzLC00NS42NCIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},3037:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMzEwLC0yNTYgMzEwLDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMjYuNjUsLTIxNi43NkMxMjIuMjksLTIwOC4yOCAxMTYuODUsLTE5Ny43MSAxMTEuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjExNC45OSwtMTg2LjQ0IDEwNy4zLC0xNzkuMTUgMTA4Ljc3LC0xODkuNjQgMTE0Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTQzLjM1LC0yMTYuNzZDMTQ3LjcxLC0yMDguMjggMTUzLjE1LC0xOTcuNzEgMTU4LjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNjEuMjMsLTE4OS42NCAxNjIuNywtMTc5LjE1IDE1NS4wMSwtMTg2LjQ0IDE2MS4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtMMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O0wxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNODQuNDMsLTE0Ni44M0M3NC4yNSwtMTM2Ljk0IDYwLjQ4LC0xMjMuNTUgNDguOTcsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xODwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjIzLjQ3LC0xMTQuODcgMjI4LjIsLTEwNS4zOCAyMTguNTksLTEwOS44NSAyMjMuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMzQuNjUsLTcyLjc2QzIzMC4yOSwtNjQuMjggMjI0Ljg1LC01My43MSAyMTkuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjIyLjk5LC00Mi40NCAyMTUuMywtMzUuMTUgMjE2Ljc3LC00NS42NCAyMjIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjc5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},4236:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiAzMTAsLTI1NiAzMTAsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NTwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNDMuMzUsLTIxNi43NkMxNDcuNzEsLTIwOC4yOCAxNTMuMTUsLTE5Ny43MSAxNTguMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE2MS4yMywtMTg5LjY0IDE2Mi43LC0xNzkuMTUgMTU1LjAxLC0xODYuNDQgMTYxLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MjwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDsxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjUxLjQxLC0xMDkuODUgNDEuOCwtMTA1LjM4IDQ2LjUzLC0xMTQuODcgNTEuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC0xNDMuN0M5OSwtMTM1Ljk4IDk5LC0xMjYuNzEgOTksLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMDIuNSwtMTE4LjEgOTksLTEwOC4xIDk1LjUsLTExOC4xIDEwMi41LC0xMTguMSIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI3LC03MS43QzI3LC02My45OCAyNywtNTQuNzEgMjcsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjMwLjUsLTQ2LjEgMjcsLTM2LjEgMjMuNSwtNDYuMSAzMC41LC00Ni4xIi8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNDEuNTcsLTc0LjgzQzUxLjc1LC02NC45NCA2NS41MiwtNTEuNTUgNzcuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9Ijc5LjQ3LC00Mi44NyA4NC4yLC0zMy4zOCA3NC41OSwtMzcuODUgNzkuNDcsLTQyLjg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE3MSwtMTQzLjdDMTcxLC0xMzUuOTggMTcxLC0xMjYuNzEgMTcxLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTc0LjUsLTExOC4xIDE3MSwtMTA4LjEgMTY3LjUsLTExOC4xIDE3NC41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE4PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTg1LjU3LC0xNDYuODNDMTk1Ljc1LC0xMzYuOTQgMjA5LjUyLC0xMjMuNTUgMjIxLjAzLC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjIyMy40NywtMTE0Ljg3IDIyOC4yLC0xMDUuMzggMjE4LjU5LC0xMDkuODUgMjIzLjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTAiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjA3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIzNC42NSwtNzIuNzZDMjMwLjI5LC02NC4yOCAyMjQuODUsLTUzLjcxIDIxOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyMjIuOTksLTQyLjQ0IDIxNS4zLC0zNS4xNSAyMTYuNzcsLTQ1LjY0IDIyMi45OSwtNDIuNDQiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjc5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNTEuMzUsLTcyLjc2QzI1NS43MSwtNjQuMjggMjYxLjE1LC01My43MSAyNjYuMDQsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjY5LjIzLC00NS42NCAyNzAuNywtMzUuMTUgMjYzLjAxLC00Mi40NCAyNjkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},4961:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMzEwLC0yNTYgMzEwLDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMjYuNjUsLTIxNi43NkMxMjIuMjksLTIwOC4yOCAxMTYuODUsLTE5Ny43MSAxMTEuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjExNC45OSwtMTg2LjQ0IDEwNy4zLC0xNzkuMTUgMTA4Ljc3LC0xODkuNjQgMTE0Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTQzLjM1LC0yMTYuNzZDMTQ3LjcxLC0yMDguMjggMTUzLjE1LC0xOTcuNzEgMTU4LjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNjEuMjMsLTE4OS42NCAxNjIuNywtMTc5LjE1IDE1NS4wMSwtMTg2LjQ0IDE2MS4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MjwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDsxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNywtNzEuN0MyNywtNjMuOTggMjcsLTU0LjcxIDI3LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzMC41LC00Ni4xIDI3LC0zNi4xIDIzLjUsLTQ2LjEgMzAuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTQxLjU3LC03NC44M0M1MS43NSwtNjQuOTQgNjUuNTIsLTUxLjU1IDc3LjAzLC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI3OS40NywtNDIuODcgODQuMiwtMzMuMzggNzQuNTksLTM3Ljg1IDc5LjQ3LC00Mi44NyIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGU5IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjE4PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTg1LjU3LC0xNDYuODNDMTk1Ljc1LC0xMzYuOTQgMjA5LjUyLC0xMjMuNTUgMjIxLjAzLC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMjMuNDcsLTExNC44NyAyMjguMiwtMTA1LjM4IDIxOC41OSwtMTA5Ljg1IDIyMy40NywtMTE0Ljg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTEwIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMzQuNjUsLTcyLjc2QzIzMC4yOSwtNjQuMjggMjI0Ljg1LC01My43MSAyMTkuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjIyLjk5LC00Mi40NCAyMTUuMywtMzUuMTUgMjE2Ljc3LC00NS42NCAyMjIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjUxLjM1LC03Mi43NkMyNTUuNzEsLTY0LjI4IDI2MS4xNSwtNTMuNzEgMjY2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjI2OS4yMywtNDUuNjQgMjcwLjcsLTM1LjE1IDI2My4wMSwtNDIuNDQgMjY5LjIzLC00NS42NCIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},376:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiA0MTgsLTI1NiA0MTgsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyMDciIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyMDciIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xOTguNjUsLTIxNi43NkMxOTQuMjksLTIwOC4yOCAxODguODUsLTE5Ny43MSAxODMuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE4Ni45OSwtMTg2LjQ0IDE3OS4zLC0xNzkuMTUgMTgwLjc3LC0xODkuNjQgMTg2Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTM5MiAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDUzOTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMjQzIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDUzOTIgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjA1MzkyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIxNS4zNSwtMjE2Ljc2QzIxOS43MSwtMjA4LjI4IDIyNS4xNSwtMTk3LjcxIDIzMC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjMzLjIzLC0xODkuNjQgMjM0LjcsLTE3OS4xNSAyMjcuMDEsLTE4Ni40NCAyMzMuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4yPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTU2LjQzLC0xNDYuODNDMTQ2LjI1LC0xMzYuOTQgMTMyLjQ4LC0xMjMuNTUgMTIwLjk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjEyMy40MSwtMTA5Ljg1IDExMy44LC0xMDUuMzggMTE4LjUzLC0xMTQuODcgMTIzLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTc0LjgzQzc0LjI1LC02NC45NCA2MC40OCwtNTEuNTUgNDguOTcsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjUxLjQxLC0zNy44NSA0MS44LC0zMy4zOCA0Ni41MywtNDIuODcgNTEuNDEsLTM3Ljg1Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTcxLjdDOTksLTYzLjk4IDk5LC01NC43MSA5OSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTQ2LjEgOTksLTM2LjEgOTUuNSwtNDYuMSAxMDIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjQzLC0xNDMuN0MyNDMsLTEzNS45OCAyNDMsLTEyNi43MSAyNDMsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjQ2LjUsLTExOC4xIDI0MywtMTA4LjEgMjM5LjUsLTExOC4xIDI0Ni41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjMxNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzE1IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xODwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0yNTcuNTcsLTE0Ni44M0MyNjcuNzUsLTEzNi45NCAyODEuNTIsLTEyMy41NSAyOTMuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjk1LjQ3LC0xMTQuODcgMzAwLjIsLTEwNS4zOCAyOTAuNTksLTEwOS44NSAyOTUuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU5IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlOCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yMjguNDMsLTc0LjgzQzIxOC4yNSwtNjQuOTQgMjA0LjQ4LC01MS41NSAxOTIuOTcsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE5NS40MSwtMzcuODUgMTg1LjgsLTMzLjM4IDE5MC41MywtNDIuODcgMTk1LjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNDMiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjQzLC03MS43QzI0MywtNjMuOTggMjQzLC01NC43MSAyNDMsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjI0Ni41LC00Ni4xIDI0MywtMzYuMSAyMzkuNSwtNDYuMSAyNDYuNSwtNDYuMSIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIzMTUiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTMxNSwtNzEuN0MzMTUsLTYzLjk4IDMxNSwtNTQuNzEgMzE1LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzMTguNSwtNDYuMSAzMTUsLTM2LjEgMzExLjUsLTQ2LjEgMzE4LjUsLTQ2LjEiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMjkuNTcsLTc0LjgzQzMzOS43NSwtNjQuOTQgMzUzLjUyLC01MS41NSAzNjUuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjM2Ny40NywtNDIuODcgMzcyLjIsLTMzLjM4IDM2Mi41OSwtMzcuODUgMzY3LjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},6061:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgNDE4LC0yNTYgNDE4LDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjA3IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjA3IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE5OC42NSwtMjE2Ljc2QzE5NC4yOSwtMjA4LjI4IDE4OC44NSwtMTk3LjcxIDE4My45NiwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTg2Ljk5LC0xODYuNDQgMTc5LjMsLTE3OS4xNSAxODAuNzcsLTE4OS42NCAxODYuOTksLTE4Ni40NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNDMiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjE1PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjA1MzkyIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwNTM5MjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMTUuMzUsLTIxNi43NkMyMTkuNzEsLTIwOC4yOCAyMjUuMTUsLTE5Ny43MSAyMzAuMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIzMy4yMywtMTg5LjY0IDIzNC43LC0xNzkuMTUgMjI3LjAxLC0xODYuNDQgMjMzLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTU2LjQzLC0xNDYuODNDMTQ2LjI1LC0xMzYuOTQgMTMyLjQ4LC0xMjMuNTUgMTIwLjk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIxMjMuNDEsLTEwOS44NSAxMTMuOCwtMTA1LjM4IDExOC41MywtMTE0Ljg3IDEyMy40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE3MSwtMTQzLjdDMTcxLC0xMzUuOTggMTcxLC0xMjYuNzEgMTcxLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTc0LjUsLTExOC4xIDE3MSwtMTA4LjEgMTY3LjUsLTExOC4xIDE3NC41LC0xMTguMSIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjQzLC0xNDMuN0MyNDMsLTEzNS45OCAyNDMsLTEyNi43MSAyNDMsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjI0Ni41LC0xMTguMSAyNDMsLTEwOC4xIDIzOS41LC0xMTguMSAyNDYuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIzMTUiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMxNSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xODwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0yNTcuNTcsLTE0Ni44M0MyNjcuNzUsLTEzNi45NCAyODEuNTIsLTEyMy41NSAyOTMuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjI5NS40NywtMTE0Ljg3IDMwMC4yLC0xMDUuMzggMjkwLjU5LC0xMDkuODUgMjk1LjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlOSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjI4LjQzLC03NC44M0MyMTguMjUsLTY0Ljk0IDIwNC40OCwtNTEuNTUgMTkyLjk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxOTUuNDEsLTM3Ljg1IDE4NS44LC0zMy4zOCAxOTAuNTMsLTQyLjg3IDE5NS40MSwtMzcuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlMTAiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjQzIiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtSMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI0MywtNzEuN0MyNDMsLTYzLjk4IDI0MywtNTQuNzEgMjQzLC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNDYuNSwtNDYuMSAyNDMsLTM2LjEgMjM5LjUsLTQ2LjEgMjQ2LjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMTUsLTcxLjdDMzE1LC02My45OCAzMTUsLTU0LjcxIDMxNSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzE4LjUsLTQ2LjEgMzE1LC0zNi4xIDMxMS41LC00Ni4xIDMxOC41LC00Ni4xIi8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjM4NyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzI5LjU3LC03NC44M0MzMzkuNzUsLTY0Ljk0IDM1My41MiwtNTEuNTUgMzY1LjAzLC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNjcuNDcsLTQyLjg3IDM3Mi4yLC0zMy4zOCAzNjIuNTksLTM3Ljg1IDM2Ny40NywtNDIuODciLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},9010:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjMzMnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAzMzIuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMzI4KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTMyOCA0MTgsLTMyOCA0MTgsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyMDciIGN5PSItMzA2IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyMDciIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xOTguNjUsLTI4OC43NkMxOTQuMjksLTI4MC4yOCAxODguODUsLTI2OS43MSAxODMuOTYsLTI2MC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE4Ni45OSwtMjU4LjQ0IDE3OS4zLC0yNTEuMTUgMTgwLjc3LC0yNjEuNjQgMTg2Ljk5LC0yNTguNDQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTM5MiAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDUzOTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE1PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjA1MzkyIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwNTM5MjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjE1LjM1LC0yODguNzZDMjE5LjcxLC0yODAuMjggMjI1LjE1LC0yNjkuNzEgMjMwLjA0LC0yNjAuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjMzLjIzLC0yNjEuNjQgMjM0LjcsLTI1MS4xNSAyMjcuMDEsLTI1OC40NCAyMzMuMjMsLTI2MS42NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDsxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xNTYuNDMsLTIxOC44M0MxNDYuMjUsLTIwOC45NCAxMzIuNDgsLTE5NS41NSAxMjAuOTcsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTIzLjQxLC0xODEuODUgMTEzLjgsLTE3Ny4zOCAxMTguNTMsLTE4Ni44NyAxMjMuNDEsLTE4MS44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC0yMTUuN0MxNzEsLTIwNy45OCAxNzEsLTE5OC43MSAxNzEsLTE5MC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNzQuNSwtMTkwLjEgMTcxLC0xODAuMSAxNjcuNSwtMTkwLjEgMTc0LjUsLTE5MC4xIi8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTE0Ni44M0M3NC4yNSwtMTM2Ljk0IDYwLjQ4LC0xMjMuNTUgNDguOTcsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMjQzIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDUzOTImIzQ1OyZndDsxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI0MywtMjE1LjdDMjQzLC0yMDcuOTggMjQzLC0xOTguNzEgMjQzLC0xOTAuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjQ2LjUsLTE5MC4xIDI0MywtMTgwLjEgMjM5LjUsLTE5MC4xIDI0Ni41LC0xOTAuMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMzE1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzE1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDUzOTImIzQ1OyZndDsxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNTcuNTcsLTIxOC44M0MyNjcuNzUsLTIwOC45NCAyODEuNTIsLTE5NS41NSAyOTMuMDMsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyOTUuNDcsLTE4Ni44NyAzMDAuMiwtMTc3LjM4IDI5MC41OSwtMTgxLjg1IDI5NS40NywtMTg2Ljg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIyOC40MywtMTQ2LjgzQzIxOC4yNSwtMTM2Ljk0IDIwNC40OCwtMTIzLjU1IDE5Mi45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE5NS40MSwtMTA5Ljg1IDE4NS44LC0xMDUuMzggMTkwLjUzLC0xMTQuODcgMTk1LjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTM8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDU2MDU0NTYgLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7MTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0yNDMsLTE0My43QzI0MywtMTM1Ljk4IDI0MywtMTI2LjcxIDI0MywtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjA1NDU2IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTQ1NiYjNDU7Jmd0O0wxNDAzOTk4MDU2MDU0NTYgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTQ1NiYjNDU7Jmd0O0wxNDAzOTk4MDU2MDU0NTY8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTYwNTQ1NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDU0NTYmIzQ1OyZndDtSMTQwMzk5ODA1NjA1NDU2IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDU0NTYmIzQ1OyZndDtSMTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMTUsLTE0My43QzMxNSwtMTM1Ljk4IDMxNSwtMTI2LjcxIDMxNSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjMxOC41LC0xMTguMSAzMTUsLTEwOC4xIDMxMS41LC0xMTguMSAzMTguNSwtMTE4LjEiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMjkuNTcsLTE0Ni44M0MzMzkuNzUsLTEzNi45NCAzNTMuNTIsLTEyMy41NSAzNjUuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzNjcuNDcsLTExNC44NyAzNzIuMiwtMTA1LjM4IDM2Mi41OSwtMTA5Ljg1IDM2Ny40NywtMTE0Ljg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},7115:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjMzMnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAzMzIuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMzI4KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0zMjggNDE4LC0zMjggNDE4LDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjA3IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjA3IiB5PSItMzAyLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE5OC42NSwtMjg4Ljc2QzE5NC4yOSwtMjgwLjI4IDE4OC44NSwtMjY5LjcxIDE4My45NiwtMjYwLjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTg2Ljk5LC0yNTguNDQgMTc5LjMsLTI1MS4xNSAxODAuNzcsLTI2MS42NCAxODYuOTksLTI1OC40NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xNTwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwNTM5MiAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDUzOTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTIxNS4zNSwtMjg4Ljc2QzIxOS43MSwtMjgwLjI4IDIyNS4xNSwtMjY5LjcxIDIzMC4wNCwtMjYwLjIiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMzMuMjMsLTI2MS42NCAyMzQuNywtMjUxLjE1IDIyNy4wMSwtMjU4LjQ0IDIzMy4yMywtMjYxLjY0Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTU2LjQzLC0yMTguODNDMTQ2LjI1LC0yMDguOTQgMTMyLjQ4LC0xOTUuNTUgMTIwLjk3LC0xODQuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIxMjMuNDEsLTE4MS44NSAxMTMuOCwtMTc3LjM4IDExOC41MywtMTg2Ljg3IDEyMy40MSwtMTgxLjg1Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzEsLTIxNS43QzE3MSwtMjA3Ljk4IDE3MSwtMTk4LjcxIDE3MSwtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC0xOTAuMSAxNzEsLTE4MC4xIDE2Ny41LC0xOTAuMSAxNzQuNSwtMTkwLjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjUxLjQxLC0xMDkuODUgNDEuOCwtMTA1LjM4IDQ2LjUzLC0xMTQuODcgNTEuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC0xNDMuN0M5OSwtMTM1Ljk4IDk5LC0xMjYuNzEgOTksLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMDIuNSwtMTE4LjEgOTksLTEwOC4xIDk1LjUsLTExOC4xIDEwMi41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNDMiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNDMsLTIxNS43QzI0MywtMjA3Ljk4IDI0MywtMTk4LjcxIDI0MywtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjI0Ni41LC0xOTAuMSAyNDMsLTE4MC4xIDIzOS41LC0xOTAuMSAyNDYuNSwtMTkwLjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGUxMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjMxNSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMxNSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDUzOTImIzQ1OyZndDsxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNTcuNTcsLTIxOC44M0MyNjcuNzUsLTIwOC45NCAyODEuNTIsLTE5NS41NSAyOTMuMDMsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyOTUuNDcsLTE4Ni44NyAzMDAuMiwtMTc3LjM4IDI5MC41OSwtMTgxLjg1IDI5NS40NywtMTg2Ljg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTIyOC40MywtMTQ2LjgzQzIxOC4yNSwtMTM2Ljk0IDIwNC40OCwtMTIzLjU1IDE5Mi45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE5NS40MSwtMTA5Ljg1IDE4NS44LC0xMDUuMzggMTkwLjUzLC0xMTQuODcgMTk1LjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMzwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDU2MDU0NTY8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTI0MywtMTQzLjdDMjQzLC0xMzUuOTggMjQzLC0xMjYuNzEgMjQzLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjA1NDU2IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTQ1NiYjNDU7Jmd0O0wxNDAzOTk4MDU2MDU0NTYgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTQ1NiYjNDU7Jmd0O0wxNDAzOTk4MDU2MDU0NTY8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTYwNTQ1NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDU0NTYmIzQ1OyZndDtSMTQwMzk5ODA1NjA1NDU2IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDU0NTYmIzQ1OyZndDtSMTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMTUsLTE0My43QzMxNSwtMTM1Ljk4IDMxNSwtMTI2LjcxIDMxNSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMxOC41LC0xMTguMSAzMTUsLTEwOC4xIDMxMS41LC0xMTguMSAzMTguNSwtMTE4LjEiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMjkuNTcsLTE0Ni44M0MzMzkuNzUsLTEzNi45NCAzNTMuNTIsLTEyMy41NSAzNjUuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNjcuNDcsLTExNC44NyAzNzIuMiwtMTA1LjM4IDM2Mi41OSwtMTA5Ljg1IDM2Ny40NywtMTE0Ljg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2399:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/br_7_dark-48445480725921bc67664cac9f225476.svg"},7239:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/br_7_light-e3494c1dc9b1d352580427c76be40a01.svg"},2705:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/br_8_dark-e63a22ae61187d5745542c84a04ded26.svg"},1461:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/br_8_light-10d25c55c1838a408ab5dad21a9da058.svg"},3591:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjEzNHB0IiBoZWlnaHQ9IjExNnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDEzNC4wMCAxMTYuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTEyKSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTExMiAxMzAsLTExMiAxMzAsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iNjMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjYzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xMjwvdGV4dD4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtSMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2227:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjEzNHB0IiBoZWlnaHQ9IjExNnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDEzNC4wMCAxMTYuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTEyKSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xMTIgMTMwLC0xMTIgMTMwLDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjYzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI2MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMjwvdGV4dD4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtSMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},7690:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjE3MHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDE3MC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTE4NCAxNjYsLTE4NCAxNjYsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik05MC42NSwtMTQ0Ljc2Qzg2LjI5LC0xMzYuMjggODAuODUsLTEyNS43MSA3NS45NiwtMTE2LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9Ijc4Ljk5LC0xMTQuNDQgNzEuMywtMTA3LjE1IDcyLjc3LC0xMTcuNjQgNzguOTksLTExNC40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjEzNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMDcuMzUsLTE0NC43NkMxMTEuNzEsLTEzNi4yOCAxMTcuMTUsLTEyNS43MSAxMjIuMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEyNS4yMywtMTE3LjY0IDEyNi43LC0xMDcuMTUgMTE5LjAxLC0xMTQuNDQgMTI1LjIzLC0xMTcuNjQiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O0wxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},6805:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjE3MHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDE3MC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xODQgMTY2LC0xODQgMTY2LDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTkwLjY1LC0xNDQuNzZDODYuMjksLTEzNi4yOCA4MC44NSwtMTI1LjcxIDc1Ljk2LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9Ijc4Ljk5LC0xMTQuNDQgNzEuMywtMTA3LjE1IDcyLjc3LC0xMTcuNjQgNzguOTksLTExNC40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjEzNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMDcuMzUsLTE0NC43NkMxMTEuNzEsLTEzNi4yOCAxMTcuMTUsLTEyNS43MSAxMjIuMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEyNS4yMywtMTE3LjY0IDEyNi43LC0xMDcuMTUgMTE5LjAxLC0xMTQuNDQgMTI1LjIzLC0xMTcuNjQiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O0wxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},9861:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjI3OHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDI3OC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTE4NCAyNzQsLTE4NCAyNzQsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTI2LjY1LC0xNDQuNzZDMTIyLjI5LC0xMzYuMjggMTE2Ljg1LC0xMjUuNzEgMTExLjk2LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTE0Ljk5LC0xMTQuNDQgMTA3LjMsLTEwNy4xNSAxMDguNzcsLTExNy42NCAxMTQuOTksLTExNC40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTQzLjM1LC0xNDQuNzZDMTQ3LjcxLC0xMzYuMjggMTUzLjE1LC0xMjUuNzEgMTU4LjA0LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTYxLjIzLC0xMTcuNjQgMTYyLjcsLTEwNy4xNSAxNTUuMDEsLTExNC40NCAxNjEuMjMsLTExNy42NCIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtMMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC03MS43QzE3MSwtNjMuOTggMTcxLC01NC43MSAxNzEsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC00Ni4xIDE3MSwtMzYuMSAxNjcuNSwtNDYuMSAxNzQuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xODUuNTcsLTc0LjgzQzE5NS43NSwtNjQuOTQgMjA5LjUyLC01MS41NSAyMjEuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMy40NywtNDIuODcgMjI4LjIsLTMzLjM4IDIxOC41OSwtMzcuODUgMjIzLjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},7676:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjI3OHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDI3OC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xODQgMjc0LC0xODQgMjc0LDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xMjYuNjUsLTE0NC43NkMxMjIuMjksLTEzNi4yOCAxMTYuODUsLTEyNS43MSAxMTEuOTYsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTE0Ljk5LC0xMTQuNDQgMTA3LjMsLTEwNy4xNSAxMDguNzcsLTExNy42NCAxMTQuOTksLTExNC40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xNDMuMzUsLTE0NC43NkMxNDcuNzEsLTEzNi4yOCAxNTMuMTUsLTEyNS43MSAxNTguMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTYxLjIzLC0xMTcuNjQgMTYyLjcsLTEwNy4xNSAxNTUuMDEsLTExNC40NCAxNjEuMjMsLTExNy42NCIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtMMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC03MS43QzE3MSwtNjMuOTggMTcxLC01NC43MSAxNzEsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC00Ni4xIDE3MSwtMzYuMSAxNjcuNSwtNDYuMSAxNzQuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xODUuNTcsLTc0LjgzQzE5NS43NSwtNjQuOTQgMjA5LjUyLC01MS41NSAyMjEuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMy40NywtNDIuODcgMjI4LjIsLTMzLjM4IDIxOC41OSwtMzcuODUgMjIzLjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},4110:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiAzMTAsLTI1NiAzMTAsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTEyNi42NSwtMjE2Ljc2QzEyMi4yOSwtMjA4LjI4IDExNi44NSwtMTk3LjcxIDExMS45NiwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTE0Ljk5LC0xODYuNDQgMTA3LjMsLTE3OS4xNSAxMDguNzcsLTE4OS42NCAxMTQuOTksLTE4Ni40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTQzLjM1LC0yMTYuNzZDMTQ3LjcxLC0yMDguMjggMTUzLjE1LC0xOTcuNzEgMTU4LjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNjEuMjMsLTE4OS42NCAxNjIuNywtMTc5LjE1IDE1NS4wMSwtMTg2LjQ0IDE2MS4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtMMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O0wxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTE0Ni44M0M3NC4yNSwtMTM2Ljk0IDYwLjQ4LC0xMjMuNTUgNDguOTcsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xODUuNTcsLTE0Ni44M0MxOTUuNzUsLTEzNi45NCAyMDkuNTIsLTEyMy41NSAyMjEuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjIzLjQ3LC0xMTQuODcgMjI4LjIsLTEwNS4zOCAyMTguNTksLTEwOS44NSAyMjMuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yMzQuNjUsLTcyLjc2QzIzMC4yOSwtNjQuMjggMjI0Ljg1LC01My43MSAyMTkuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjIyLjk5LC00Mi40NCAyMTUuMywtMzUuMTUgMjE2Ljc3LC00NS42NCAyMjIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjc5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},7632:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMzEwLC0yNTYgMzEwLDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjEzNSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjEzNSIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE0My4zNSwtMjE2Ljc2QzE0Ny43MSwtMjA4LjI4IDE1My4xNSwtMTk3LjcxIDE1OC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYxLjIzLC0xODkuNjQgMTYyLjcsLTE3OS4xNSAxNTUuMDEsLTE4Ni40NCAxNjEuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtMMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE3MSwtMTQzLjdDMTcxLC0xMzUuOTggMTcxLC0xMjYuNzEgMTcxLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTc0LjUsLTExOC4xIDE3MSwtMTA4LjEgMTY3LjUsLTExOC4xIDE3NC41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xODUuNTcsLTE0Ni44M0MxOTUuNzUsLTEzNi45NCAyMDkuNTIsLTEyMy41NSAyMjEuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjIyMy40NywtMTE0Ljg3IDIyOC4yLC0xMDUuMzggMjE4LjU5LC0xMDkuODUgMjIzLjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyMDciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtMMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGU5IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlOCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNTEuMzUsLTcyLjc2QzI1NS43MSwtNjQuMjggMjYxLjE1LC01My43MSAyNjYuMDQsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjY5LjIzLC00NS42NCAyNzAuNywtMzUuMTUgMjYzLjAxLC00Mi40NCAyNjkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},9418:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiAzMTAsLTI1NiAzMTAsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTEyNi42NSwtMjE2Ljc2QzEyMi4yOSwtMjA4LjI4IDExNi44NSwtMTk3LjcxIDExMS45NiwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTE0Ljk5LC0xODYuNDQgMTA3LjMsLTE3OS4xNSAxMDguNzcsLTE4OS42NCAxMTQuOTksLTE4Ni40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTQzLjM1LC0yMTYuNzZDMTQ3LjcxLC0yMDguMjggMTUzLjE1LC0xOTcuNzEgMTU4LjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNjEuMjMsLTE4OS42NCAxNjIuNywtMTc5LjE1IDE1NS4wMSwtMTg2LjQ0IDE2MS4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNywtNzEuN0MyNywtNjMuOTggMjcsLTU0LjcxIDI3LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzMC41LC00Ni4xIDI3LC0zNi4xIDIzLjUsLTQ2LjEgMzAuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtSMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTQxLjU3LC03NC44M0M1MS43NSwtNjQuOTQgNjUuNTIsLTUxLjU1IDc3LjAzLC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI3OS40NywtNDIuODcgODQuMiwtMzMuMzggNzQuNTksLTM3Ljg1IDc5LjQ3LC00Mi44NyIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGU5IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xODwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMjMuNDcsLTExNC44NyAyMjguMiwtMTA1LjM4IDIxOC41OSwtMTA5Ljg1IDIyMy40NywtMTE0Ljg3Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTEwIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yMzQuNjUsLTcyLjc2QzIzMC4yOSwtNjQuMjggMjI0Ljg1LC01My43MSAyMTkuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjIyLjk5LC00Mi40NCAyMTUuMywtMzUuMTUgMjE2Ljc3LC00NS42NCAyMjIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjUxLjM1LC03Mi43NkMyNTUuNzEsLTY0LjI4IDI2MS4xNSwtNTMuNzEgMjY2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjI2OS4yMywtNDUuNjQgMjcwLjcsLTM1LjE1IDI2My4wMSwtNDIuNDQgMjY5LjIzLC00NS42NCIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},7109:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMzEwLC0yNTYgMzEwLDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjEzNSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjEzNSIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE0My4zNSwtMjE2Ljc2QzE0Ny43MSwtMjA4LjI4IDE1My4xNSwtMTk3LjcxIDE1OC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYxLjIzLC0xODkuNjQgMTYyLjcsLTE3OS4xNSAxNTUuMDEsLTE4Ni40NCAxNjEuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtMMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjcsLTcxLjdDMjcsLTYzLjk4IDI3LC01NC43MSAyNywtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzAuNSwtNDYuMSAyNywtMzYuMSAyMy41LC00Ni4xIDMwLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik00MS41NywtNzQuODNDNTEuNzUsLTY0Ljk0IDY1LjUyLC01MS41NSA3Ny4wMywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNzkuNDcsLTQyLjg3IDg0LjIsLTMzLjM4IDc0LjU5LC0zNy44NSA3OS40NywtNDIuODciLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlOSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xODwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjIzLjQ3LC0xMTQuODcgMjI4LjIsLTEwNS4zOCAyMTguNTksLTEwOS44NSAyMjMuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyMDciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtMMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0iZWRnZTEwIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},3533:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiA0MTgsLTI1NiA0MTgsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjA3IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjA3IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTk4LjY1LC0yMTYuNzZDMTk0LjI5LC0yMDguMjggMTg4Ljg1LC0xOTcuNzEgMTgzLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxODYuOTksLTE4Ni40NCAxNzkuMywtMTc5LjE1IDE4MC43NywtMTg5LjY0IDE4Ni45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQgLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkzNDI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI0MyIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE1PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkzNDI0IC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yMTUuMzUsLTIxNi43NkMyMTkuNzEsLTIwOC4yOCAyMjUuMTUsLTE5Ny43MSAyMzAuMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIzMy4yMywtMTg5LjY0IDIzNC43LC0xNzkuMTUgMjI3LjAxLC0xODYuNDQgMjMzLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0OzEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE1Ni40MywtMTQ2LjgzQzE0Ni4yNSwtMTM2Ljk0IDEzMi40OCwtMTIzLjU1IDEyMC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIxMjMuNDEsLTEwOS44NSAxMTMuOCwtMTA1LjM4IDExOC41MywtMTE0Ljg3IDEyMy40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE3MSwtMTQzLjdDMTcxLC0xMzUuOTggMTcxLC0xMjYuNzEgMTcxLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTc0LjUsLTExOC4xIDE3MSwtMTA4LjEgMTY3LjUsLTExOC4xIDE3NC41LC0xMTguMSIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7TDEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtMMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtSMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTI0MywtMTQzLjdDMjQzLC0xMzUuOTggMjQzLC0xMjYuNzEgMjQzLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjI0Ni41LC0xMTguMSAyNDMsLTEwOC4xIDIzOS41LC0xMTguMSAyNDYuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIzMTUiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMxNSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjU3LjU3LC0xNDYuODNDMjY3Ljc1LC0xMzYuOTQgMjgxLjUyLC0xMjMuNTUgMjkzLjAzLC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjI5NS40NywtMTE0Ljg3IDMwMC4yLC0xMDUuMzggMjkwLjU5LC0xMDkuODUgMjk1LjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlOSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjI4LjQzLC03NC44M0MyMTguMjUsLTY0Ljk0IDIwNC40OCwtNTEuNTUgMTkyLjk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxOTUuNDEsLTM3Ljg1IDE4NS44LC0zMy4zOCAxOTAuNTMsLTQyLjg3IDE5NS40MSwtMzcuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlMTAiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjQzIiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtSMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI0MywtNzEuN0MyNDMsLTYzLjk4IDI0MywtNTQuNzEgMjQzLC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyNDYuNSwtNDYuMSAyNDMsLTM2LjEgMjM5LjUsLTQ2LjEgMjQ2LjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMTUsLTcxLjdDMzE1LC02My45OCAzMTUsLTU0LjcxIDMxNSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMzE4LjUsLTQ2LjEgMzE1LC0zNi4xIDMxMS41LC00Ni4xIDMxOC41LC00Ni4xIi8+CjwvZz4KPCEtLSBSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjM4NyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMzI5LjU3LC03NC44M0MzMzkuNzUsLTY0Ljk0IDM1My41MiwtNTEuNTUgMzY1LjAzLC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzNjcuNDcsLTQyLjg3IDM3Mi4yLC0zMy4zOCAzNjIuNTksLTM3Ljg1IDM2Ny40NywtNDIuODciLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8998:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgNDE4LC0yNTYgNDE4LDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjIwNyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xOTguNjUsLTIxNi43NkMxOTQuMjksLTIwOC4yOCAxODguODUsLTE5Ny43MSAxODMuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE4Ni45OSwtMTg2LjQ0IDE3OS4zLC0xNzkuMTUgMTgwLjc3LC0xODkuNjQgMTg2Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQyNCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjQzIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xNTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQyNCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTM0MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjE1LjM1LC0yMTYuNzZDMjE5LjcxLC0yMDguMjggMjI1LjE1LC0xOTcuNzEgMjMwLjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyMzMuMjMsLTE4OS42NCAyMzQuNywtMTc5LjE1IDIyNy4wMSwtMTg2LjQ0IDIzMy4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0OzEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE1Ni40MywtMTQ2LjgzQzE0Ni4yNSwtMTM2Ljk0IDEzMi40OCwtMTIzLjU1IDEyMC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTIzLjQxLC0xMDkuODUgMTEzLjgsLTEwNS4zOCAxMTguNTMsLTExNC44NyAxMjMuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtNzQuODNDNzQuMjUsLTY0Ljk0IDYwLjQ4LC01MS41NSA0OC45NywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTM3Ljg1IDQxLjgsLTMzLjM4IDQ2LjUzLC00Mi44NyA1MS40MSwtMzcuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtNzEuN0M5OSwtNjMuOTggOTksLTU0LjcxIDk5LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMDIuNSwtNDYuMSA5OSwtMzYuMSA5NS41LC00Ni4xIDEwMi41LC00Ni4xIi8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTI0MywtMTQzLjdDMjQzLC0xMzUuOTggMjQzLC0xMjYuNzEgMjQzLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIzMTUiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjU3LjU3LC0xNDYuODNDMjY3Ljc1LC0xMzYuOTQgMjgxLjUyLC0xMjMuNTUgMjkzLjAzLC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyOTUuNDcsLTExNC44NyAzMDAuMiwtMTA1LjM4IDI5MC41OSwtMTA5Ljg1IDI5NS40NywtMTE0Ljg3Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTIyOC40MywtNzQuODNDMjE4LjI1LC02NC45NCAyMDQuNDgsLTUxLjU1IDE5Mi45NywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTk1LjQxLC0zNy44NSAxODUuOCwtMzMuMzggMTkwLjUzLC00Mi44NyAxOTUuNDEsLTM3Ljg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTEwIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNDMsLTcxLjdDMjQzLC02My45OCAyNDMsLTU0LjcxIDI0MywtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjQ2LjUsLTQ2LjEgMjQzLC0zNi4xIDIzOS41LC00Ni4xIDI0Ni41LC00Ni4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTEyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjMxNSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzE1LC03MS43QzMxNSwtNjMuOTggMzE1LC01NC43MSAzMTUsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMxOC41LC00Ni4xIDMxNSwtMzYuMSAzMTEuNSwtNDYuMSAzMTguNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIzODciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0iZWRnZTEyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTMyOS41NywtNzQuODNDMzM5Ljc1LC02NC45NCAzNTMuNTIsLTUxLjU1IDM2NS4wMywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzY3LjQ3LC00Mi44NyAzNzIuMiwtMzMuMzggMzYyLjU5LC0zNy44NSAzNjcuNDcsLTQyLjg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},4269:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjMzMnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAzMzIuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMzI4KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTMyOCA0MTgsLTMyOCA0MTgsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyMDciIGN5PSItMzA2IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyMDciIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xOTguNjUsLTI4OC43NkMxOTQuMjksLTI4MC4yOCAxODguODUsLTI2OS43MSAxODMuOTYsLTI2MC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE4Ni45OSwtMjU4LjQ0IDE3OS4zLC0yNTEuMTUgMTgwLjc3LC0yNjEuNjQgMTg2Ljk5LC0yNTguNDQiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQyNCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE1PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkzNDI0IC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjE1LjM1LC0yODguNzZDMjE5LjcxLC0yODAuMjggMjI1LjE1LC0yNjkuNzEgMjMwLjA0LC0yNjAuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjMzLjIzLC0yNjEuNjQgMjM0LjcsLTI1MS4xNSAyMjcuMDEsLTI1OC40NCAyMzMuMjMsLTI2MS42NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xNTYuNDMsLTIxOC44M0MxNDYuMjUsLTIwOC45NCAxMzIuNDgsLTE5NS41NSAxMjAuOTcsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTIzLjQxLC0xODEuODUgMTEzLjgsLTE3Ny4zOCAxMTguNTMsLTE4Ni44NyAxMjMuNDEsLTE4MS44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC0yMTUuN0MxNzEsLTIwNy45OCAxNzEsLTE5OC43MSAxNzEsLTE5MC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNzQuNSwtMTkwLjEgMTcxLC0xODAuMSAxNjcuNSwtMTkwLjEgMTc0LjUsLTE5MC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtMMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTE0Ni44M0M3NC4yNSwtMTM2Ljk0IDYwLjQ4LC0xMjMuNTUgNDguOTcsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMjQzIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkzNDI0JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI0MywtMjE1LjdDMjQzLC0yMDcuOTggMjQzLC0xOTguNzEgMjQzLC0xOTAuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjQ2LjUsLTE5MC4xIDI0MywtMTgwLjEgMjM5LjUsLTE5MC4xIDI0Ni41LC0xOTAuMSIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMzE1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzE1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNTcuNTcsLTIxOC44M0MyNjcuNzUsLTIwOC45NCAyODEuNTIsLTE5NS41NSAyOTMuMDMsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyOTUuNDcsLTE4Ni44NyAzMDAuMiwtMTc3LjM4IDI5MC41OSwtMTgxLjg1IDI5NS40NywtMTg2Ljg3Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIyOC40MywtMTQ2LjgzQzIxOC4yNSwtMTM2Ljk0IDIwNC40OCwtMTIzLjU1IDE5Mi45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE5NS40MSwtMTA5Ljg1IDE4NS44LC0xMDUuMzggMTkwLjUzLC0xMTQuODcgMTk1LjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTM8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU3OTM0ODggLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7MTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0yNDMsLTE0My43QzI0MywtMTM1Ljk4IDI0MywtMTI2LjcxIDI0MywtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkzNDg4IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQ4OCYjNDU7Jmd0O0wxMzk2NjA0MzU3OTM0ODggLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQ4OCYjNDU7Jmd0O0wxMzk2NjA0MzU3OTM0ODg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTc5MzQ4ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0ODgmIzQ1OyZndDtSMTM5NjYwNDM1NzkzNDg4IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0ODgmIzQ1OyZndDtSMTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMTUsLTE0My43QzMxNSwtMTM1Ljk4IDMxNSwtMTI2LjcxIDMxNSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjMxOC41LC0xMTguMSAzMTUsLTEwOC4xIDMxMS41LC0xMTguMSAzMTguNSwtMTE4LjEiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMjkuNTcsLTE0Ni44M0MzMzkuNzUsLTEzNi45NCAzNTMuNTIsLTEyMy41NSAzNjUuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzNjcuNDcsLTExNC44NyAzNzIuMiwtMTA1LjM4IDM2Mi41OSwtMTA5Ljg1IDM2Ny40NywtMTE0Ljg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2366:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjMzMnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAzMzIuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMzI4KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0zMjggNDE4LC0zMjggNDE4LDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjA3IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjA3IiB5PSItMzAyLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE5OC42NSwtMjg4Ljc2QzE5NC4yOSwtMjgwLjI4IDE4OC44NSwtMjY5LjcxIDE4My45NiwtMjYwLjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTg2Ljk5LC0yNTguNDQgMTc5LjMsLTI1MS4xNSAxODAuNzcsLTI2MS42NCAxODYuOTksLTI1OC40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkzNDI0IC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xNTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQyNCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTM0MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTIxNS4zNSwtMjg4Ljc2QzIxOS43MSwtMjgwLjI4IDIyNS4xNSwtMjY5LjcxIDIzMC4wNCwtMjYwLjIiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMzMuMjMsLTI2MS42NCAyMzQuNywtMjUxLjE1IDIyNy4wMSwtMjU4LjQ0IDIzMy4yMywtMjYxLjY0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7MTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0OzEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTU2LjQzLC0yMTguODNDMTQ2LjI1LC0yMDguOTQgMTMyLjQ4LC0xOTUuNTUgMTIwLjk3LC0xODQuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIxMjMuNDEsLTE4MS44NSAxMTMuOCwtMTc3LjM4IDExOC41MywtMTg2Ljg3IDEyMy40MSwtMTgxLjg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzEsLTIxNS43QzE3MSwtMjA3Ljk4IDE3MSwtMTk4LjcxIDE3MSwtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC0xOTAuMSAxNzEsLTE4MC4xIDE2Ny41LC0xOTAuMSAxNzQuNSwtMTkwLjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjUxLjQxLC0xMDkuODUgNDEuOCwtMTA1LjM4IDQ2LjUzLC0xMTQuODcgNTEuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtSMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC0xNDMuN0M5OSwtMTM1Ljk4IDk5LC0xMjYuNzEgOTksLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMDIuNSwtMTE4LjEgOTksLTEwOC4xIDk1LjUsLTExOC4xIDEwMi41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNDMiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkzNDI0JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNDMsLTIxNS43QzI0MywtMjA3Ljk4IDI0MywtMTk4LjcxIDI0MywtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjI0Ni41LC0xOTAuMSAyNDMsLTE4MC4xIDIzOS41LC0xOTAuMSAyNDYuNSwtMTkwLjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjMxNSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMxNSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNTcuNTcsLTIxOC44M0MyNjcuNzUsLTIwOC45NCAyODEuNTIsLTE5NS41NSAyOTMuMDMsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyOTUuNDcsLTE4Ni44NyAzMDAuMiwtMTc3LjM4IDI5MC41OSwtMTgxLjg1IDI5NS40NywtMTg2Ljg3Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTIyOC40MywtMTQ2LjgzQzIxOC4yNSwtMTM2Ljk0IDIwNC40OCwtMTIzLjU1IDE5Mi45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE5NS40MSwtMTA5Ljg1IDE4NS44LC0xMDUuMzggMTkwLjUzLC0xMTQuODcgMTk1LjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMzwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU3OTM0ODg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTI0MywtMTQzLjdDMjQzLC0xMzUuOTggMjQzLC0xMjYuNzEgMjQzLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkzNDg4IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQ4OCYjNDU7Jmd0O0wxMzk2NjA0MzU3OTM0ODggLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQ4OCYjNDU7Jmd0O0wxMzk2NjA0MzU3OTM0ODg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTc5MzQ4ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0ODgmIzQ1OyZndDtSMTM5NjYwNDM1NzkzNDg4IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0ODgmIzQ1OyZndDtSMTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMTUsLTE0My43QzMxNSwtMTM1Ljk4IDMxNSwtMTI2LjcxIDMxNSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMxOC41LC0xMTguMSAzMTUsLTEwOC4xIDMxMS41LC0xMTguMSAzMTguNSwtMTE4LjEiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMjkuNTcsLTE0Ni44M0MzMzkuNzUsLTEzNi45NCAzNTMuNTIsLTEyMy41NSAzNjUuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNjcuNDcsLTExNC44NyAzNzIuMiwtMTA1LjM4IDM2Mi41OSwtMTA5Ljg1IDM2Ny40NywtMTE0Ljg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},122:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rr_7_dark-f8796e7eda13a89d198098744b079384.svg"},3927:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rr_7_light-f03b9073d10947b0af1a226ee8e12fa4.svg"},2476:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rr_8_dark-f1562f7fd1dc9442e496260e74447d03.svg"},5509:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rr_8_light-7531279bbbb44b4e206fe5040b38df4d.svg"}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3184],{3905:(I,M,i)=>{i.d(M,{Zo:()=>c,kt:()=>m});var N=i(7294);function T(I,M,i){return M in I?Object.defineProperty(I,M,{value:i,enumerable:!0,configurable:!0,writable:!0}):I[M]=i,I}function g(I,M){var i=Object.keys(I);if(Object.getOwnPropertySymbols){var N=Object.getOwnPropertySymbols(I);M&&(N=N.filter((function(M){return Object.getOwnPropertyDescriptor(I,M).enumerable}))),i.push.apply(i,N)}return i}function j(I){for(var M=1;M=0||(T[i]=I[i]);return T}(I,M);if(Object.getOwnPropertySymbols){var g=Object.getOwnPropertySymbols(I);for(N=0;N=0||Object.prototype.propertyIsEnumerable.call(I,i)&&(T[i]=I[i])}return T}var Z=N.createContext({}),D=function(I){var M=N.useContext(Z),i=M;return I&&(i="function"==typeof I?I(M):j(j({},M),I)),i},c=function(I){var M=D(I.components);return N.createElement(Z.Provider,{value:M},I.children)},C="mdxType",l={inlineCode:"code",wrapper:function(I){var M=I.children;return N.createElement(N.Fragment,{},M)}},G=N.forwardRef((function(I,M){var i=I.components,T=I.mdxType,g=I.originalType,Z=I.parentName,c=z(I,["components","mdxType","originalType","parentName"]),C=D(i),G=T,m=C["".concat(Z,".").concat(G)]||C[G]||l[G]||g;return i?N.createElement(m,j(j({ref:M},c),{},{components:i})):N.createElement(m,j({ref:M},c))}));function m(I,M){var i=arguments,T=M&&M.mdxType;if("string"==typeof I||T){var g=i.length,j=new Array(g);j[0]=G;var z={};for(var Z in M)hasOwnProperty.call(M,Z)&&(z[Z]=M[Z]);z.originalType=I,z[C]="string"==typeof I?I:T,j[1]=z;for(var D=2;D{i.r(M),i.d(M,{assets:()=>k,contentTitle:()=>n,default:()=>Y,frontMatter:()=>y,metadata:()=>e,toc:()=>O});var N=i(7462),T=i(7294),g=i(3905),j=i(6010),z=i(2466),Z=i(6550),D=i(1980),c=i(7392),C=i(12);function l(I){return function(I){return T.Children.map(I,(I=>{if(!I||(0,T.isValidElement)(I)&&function(I){const{props:M}=I;return!!M&&"object"==typeof M&&"value"in M}(I))return I;throw new Error(`Docusaurus error: Bad child <${"string"==typeof I.type?I.type:I.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}(I).map((I=>{let{props:{value:M,label:i,attributes:N,default:T}}=I;return{value:M,label:i,attributes:N,default:T}}))}function G(I){const{values:M,children:i}=I;return(0,T.useMemo)((()=>{const I=M??l(i);return function(I){const M=(0,c.l)(I,((I,M)=>I.value===M.value));if(M.length>0)throw new Error(`Docusaurus error: Duplicate values "${M.map((I=>I.value)).join(", ")}" found in . Every value needs to be unique.`)}(I),I}),[M,i])}function m(I){let{value:M,tabValues:i}=I;return i.some((I=>I.value===M))}function b(I){let{queryString:M=!1,groupId:i}=I;const N=(0,Z.k6)(),g=function(I){let{queryString:M=!1,groupId:i}=I;if("string"==typeof M)return M;if(!1===M)return null;if(!0===M&&!i)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return i??null}({queryString:M,groupId:i});return[(0,D._X)(g),(0,T.useCallback)((I=>{if(!g)return;const M=new URLSearchParams(N.location.search);M.set(g,I),N.replace({...N.location,search:M.toString()})}),[g,N])]}function S(I){const{defaultValue:M,queryString:i=!1,groupId:N}=I,g=G(I),[j,z]=(0,T.useState)((()=>function(I){let{defaultValue:M,tabValues:i}=I;if(0===i.length)throw new Error("Docusaurus error: the component requires at least one children component");if(M){if(!m({value:M,tabValues:i}))throw new Error(`Docusaurus error: The has a defaultValue "${M}" but none of its children has the corresponding value. Available values are: ${i.map((I=>I.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return M}const N=i.find((I=>I.default))??i[0];if(!N)throw new Error("Unexpected error: 0 tabValues");return N.value}({defaultValue:M,tabValues:g}))),[Z,D]=b({queryString:i,groupId:N}),[c,l]=function(I){let{groupId:M}=I;const i=function(I){return I?`docusaurus.tab.${I}`:null}(M),[N,g]=(0,C.Nk)(i);return[N,(0,T.useCallback)((I=>{i&&g.set(I)}),[i,g])]}({groupId:N}),S=(()=>{const I=Z??c;return m({value:I,tabValues:g})?I:null})();(0,T.useLayoutEffect)((()=>{S&&z(S)}),[S]);return{selectedValue:j,selectValue:(0,T.useCallback)((I=>{if(!m({value:I,tabValues:g}))throw new Error(`Can't select invalid tab value=${I}`);z(I),D(I),l(I)}),[D,l,g]),tabValues:g}}var L=i(2389);const t={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function x(I){let{className:M,block:i,selectedValue:g,selectValue:Z,tabValues:D}=I;const c=[],{blockElementScrollPositionUntilNextRender:C}=(0,z.o5)(),l=I=>{const M=I.currentTarget,i=c.indexOf(M),N=D[i].value;N!==g&&(C(M),Z(N))},G=I=>{let M=null;switch(I.key){case"Enter":l(I);break;case"ArrowRight":{const i=c.indexOf(I.currentTarget)+1;M=c[i]??c[0];break}case"ArrowLeft":{const i=c.indexOf(I.currentTarget)-1;M=c[i]??c[c.length-1];break}}M?.focus()};return T.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,j.Z)("tabs",{"tabs--block":i},M)},D.map((I=>{let{value:M,label:i,attributes:z}=I;return T.createElement("li",(0,N.Z)({role:"tab",tabIndex:g===M?0:-1,"aria-selected":g===M,key:M,ref:I=>c.push(I),onKeyDown:G,onClick:l},z,{className:(0,j.Z)("tabs__item",t.tabItem,z?.className,{"tabs__item--active":g===M})}),i??M)})))}function w(I){let{lazy:M,children:i,selectedValue:N}=I;const g=(Array.isArray(i)?i:[i]).filter(Boolean);if(M){const I=g.find((I=>I.props.value===N));return I?(0,T.cloneElement)(I,{className:"margin-top--md"}):null}return T.createElement("div",{className:"margin-top--md"},g.map(((I,M)=>(0,T.cloneElement)(I,{key:M,hidden:I.props.value!==N}))))}function s(I){const M=S(I);return T.createElement("div",{className:(0,j.Z)("tabs-container",t.tabList)},T.createElement(x,(0,N.Z)({},I,M)),T.createElement(w,(0,N.Z)({},I,M)))}function P(I){const M=(0,L.Z)();return T.createElement(s,(0,N.Z)({key:String(M)},I))}const d={tabItem:"tabItem_Ymn6"};function a(I){let{children:M,hidden:i,className:N}=I;return T.createElement("div",{role:"tabpanel",className:(0,j.Z)(d.tabItem,N),hidden:i},M)}const y={id:"rules",title:"On the rules of the red-black tree",description:"Shower thoughts on the rules of the red-black tree.\n",tags:["red-black trees","balanced trees"],last_update:{date:new Date("2023-06-10T00:00:00.000Z")}},n=void 0,e={unversionedId:"rb-trees/rules",id:"rb-trees/rules",title:"On the rules of the red-black tree",description:"Shower thoughts on the rules of the red-black tree.\n",source:"@site/ib002/08-rb-trees/2023-06-10-rules.md",sourceDirName:"08-rb-trees",slug:"/rb-trees/rules",permalink:"/ib002/rb-trees/rules",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/08-rb-trees/2023-06-10-rules.md",tags:[{label:"red-black trees",permalink:"/ib002/tags/red-black-trees"},{label:"balanced trees",permalink:"/ib002/tags/balanced-trees"}],version:"current",lastUpdatedAt:1686355200,formattedLastUpdatedAt:"Jun 10, 2023",frontMatter:{id:"rules",title:"On the rules of the red-black tree",description:"Shower thoughts on the rules of the red-black tree.\n",tags:["red-black trees","balanced trees"],last_update:{date:"2023-06-10T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Pou\u017eit\xed \u010derveno-\u010dern\xfdch strom\u016f",permalink:"/ib002/rb-trees/applications"},next:{title:"Graphs",permalink:"/ib002/category/graphs"}},k={},O=[{value:"Introduction",id:"introduction",level:2},{value:"1\xaa Every node is either red or black.",id:"1\xaa-every-node-is-either-red-or-black",level:2},{value:"Do I really need the nodes to be explicitly colored?",id:"do-i-really-need-the-nodes-to-be-explicitly-colored",level:3},{value:"Black height",id:"black-height",level:4},{value:"Isomorphic trees",id:"isomorphic-trees",level:4},{value:"2\xaa The root is black.",id:"2\xaa-the-root-is-black",level:2},{value:"3\xaa Every leaf (nil) is black.",id:"3\xaa-every-leaf-nil-is-black",level:2},{value:"4\xaa If a node is red, then both its children are black.",id:"4\xaa-if-a-node-is-red-then-both-its-children-are-black",level:2},{value:"5\xaa For each node, all simple paths from the node to descendant leaves contain the same number of black nodes.",id:"5\xaa-for-each-node-all-simple-paths-from-the-node-to-descendant-leaves-contain-the-same-number-of-black-nodes",level:2}],u={toc:O},U="wrapper";function Y(I){let{components:M,...T}=I;return(0,g.kt)(U,(0,N.Z)({},u,T,{components:M,mdxType:"MDXLayout"}),(0,g.kt)("h2",{id:"introduction"},"Introduction"),(0,g.kt)("p",null,"Have you ever thought about the red-black tree rules in more depth? Why are they\nformulated the way they are? How come they keep the tree balanced? Let's go through\neach of the red-black tree rules and try to change, break and contemplate about\nthem."),(0,g.kt)("p",null,"We expect that you are familiar with the following set of the rules",(0,g.kt)("sup",{parentName:"p",id:"fnref-1"},(0,g.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),":"),(0,g.kt)("ol",null,(0,g.kt)("li",{parentName:"ol"},"Every node is either red or black."),(0,g.kt)("li",{parentName:"ol"},"The root is black."),(0,g.kt)("li",{parentName:"ol"},"Every leaf (",(0,g.kt)("inlineCode",{parentName:"li"},"nil"),") is black."),(0,g.kt)("li",{parentName:"ol"},"If a node is red, then both its children are black."),(0,g.kt)("li",{parentName:"ol"},"For each node, all simple paths from the node to descendant leaves contain the\nsame number of black nodes.")),(0,g.kt)("p",null,"Each section will go into ",(0,g.kt)("em",{parentName:"p"},"reasonable")," details of each rule."),(0,g.kt)("h2",{id:"1\xaa-every-node-is-either-red-or-black"},"1\xaa Every node is either red or black."),(0,g.kt)("p",null,"OK\u2026 This one is very simple. It is just a definition and is used in all other\nrules. Not much to talk about here. Or is there?"),(0,g.kt)("h3",{id:"do-i-really-need-the-nodes-to-be-explicitly-colored"},"Do I really need the nodes to be explicitly colored?"),(0,g.kt)("p",null,"The answer is no. Balancing of the red-black trees is \u201cenforced\u201d by the 4th and\n5th rule in the enumeration above. There are many ways you can avoid using colors."),(0,g.kt)("h4",{id:"black-height"},"Black height"),(0,g.kt)("p",null,"We mentioned the 4th and 5th rule and that it enforces the balancing. What does\nit mean for us?"),(0,g.kt)("p",null,"Well, we definitely do not have to use the colors, which even as a ",(0,g.kt)("em",{parentName:"p"},"boolean")," flag\nwould take at least 1 byte of space (and usually even more), cause\u2026 well, it is\neasier for the CPU to work with words rather than single bits."),(0,g.kt)("p",null,"We could use the black height, couldn't we? It would mean more memory used, cause\nit should be ideally big and unsigned. Can we tell the color of a node from the\nblack height? Of course we can, if my child has the same black height as I do,\nit means that there was no black node added on the path between us and therefore\nmy child would be colored red."),(0,g.kt)("p",null,"Example of a red-black tree that keeps count of black nodes on paths to the\nleaves follows:"),(0,g.kt)("p",null,(0,g.kt)("img",{alt:"Red-black tree with black height",src:i(4866).Z+"#gh-light-mode-only",width:"923",height:"539"}),"\n",(0,g.kt)("img",{alt:"Red-black tree with black height",src:i(1185).Z+"#gh-dark-mode-only",width:"923",height:"539"})),(0,g.kt)("p",null,"We mark the ",(0,g.kt)("em",{parentName:"p"},"black heights")," in superscript. You can see that all leaves have the\nblack height equal to ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mn",{parentName:"mrow"},"1")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"1")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"1"))))),". Let's take a look at some of the interesting cases:"),(0,g.kt)("ul",null,(0,g.kt)("li",{parentName:"ul"},(0,g.kt)("p",{parentName:"li"},"If we take a look at the node with ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mtext",{parentName:"mrow"},"key"),(0,g.kt)("mo",{parentName:"mrow"},"="),(0,g.kt)("mn",{parentName:"mrow"},"9")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\text{key} = 9")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,g.kt)("span",{parentName:"span",className:"mord text"},(0,g.kt)("span",{parentName:"span",className:"mord"},"key")),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,g.kt)("span",{parentName:"span",className:"mrel"},"="),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"9"))))),", we can see that it is\ncoloured red and its black height is 1, because it is a leaf."),(0,g.kt)("p",{parentName:"li"},"Let's look at its parent (node with ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mtext",{parentName:"mrow"},"key"),(0,g.kt)("mo",{parentName:"mrow"},"="),(0,g.kt)("mn",{parentName:"mrow"},"8")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\text{key} = 8")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,g.kt)("span",{parentName:"span",className:"mord text"},(0,g.kt)("span",{parentName:"span",className:"mord"},"key")),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,g.kt)("span",{parentName:"span",className:"mrel"},"="),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"8"))))),"). On its left side it has\n",(0,g.kt)("inlineCode",{parentName:"p"},"nil")," and on its right side the ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mn",{parentName:"mrow"},"9")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"9")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"9"))))),". And its black height is still ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mn",{parentName:"mrow"},"1")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"1")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"1"))))),", cause\nexcept for the ",(0,g.kt)("inlineCode",{parentName:"p"},"nil")," leaves, there are no other black nodes."),(0,g.kt)("p",{parentName:"li"},"We can clearly see that if a node has the same black height as its parent, it\nis a red node.")),(0,g.kt)("li",{parentName:"ul"},(0,g.kt)("p",{parentName:"li"},"Now let's take a look at the root with ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mtext",{parentName:"mrow"},"key"),(0,g.kt)("mo",{parentName:"mrow"},"="),(0,g.kt)("mn",{parentName:"mrow"},"3")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\text{key} = 3")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,g.kt)("span",{parentName:"span",className:"mord text"},(0,g.kt)("span",{parentName:"span",className:"mord"},"key")),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,g.kt)("span",{parentName:"span",className:"mrel"},"="),(0,g.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"3"))))),". It has a black height\nof 3. Both of its children are black nodes and have black height of 2."),(0,g.kt)("p",{parentName:"li"},"We can see that if a node has its height 1 lower than its parent, it is a black\nnode."),(0,g.kt)("p",{parentName:"li"},"The reasoning behind it is rather simple, we count the black nodes all the way\nto the leaves, therefore if my parent has a higher black height, it means that\non the path from me to my parent there is a black node, but the only node added\nis me, therefore I must be black."))),(0,g.kt)("h4",{id:"isomorphic-trees"},"Isomorphic trees"),(0,g.kt)("p",null,"One of the other ways to avoid using color is storing the red-black tree in some\nisomorphic tree. The structure of 2-3-4 tree allows us to avoid using the color\ncompletely. This is a bit different approach, cause we would be basically using\ndifferent tree, so we keep this note in just as a \u201chack\u201d."),(0,g.kt)("h2",{id:"2\xaa-the-root-is-black"},"2\xaa The root is black."),(0,g.kt)("p",null,"This rule might seem like a very important one, but overall is not. You can safely\nomit this rule, but you also need to deal with the consequences."),(0,g.kt)("p",null,"Let's refresh our memory with the algorithm of ",(0,g.kt)("em",{parentName:"p"},"insert fixup"),":"),(0,g.kt)("pre",null,(0,g.kt)("code",{parentName:"pre"},"WHILE z.p.color == Red\n IF z.p == z.p.p.left\n y = z.p.p.right\n\n IF y.color == Red\n z.p.color = Black\n y.color = Black\n z.p.p.color = Red\n z = z.p.p\n ELSE\n IF z == z.p.right\n z = z.p\n Left-Rotate(T, z)\n z.p.color = Black\n z.p.p.color = Red\n Right-Rotate(T, z.p.p)\n ELSE (same as above with \u201cright\u201d and \u201cleft\u201d exchanged)\n\nT.root.color = Black\n")),(0,g.kt)("admonition",{type:"tip"},(0,g.kt)("p",{parentName:"admonition"},"If you have tried to implement any of the more complex data structures, such as\nred-black trees, etc., in a statically typed language that also checks you for\n",(0,g.kt)("inlineCode",{parentName:"p"},"NULL"),"-correctness (e.g. ",(0,g.kt)("em",{parentName:"p"},"mypy")," or even C# with nullable reference types), you\nmight have run into numerous issues in the cases where you are 100% sure that you\ncannot obtain ",(0,g.kt)("inlineCode",{parentName:"p"},"NULL")," because of the invariants, but the static type checking\ndoesn't know that."),(0,g.kt)("p",{parentName:"admonition"},"The issue we hit with the ",(0,g.kt)("em",{parentName:"p"},"insert fixup")," is very similar.")),(0,g.kt)("p",null,"You might not realize the issue at the first sight, but the algorithm described\nwith the pseudocode above expects that the root of the red-black tree is black by\nboth relying on the invariant in the algorithm and afterwards by enforcing the\nblack root property."),(0,g.kt)("p",null,"If we decide to omit this condition, we need to address it in the pseudocodes\naccordingly."),(0,g.kt)("table",null,(0,g.kt)("thead",{parentName:"table"},(0,g.kt)("tr",{parentName:"thead"},(0,g.kt)("th",{parentName:"tr",align:"center"},"Usual algorithm with black root"),(0,g.kt)("th",{parentName:"tr",align:"center"},"Allowing red root"))),(0,g.kt)("tbody",{parentName:"table"},(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"1\xaa insertion",src:i(5018).Z+"#gh-light-mode-only",width:"179",height:"155"}),(0,g.kt)("img",{alt:"1\xaa insertion",src:i(4241).Z+"#gh-dark-mode-only",width:"179",height:"155"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"1\xaa insertion",src:i(2227).Z+"#gh-light-mode-only",width:"179",height:"155"}),(0,g.kt)("img",{alt:"1\xaa insertion",src:i(3591).Z+"#gh-dark-mode-only",width:"179",height:"155"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"2\xaa insertion",src:i(8491).Z+"#gh-light-mode-only",width:"227",height:"251"}),(0,g.kt)("img",{alt:"2\xaa insertion",src:i(9232).Z+"#gh-dark-mode-only",width:"227",height:"251"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"2\xaa insertion",src:i(6805).Z+"#gh-light-mode-only",width:"227",height:"251"}),(0,g.kt)("img",{alt:"2\xaa insertion",src:i(7690).Z+"#gh-dark-mode-only",width:"227",height:"251"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"3\xaa insertion",src:i(4485).Z+"#gh-light-mode-only",width:"371",height:"251"}),(0,g.kt)("img",{alt:"3\xaa insertion",src:i(3559).Z+"#gh-dark-mode-only",width:"371",height:"251"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"3\xaa insertion",src:i(7676).Z+"#gh-light-mode-only",width:"371",height:"251"}),(0,g.kt)("img",{alt:"3\xaa insertion",src:i(9861).Z+"#gh-dark-mode-only",width:"371",height:"251"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"4\xaa insertion",src:i(3037).Z+"#gh-light-mode-only",width:"419",height:"347"}),(0,g.kt)("img",{alt:"4\xaa insertion",src:i(9034).Z+"#gh-dark-mode-only",width:"419",height:"347"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"4\xaa insertion",src:i(7632).Z+"#gh-light-mode-only",width:"419",height:"347"}),(0,g.kt)("img",{alt:"4\xaa insertion",src:i(4110).Z+"#gh-dark-mode-only",width:"419",height:"347"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"5\xaa insertion",src:i(4961).Z+"#gh-light-mode-only",width:"419",height:"347"}),(0,g.kt)("img",{alt:"5\xaa insertion",src:i(4236).Z+"#gh-dark-mode-only",width:"419",height:"347"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"5\xaa insertion",src:i(7109).Z+"#gh-light-mode-only",width:"419",height:"347"}),(0,g.kt)("img",{alt:"5\xaa insertion",src:i(9418).Z+"#gh-dark-mode-only",width:"419",height:"347"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"6\xaa insertion",src:i(6061).Z+"#gh-light-mode-only",width:"563",height:"347"}),(0,g.kt)("img",{alt:"6\xaa insertion",src:i(376).Z+"#gh-dark-mode-only",width:"563",height:"347"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"6\xaa insertion",src:i(8998).Z+"#gh-light-mode-only",width:"563",height:"347"}),(0,g.kt)("img",{alt:"6\xaa insertion",src:i(3533).Z+"#gh-dark-mode-only",width:"563",height:"347"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"7\xaa insertion",src:i(7115).Z+"#gh-light-mode-only",width:"563",height:"443"}),(0,g.kt)("img",{alt:"7\xaa insertion",src:i(9010).Z+"#gh-dark-mode-only",width:"563",height:"443"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"7\xaa insertion",src:i(2366).Z+"#gh-light-mode-only",width:"563",height:"443"}),(0,g.kt)("img",{alt:"7\xaa insertion",src:i(4269).Z+"#gh-dark-mode-only",width:"563",height:"443"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"8\xaa insertion",src:i(7239).Z+"#gh-light-mode-only",width:"635",height:"443"}),(0,g.kt)("img",{alt:"8\xaa insertion",src:i(2399).Z+"#gh-dark-mode-only",width:"635",height:"443"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"8\xaa insertion",src:i(3927).Z+"#gh-light-mode-only",width:"635",height:"443"}),(0,g.kt)("img",{alt:"8\xaa insertion",src:i(122).Z+"#gh-dark-mode-only",width:"635",height:"443"}))),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"9\xaa insertion",src:i(1461).Z+"#gh-light-mode-only",width:"755",height:"443"}),(0,g.kt)("img",{alt:"9\xaa insertion",src:i(2705).Z+"#gh-dark-mode-only",width:"755",height:"443"})),(0,g.kt)("td",{parentName:"tr",align:"center"},(0,g.kt)("img",{alt:"9\xaa insertion",src:i(5509).Z+"#gh-light-mode-only",width:"755",height:"443"}),(0,g.kt)("img",{alt:"9\xaa insertion",src:i(2476).Z+"#gh-dark-mode-only",width:"755",height:"443"}))))),(0,g.kt)("h2",{id:"3\xaa-every-leaf-nil-is-black"},"3\xaa Every leaf (",(0,g.kt)("inlineCode",{parentName:"h2"},"nil"),") is black."),(0,g.kt)("p",null,"Now, this rule is a funny one. What does this imply and can I interpret this in\nsome other way? Let's go through some of the possible ways I can look at this and\nhow would they affect the other rules and balancing."),(0,g.kt)("p",null,"We will experiment with the following tree:\n",(0,g.kt)("img",{src:i(6034).Z+"#gh-light-mode-only",width:"899",height:"539"}),"\n",(0,g.kt)("img",{src:i(4254).Z+"#gh-dark-mode-only",width:"899",height:"539"})),(0,g.kt)("p",null,"We should start by counting the black nodes from root to the ",(0,g.kt)("inlineCode",{parentName:"p"},"nil")," leaves based\non the rules. We have multiple similar paths, so we will pick only the interesting\nones."),(0,g.kt)("ol",null,(0,g.kt)("li",{parentName:"ol"},"What happens if we do not count the ",(0,g.kt)("inlineCode",{parentName:"li"},"nil")," leaves?"),(0,g.kt)("li",{parentName:"ol"},"What happens if we consider leaves the nodes with ",(0,g.kt)("em",{parentName:"li"},"no descendants"),", i.e. both\nof node's children are ",(0,g.kt)("inlineCode",{parentName:"li"},"nil"),"?"),(0,g.kt)("li",{parentName:"ol"},"What happens if we do not count the ",(0,g.kt)("inlineCode",{parentName:"li"},"nil")," leaves, but consider nodes with at\nleast one ",(0,g.kt)("inlineCode",{parentName:"li"},"nil")," descendant as leaves?")),(0,g.kt)("table",null,(0,g.kt)("thead",{parentName:"table"},(0,g.kt)("tr",{parentName:"thead"},(0,g.kt)("th",{parentName:"tr",align:"right"},"path"),(0,g.kt)("th",{parentName:"tr",align:"right"},"black nodes"),(0,g.kt)("th",{parentName:"tr",align:"right"},"1\xaa idea"),(0,g.kt)("th",{parentName:"tr",align:"right"},"2\xaa idea"),(0,g.kt)("th",{parentName:"tr",align:"right"},"3\xaa idea"))),(0,g.kt)("tbody",{parentName:"table"},(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"right"},(0,g.kt)("inlineCode",{parentName:"td"},"3 \u2192 1 \u2192 0 \u2192 nil")),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3"),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3")),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"right"},(0,g.kt)("inlineCode",{parentName:"td"},"3 \u2192 5 \u2192 7 \u2192 8 \u2192 nil")),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3"),(0,g.kt)("td",{parentName:"tr",align:"right"},"-"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3")),(0,g.kt)("tr",{parentName:"tbody"},(0,g.kt)("td",{parentName:"tr",align:"right"},(0,g.kt)("inlineCode",{parentName:"td"},"3 \u2192 5 \u2192 7 \u2192 8 \u2192 9 \u2192 nil")),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3"),(0,g.kt)("td",{parentName:"tr",align:"right"},"4"),(0,g.kt)("td",{parentName:"tr",align:"right"},"3")))),(0,g.kt)("p",null,"First idea is very easy to execute and it is also very easy to argue about its\ncorrectness. It is correct, because we just subtract one from each of the paths.\nThis affects ",(0,g.kt)("strong",{parentName:"p"},"all")," paths and therefore results in global decrease by one."),(0,g.kt)("p",null,"Second idea is a bit more complicated. We count the ",(0,g.kt)("inlineCode",{parentName:"p"},"nil"),"s, so the count is ",(0,g.kt)("span",{parentName:"p",className:"math math-inline"},(0,g.kt)("span",{parentName:"span",className:"katex"},(0,g.kt)("span",{parentName:"span",className:"katex-mathml"},(0,g.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,g.kt)("semantics",{parentName:"math"},(0,g.kt)("mrow",{parentName:"semantics"},(0,g.kt)("mn",{parentName:"mrow"},"4")),(0,g.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"4")))),(0,g.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,g.kt)("span",{parentName:"span",className:"base"},(0,g.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,g.kt)("span",{parentName:"span",className:"mord"},"4"))))),"\nas it should be. However, there is one difference. Second path no longer satisfies\nthe condition of a ",(0,g.kt)("em",{parentName:"p"},"leaf"),". Technically it relaxes the 5th rule, because we leave\nout some of the nodes. We should probably avoid that."),(0,g.kt)("admonition",{type:"caution"},(0,g.kt)("p",{parentName:"admonition"},"With the second idea, you may also feel that we are \u201cbending\u201d the rules a bit,\nespecially the definition of the \u201cleaf\u201d nodes."),(0,g.kt)("p",{parentName:"admonition"},"Given the definition of the red-black tree, where ",(0,g.kt)("inlineCode",{parentName:"p"},"nil")," is considered to be an\nexternal node, we have decided that bending it a bit just to stir a thought about\nit won't hurt anybody. \ud83d\ude09")),(0,g.kt)("h2",{id:"4\xaa-if-a-node-is-red-then-both-its-children-are-black"},"4\xaa If a node is red, then both its children are black."),(0,g.kt)("p",null,"This rule might seem rather silly on the first look, but there are 2 important\nfunctions:"),(0,g.kt)("ol",null,(0,g.kt)("li",{parentName:"ol"},"it allows the algorithms to ",(0,g.kt)("em",{parentName:"li"},"\u201cnotice\u201d")," that something went wrong (i.e. the\ntree needs to be rebalanced), and"),(0,g.kt)("li",{parentName:"ol"},"it holds the balancing and height of the tree ",(0,g.kt)("em",{parentName:"li"},"\u201cin check\u201d")," (with the help of\nthe 5th rule).")),(0,g.kt)("p",null,"When we have a look at the algorithms that are used for fixing up the red-black\ntree after an insertion or deletion, we will notice that all the algorithms need\nis the color of the node. "),(0,g.kt)("blockquote",null,(0,g.kt)("p",{parentName:"blockquote"},"How come it is the only thing that we need?\nHow come such na\xefve thing can be enough?")),(0,g.kt)("p",null,"Let's say we perform an insertion into the tree\u2026 We go with the usual and pretty\nprimitive insertion into the binary-search tree and then, if needed, we \u201cfix up\u201d\nbroken invariants. ",(0,g.kt)("em",{parentName:"p"},"How can that be enough?")," With each insertion and deletion we\nmaintain the invariants, therefore if we break them with one operation, there's\nonly one path on which the invariants were ",(0,g.kt)("em",{parentName:"p"},"felled"),". If we know that rest of the\ntree is correct, it allows us to fix the issues just by propagating it to the\nroot and ",(0,g.kt)("em",{parentName:"p"},"abusing")," the siblings (which are, of course, correct red-black\nsubtrees) to fix or at least partially mitigate the issues and propagate them\nfurther."),(0,g.kt)("p",null,"Let's assume that we do not enforce this rule, you can see how it breaks the\nbalancing of the tree below."),(0,g.kt)(P,{mdxType:"Tabs"},(0,g.kt)(a,{value:"enforcing",label:"Enforcing this rule",mdxType:"TabItem"},(0,g.kt)("p",null,(0,g.kt)("img",{src:i(2815).Z+"#gh-light-mode-only",width:"755",height:"347"}),"\n",(0,g.kt)("img",{src:i(6754).Z+"#gh-dark-mode-only",width:"755",height:"347"}))),(0,g.kt)(a,{value:"omitting",label:"Omitting this rule",mdxType:"TabItem"},(0,g.kt)("p",null,(0,g.kt)("img",{src:i(8800).Z+"#gh-light-mode-only",width:"803",height:"443"}),"\n",(0,g.kt)("img",{src:i(9183).Z+"#gh-dark-mode-only",width:"803",height:"443"})))),(0,g.kt)("p",null,"We can create a ",(0,g.kt)("strong",{parentName:"p"},"big")," subtree with only red nodes and ",(0,g.kt)("strong",{parentName:"p"},"even")," when keeping\nthe rest of the rules maintained, it will break the time complexity. It stops us\nfrom \u201chacking\u201d the black height requirement laid by the 5th rule."),(0,g.kt)("h2",{id:"5\xaa-for-each-node-all-simple-paths-from-the-node-to-descendant-leaves-contain-the-same-number-of-black-nodes"},"5\xaa For each node, all simple paths from the node to descendant leaves contain the same number of black nodes."),(0,g.kt)("p",null,"As it was mentioned, with the 4th rule they hold the balancing of the red-black\ntree."),(0,g.kt)("admonition",{type:"tip"},(0,g.kt)("p",{parentName:"admonition"},"An important observation here is the fact that the red-black tree is a\n",(0,g.kt)("strong",{parentName:"p"},"height"),"-balanced tree.")),(0,g.kt)("p",null,"Enforcing this rule (together with the 4th rule) keeps the tree balanced:"),(0,g.kt)("ol",null,(0,g.kt)("li",{parentName:"ol"},"4th rule makes sure we can't \u201chack\u201d this requirement."),(0,g.kt)("li",{parentName:"ol"},"This rule ensures that we have \u201csimilar\u201d",(0,g.kt)("sup",{parentName:"li",id:"fnref-2"},(0,g.kt)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2"))," length to each of the leaves.")),(0,g.kt)("admonition",{title:"AVL tree",type:"tip"},(0,g.kt)("p",{parentName:"admonition"},"You might have heard about an ",(0,g.kt)("em",{parentName:"p"},"AVL tree")," before. It is the first self-balanced\ntree to be ever introduced and works in a very similar nature as the red-black\ntree, the only difference is that it does not deal with the ",(0,g.kt)("em",{parentName:"p"},"black height"),", but\nthe height in general."),(0,g.kt)("p",{parentName:"admonition"},"If you were to compare AVL with the red-black tree, you can say that AVL is much\nmore strict while red-black tree can still maintain the same asymptotic time\ncomplexity for the operations, but having more relaxed rules.")),(0,g.kt)("div",{className:"footnotes"},(0,g.kt)("hr",{parentName:"div"}),(0,g.kt)("ol",{parentName:"div"},(0,g.kt)("li",{parentName:"ol",id:"fn-1"},"CORMEN, Thomas. Introduction to algorithms. Cambridge, Mass: MIT Press, 2009. isbn 9780262033848.",(0,g.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,g.kt)("li",{parentName:"ol",id:"fn-2"},"red nodes still exist",(0,g.kt)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")))))}Y.isMDXComponent=!0},4254:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rb_dark-2917b0f8de62597646b619102f126a53.svg"},1185:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rb_height_dark-921b2d98d9fe1e579474faf36486f281.svg"},4866:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rb_height_light-0aff6e7a40a9f601e0dd1114e43e43b1.svg"},6034:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rb_light-9889570d993cf4a78a1bcccfbd76eab4.svg"},6754:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iNTY2cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgNTY2LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0iIzFiMWIxZCIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgNTYyLC0yNTYgNTYyLDQgLTQsNCIvPgo8IS0tIE5vZGUodmFsdWU9MywgcmFuaz0yKSAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTMsIHJhbms9Mik8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMjc5IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjc5IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MzwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjIwNyIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTEsIHJhbms9MSkgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0xLCByYW5rPTEpPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI2NC40MywtMjE4LjgzQzI1NC4yNSwtMjA4Ljk0IDI0MC40OCwtMTk1LjU1IDIyOC45NywtMTg0LjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIzMS40MSwtMTgxLjg1IDIyMS44LC0xNzcuMzggMjI2LjUzLC0xODYuODcgMjMxLjQxLC0xODEuODUiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NSwgcmFuaz0xKSAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTUsIHJhbms9MSk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMzUxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzUxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NTwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MywgcmFuaz0yKSYjNDU7Jmd0O05vZGUodmFsdWU9NSwgcmFuaz0xKSAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTUsIHJhbms9MSk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjkzLjU3LC0yMTguODNDMzAzLjc1LC0yMDguOTQgMzE3LjUyLC0xOTUuNTUgMzI5LjAzLC0xODQuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMzMxLjQ3LC0xODYuODcgMzM2LjIsLTE3Ny4zOCAzMjYuNTksLTE4MS44NSAzMzEuNDcsLTE4Ni44NyIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0wLCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjA8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTEsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTAsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0xLCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0wLCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE4OC4xOSwtMTQ4LjgxQzE3MSwtMTM3LjY3IDE0NS4zOCwtMTIxLjA2IDEyNi4wMSwtMTA4LjUiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTI3Ljg5LC0xMDUuNTYgMTE3LjYsLTEwMy4wNSAxMjQuMDgsLTExMS40MyAxMjcuODksLTEwNS41NiIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0yLCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyMDciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MjwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9MiwgcmFuaz0wKSAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTIsIHJhbms9MCk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjA3LC0xNDMuN0MyMDcsLTEzNS45OCAyMDcsLTEyNi43MSAyMDcsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyMTAuNSwtMTE4LjEgMjA3LC0xMDguMSAyMDMuNSwtMTE4LjEgMjEwLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTQsIHJhbms9MCkgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+Tm9kZSh2YWx1ZT00LCByYW5rPTApPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIzNTEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjM1MSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NDwvdGV4dD4KPC9nPgo8IS0tIG5pbDYgLS0+CjxnIGlkPSJub2RlMTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT00LCByYW5rPTApJiM0NTsmZ3Q7bmlsNiAtLT4KPGcgaWQ9ImVkZ2UxMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT00LCByYW5rPTApJiM0NTsmZ3Q7bmlsNjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zNDIuNjUsLTcyLjc2QzMzOC4yOSwtNjQuMjggMzMyLjg1LC01My43MSAzMjcuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMzMwLjk5LC00Mi40NCAzMjMuMywtMzUuMTUgMzI0Ljc3LC00NS42NCAzMzAuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBuaWw3IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw3PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjM4NyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDcgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDc8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMzU5LjM1LC03Mi43NkMzNjMuNzEsLTY0LjI4IDM2OS4xNSwtNTMuNzEgMzc0LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjM3Ny4yMywtNDUuNjQgMzc4LjcsLTM1LjE1IDM3MS4wMSwtNDIuNDQgMzc3LjIzLC00NS42NCIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT03LCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iNDU5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI0NTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjc8L3RleHQ+CjwvZz4KPCEtLSBuaWw4IC0tPgo8ZyBpZD0ibm9kZTE0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjQ1OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0O25pbDggLS0+CjxnIGlkPSJlZGdlMTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0O25pbDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNDU5LC03MS43QzQ1OSwtNjMuOTggNDU5LC01NC43MSA0NTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjQ2Mi41LC00Ni4xIDQ1OSwtMzYuMSA0NTUuNSwtNDYuMSA0NjIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gbmlsOSAtLT4KPGcgaWQ9Im5vZGUxNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsOTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI1MzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw5IC0tPgo8ZyBpZD0iZWRnZTE0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw5PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTQ3My41NywtNzQuODNDNDgzLjc1LC02NC45NCA0OTcuNTIsLTUxLjU1IDUwOS4wMywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iNTExLjQ3LC00Mi44NyA1MTYuMiwtMzMuMzggNTA2LjU5LC0zNy44NSA1MTEuNDcsLTQyLjg3Ii8+CjwvZz4KPCEtLSBuaWwyIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwyIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTc0LjgzQzc0LjI1LC02NC45NCA2MC40OCwtNTEuNTUgNDguOTcsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjUxLjQxLC0zNy44NSA0MS44LC0zMy4zOCA0Ni41MywtNDIuODcgNTEuNDEsLTM3Ljg1Ii8+CjwvZz4KPCEtLSBuaWwzIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDM8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwzIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDM8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTcxLjdDOTksLTYzLjk4IDk5LC01NC43MSA5OSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTQ2LjEgOTksLTM2LjEgOTUuNSwtNDYuMSAxMDIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gbmlsNCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw0IC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTk4LjY1LC03Mi43NkMxOTQuMjksLTY0LjI4IDE4OC44NSwtNTMuNzEgMTgzLjk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE4Ni45OSwtNDIuNDQgMTc5LjMsLTM1LjE1IDE4MC43NywtNDUuNjQgMTg2Ljk5LC00Mi40NCIvPgo8L2c+CjwhLS0gbmlsNSAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNDMiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw1IC0tPgo8ZyBpZD0iZWRnZTEwIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw1PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIxNS4zNSwtNzIuNzZDMjE5LjcxLC02NC4yOCAyMjUuMTUsLTUzLjcxIDIzMC4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyMzMuMjMsLTQ1LjY0IDIzNC43LC0zNS4xNSAyMjcuMDEsLTQyLjQ0IDIzMy4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9NCwgcmFuaz0wKSAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTQsIHJhbms9MCk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMzUxLC0xNDMuN0MzNTEsLTEzNS45OCAzNTEsLTEyNi43MSAzNTEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzNTQuNSwtMTE4LjEgMzUxLC0xMDguMSAzNDcuNSwtMTE4LjEgMzU0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTcsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT01LCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT03LCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0zNjkuODEsLTE0OC44MUMzODcsLTEzNy42NyA0MTIuNjIsLTEyMS4wNiA0MzEuOTksLTEwOC41Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSI0MzMuOTIsLTExMS40MyA0NDAuNCwtMTAzLjA1IDQzMC4xMSwtMTA1LjU2IDQzMy45MiwtMTExLjQzIi8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2815:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iNTY2cHQiIGhlaWdodD0iMjYwcHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgNTY2LjAwIDI2MC4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAyNTYpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMjU2IDU2MiwtMjU2IDU2Miw0IC00LDQiLz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjI3OSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3OSIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MzwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjIwNyIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MywgcmFuaz0yKSYjNDU7Jmd0O05vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjY0LjQzLC0yMTguODNDMjU0LjI1LC0yMDguOTQgMjQwLjQ4LC0xOTUuNTUgMjI4Ljk3LC0xODQuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjMxLjQxLC0xODEuODUgMjIxLjgsLTE3Ny4zOCAyMjYuNTMsLTE4Ni44NyAyMzEuNDEsLTE4MS44NSIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT01LCByYW5rPTEpIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9NSwgcmFuaz0xKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIzNTEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIzNTEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTUsIHJhbms9MSkgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT01LCByYW5rPTEpPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI5My41NywtMjE4LjgzQzMwMy43NSwtMjA4Ljk0IDMxNy41MiwtMTk1LjU1IDMyOS4wMywtMTg0LjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMzMS40NywtMTg2Ljg3IDMzNi4yLC0xNzcuMzggMzI2LjU5LC0xODEuODUgMzMxLjQ3LC0xODYuODciLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MCwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTAsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjA8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTEsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTAsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0xLCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0wLCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE4OC4xOSwtMTQ4LjgxQzE3MSwtMTM3LjY3IDE0NS4zOCwtMTIxLjA2IDEyNi4wMSwtMTA4LjUiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTI3Ljg5LC0xMDUuNTYgMTE3LjYsLTEwMy4wNSAxMjQuMDgsLTExMS40MyAxMjcuODksLTEwNS41NiIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0yLCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyMDciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0xLCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0yLCByYW5rPTApIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9MiwgcmFuaz0wKTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMDcsLTE0My43QzIwNywtMTM1Ljk4IDIwNywtMTI2LjcxIDIwNywtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIxMC41LC0xMTguMSAyMDcsLTEwOC4xIDIwMy41LC0xMTguMSAyMTAuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTQsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjM1MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzUxIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjQ8L3RleHQ+CjwvZz4KPCEtLSBuaWw2IC0tPgo8ZyBpZD0ibm9kZTEyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjMxNSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDYgLS0+CjxnIGlkPSJlZGdlMTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDY8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzQyLjY1LC03Mi43NkMzMzguMjksLTY0LjI4IDMzMi44NSwtNTMuNzEgMzI3Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMzMC45OSwtNDIuNDQgMzIzLjMsLTM1LjE1IDMyNC43NywtNDUuNjQgMzMwLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gbmlsNyAtLT4KPGcgaWQ9Im5vZGUxMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNzwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIzODciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTQsIHJhbms9MCkmIzQ1OyZndDtuaWw3IC0tPgo8ZyBpZD0iZWRnZTEyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTQsIHJhbms9MCkmIzQ1OyZndDtuaWw3PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTM1OS4zNSwtNzIuNzZDMzYzLjcxLC02NC4yOCAzNjkuMTUsLTUzLjcxIDM3NC4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNzcuMjMsLTQ1LjY0IDM3OC43LC0zNS4xNSAzNzEuMDEsLTQyLjQ0IDM3Ny4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NywgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTcsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjQ1OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNDU5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjc8L3RleHQ+CjwvZz4KPCEtLSBuaWw4IC0tPgo8ZyBpZD0ibm9kZTE0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjQ1OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0O25pbDggLS0+CjxnIGlkPSJlZGdlMTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0O25pbDg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNDU5LC03MS43QzQ1OSwtNjMuOTggNDU5LC01NC43MSA0NTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjQ2Mi41LC00Ni4xIDQ1OSwtMzYuMSA0NTUuNSwtNDYuMSA0NjIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gbmlsOSAtLT4KPGcgaWQ9Im5vZGUxNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsOTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI1MzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw5IC0tPgo8ZyBpZD0iZWRnZTE0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw5PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTQ3My41NywtNzQuODNDNDgzLjc1LC02NC45NCA0OTcuNTIsLTUxLjU1IDUwOS4wMywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTExLjQ3LC00Mi44NyA1MTYuMiwtMzMuMzggNTA2LjU5LC0zNy44NSA1MTEuNDcsLTQyLjg3Ii8+CjwvZz4KPCEtLSBuaWwyIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwyIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNODQuNDMsLTc0LjgzQzc0LjI1LC02NC45NCA2MC40OCwtNTEuNTUgNDguOTcsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjUxLjQxLC0zNy44NSA0MS44LC0zMy4zOCA0Ni41MywtNDIuODcgNTEuNDEsLTM3Ljg1Ii8+CjwvZz4KPCEtLSBuaWwzIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDM8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwzIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDM8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTcxLjdDOTksLTYzLjk4IDk5LC01NC43MSA5OSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTQ2LjEgOTksLTM2LjEgOTUuNSwtNDYuMSAxMDIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gbmlsNCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw0IC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTk4LjY1LC03Mi43NkMxOTQuMjksLTY0LjI4IDE4OC44NSwtNTMuNzEgMTgzLjk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE4Ni45OSwtNDIuNDQgMTc5LjMsLTM1LjE1IDE4MC43NywtNDUuNjQgMTg2Ljk5LC00Mi40NCIvPgo8L2c+CjwhLS0gbmlsNSAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsNTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNDMiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw1IC0tPgo8ZyBpZD0iZWRnZTEwIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTIsIHJhbms9MCkmIzQ1OyZndDtuaWw1PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTIxNS4zNSwtNzIuNzZDMjE5LjcxLC02NC4yOCAyMjUuMTUsLTUzLjcxIDIzMC4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyMzMuMjMsLTQ1LjY0IDIzNC43LC0zNS4xNSAyMjcuMDEsLTQyLjQ0IDIzMy4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9NCwgcmFuaz0wKSAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTQsIHJhbms9MCk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzUxLC0xNDMuN0MzNTEsLTEzNS45OCAzNTEsLTEyNi43MSAzNTEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNTQuNSwtMTE4LjEgMzUxLC0xMDguMSAzNDcuNSwtMTE4LjEgMzU0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTcsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT01LCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT03LCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0zNjkuODEsLTE0OC44MUMzODcsLTEzNy42NyA0MTIuNjIsLTEyMS4wNiA0MzEuOTksLTEwOC41Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iNDMzLjkyLC0xMTEuNDMgNDQwLjQsLTEwMy4wNSA0MzAuMTEsLTEwNS41NiA0MzMuOTIsLTExMS40MyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},9183:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/incorrect_dark-d9c04aed74f7d364c3c3b1855b769ab0.svg"},8800:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiAlMyBQYWdlczogMSAtLT4KPHN2ZyB3aWR0aD0iNjAycHQiIGhlaWdodD0iMzMycHQiCiB2aWV3Qm94PSIwLjAwIDAuMDAgNjAyLjAwIDMzMi4wMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxnIGlkPSJncmFwaDAiIGNsYXNzPSJncmFwaCIgdHJhbnNmb3JtPSJzY2FsZSgxIDEpIHJvdGF0ZSgwKSB0cmFuc2xhdGUoNCAzMjgpIj4KPHRpdGxlPiUzPC90aXRsZT4KPHBvbHlnb24gZmlsbD0id2hpdGUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIHBvaW50cz0iLTQsNCAtNCwtMzI4IDU5OCwtMzI4IDU5OCw0IC00LDQiLz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikgLS0+CjxnIGlkPSJub2RlMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjI3OSIgY3k9Ii0zMDYiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3OSIgeT0iLTMwMi4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MzwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjIyNSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIyNSIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MywgcmFuaz0yKSYjNDU7Jmd0O05vZGUodmFsdWU9MSwgcmFuaz0xKSAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTEsIHJhbms9MSk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjY3LjAyLC0yODkuNDZDMjYwLjAyLC0yODAuNCAyNTEuMDYsLTI2OC43OSAyNDMuMjEsLTI1OC42MSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNDUuODMsLTI1Ni4yNyAyMzYuOTUsLTI1MC40OSAyNDAuMjksLTI2MC41NSAyNDUuODMsLTI1Ni4yNyIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT01LCByYW5rPTEpIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9NSwgcmFuaz0xKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIzMzMiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIzMzMiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTMsIHJhbms9MikmIzQ1OyZndDtOb2RlKHZhbHVlPTUsIHJhbms9MSkgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0zLCByYW5rPTIpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT01LCByYW5rPTEpPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI5MC45OCwtMjg5LjQ2QzI5Ny45OCwtMjgwLjQgMzA2Ljk0LC0yNjguNzkgMzE0Ljc5LC0yNTguNjEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzE3LjcxLC0yNjAuNTUgMzIxLjA1LC0yNTAuNDkgMzEyLjE3LC0yNTYuMjcgMzE3LjcxLC0yNjAuNTUiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MCwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTAsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MDwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9MCwgcmFuaz0wKSAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTEsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTAsIHJhbms9MCk8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjA0Ljc2LC0yMjEuNzVDMTg0LC0yMTAuMjIgMTUxLjUyLC0xOTIuMTggMTI4LjAyLC0xNzkuMTIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTI5LjY0LC0xNzYuMDIgMTE5LjE5LC0xNzQuMjIgMTI2LjI0LC0xODIuMTMgMTI5LjY0LC0xNzYuMDIiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MiwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTIsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjI1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjI1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0xLCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT0yLCByYW5rPTApIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9MiwgcmFuaz0wKTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMjUsLTIxNS43QzIyNSwtMjA3Ljk4IDIyNSwtMTk4LjcxIDIyNSwtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyOC41LC0xOTAuMSAyMjUsLTE4MC4xIDIyMS41LC0xOTAuMSAyMjguNSwtMTkwLjEiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTQsIHJhbms9MCk8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjMzMyIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMzMyIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NDwvdGV4dD4KPC9nPgo8IS0tIG5pbDYgLS0+CjxnIGlkPSJub2RlMTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT00LCByYW5rPTApJiM0NTsmZ3Q7bmlsNiAtLT4KPGcgaWQ9ImVkZ2UxMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT00LCByYW5rPTApJiM0NTsmZ3Q7bmlsNjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMjguNjQsLTE0NC4wNUMzMjYuNjEsLTEzNi4xNCAzMjQuMTQsLTEyNi41NCAzMjEuODYsLTExNy42OSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzMjUuMiwtMTE2LjYgMzE5LjMyLC0xMDcuNzkgMzE4LjQyLC0xMTguMzUgMzI1LjIsLTExNi42Ii8+CjwvZz4KPCEtLSBuaWw3IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw3PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjM4NyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDcgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NCwgcmFuaz0wKSYjNDU7Jmd0O25pbDc8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzQ0Ljk4LC0xNDUuNDZDMzUxLjk4LC0xMzYuNCAzNjAuOTQsLTEyNC43OSAzNjguNzksLTExNC42MSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNzEuNzEsLTExNi41NSAzNzUuMDUsLTEwNi40OSAzNjYuMTcsLTExMi4yNyAzNzEuNzEsLTExNi41NSIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT03LCByYW5rPTApIC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iNDU5IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNDU5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj43PC90ZXh0Pgo8L2c+CjwhLS0gbmlsOCAtLT4KPGcgaWQ9Im5vZGUxNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI0NTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw4IC0tPgo8ZyBpZD0iZWRnZTEzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTcsIHJhbms9MCkmIzQ1OyZndDtuaWw4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTQ1OSwtMTQzLjdDNDU5LC0xMzUuOTggNDU5LC0xMjYuNzEgNDU5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNDYyLjUsLTExOC4xIDQ1OSwtMTA4LjEgNDU1LjUsLTExOC4xIDQ2Mi41LC0xMTguMSIvPgo8L2c+CjwhLS0gOCAtLT4KPGcgaWQ9Im5vZGUxNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iNTMxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI1MzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+ODwvdGV4dD4KPC9nPgo8IS0tIE5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0OzggLS0+CjxnIGlkPSJlZGdlMTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NywgcmFuaz0wKSYjNDU7Jmd0Ozg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTQ3My41NywtMTQ2LjgzQzQ4My43NSwtMTM2Ljk0IDQ5Ny41MiwtMTIzLjU1IDUwOS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iNTExLjQ3LC0xMTQuODcgNTE2LjIsLTEwNS4zOCA1MDYuNTksLTEwOS44NSA1MTEuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gbmlsMiAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWwyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT0wLCByYW5rPTApJiM0NTsmZ3Q7bmlsMiAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT5Ob2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBuaWwzIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPm5pbDM8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTAsIHJhbms9MCkmIzQ1OyZndDtuaWwzIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MCwgcmFuaz0wKSYjNDU7Jmd0O25pbDM8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBuaWw0IC0tPgo8ZyBpZD0ibm9kZTEwIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDQgLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT0yLCByYW5rPTApJiM0NTsmZ3Q7bmlsNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMTMuMDIsLTE0NS40NkMyMDYuMDIsLTEzNi40IDE5Ny4wNiwtMTI0Ljc5IDE4OS4yMSwtMTE0LjYxIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE5MS44MywtMTEyLjI3IDE4Mi45NSwtMTA2LjQ5IDE4Ni4yOSwtMTE2LjU1IDE5MS44MywtMTEyLjI3Ii8+CjwvZz4KPCEtLSBuaWw1IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5uaWw1PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIE5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDUgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9MiwgcmFuaz0wKSYjNDU7Jmd0O25pbDU8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjI5LjM2LC0xNDQuMDVDMjMxLjM5LC0xMzYuMTQgMjMzLjg2LC0xMjYuNTQgMjM2LjE0LC0xMTcuNjkiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjM5LjU4LC0xMTguMzUgMjM4LjY4LC0xMDcuNzkgMjMyLjgsLTExNi42IDIzOS41OCwtMTE4LjM1Ii8+CjwvZz4KPCEtLSBOb2RlKHZhbHVlPTUsIHJhbms9MSkmIzQ1OyZndDtOb2RlKHZhbHVlPTQsIHJhbms9MCkgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+Tm9kZSh2YWx1ZT01LCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT00LCByYW5rPTApPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTMzMywtMjE1LjdDMzMzLC0yMDcuOTggMzMzLC0xOTguNzEgMzMzLC0xOTAuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzM2LjUsLTE5MC4xIDMzMywtMTgwLjEgMzI5LjUsLTE5MC4xIDMzNi41LC0xOTAuMSIvPgo8L2c+CjwhLS0gTm9kZSh2YWx1ZT01LCByYW5rPTEpJiM0NTsmZ3Q7Tm9kZSh2YWx1ZT03LCByYW5rPTApIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPk5vZGUodmFsdWU9NSwgcmFuaz0xKSYjNDU7Jmd0O05vZGUodmFsdWU9NywgcmFuaz0wKTwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMzUzLjI0LC0yMjEuNzVDMzc0LC0yMTAuMjIgNDA2LjQ4LC0xOTIuMTggNDI5Ljk4LC0xNzkuMTIiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSI0MzEuNzYsLTE4Mi4xMyA0MzguODEsLTE3NC4yMiA0MjguMzYsLTE3Ni4wMiA0MzEuNzYsLTE4Mi4xMyIvPgo8L2c+CjwhLS0gbmlsOSAtLT4KPGcgaWQ9Im5vZGUxNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsOTwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI0OTUiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSBuaWwxMCAtLT4KPGcgaWQ9Im5vZGUxNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+bmlsMTA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iNTY3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gOCYjNDU7Jmd0O25pbDkgLS0+CjxnIGlkPSJlZGdlMTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjgmIzQ1OyZndDtuaWw5PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTUyMi42NSwtNzIuNzZDNTE4LjI5LC02NC4yOCA1MTIuODUsLTUzLjcxIDUwNy45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MTAuOTksLTQyLjQ0IDUwMy4zLC0zNS4xNSA1MDQuNzcsLTQ1LjY0IDUxMC45OSwtNDIuNDQiLz4KPC9nPgo8IS0tIDgmIzQ1OyZndDtuaWwxMCAtLT4KPGcgaWQ9ImVkZ2UxNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+OCYjNDU7Jmd0O25pbDEwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTUzOS4zNSwtNzIuNzZDNTQzLjcxLC02NC4yOCA1NDkuMTUsLTUzLjcxIDU1NC4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1NTcuMjMsLTQ1LjY0IDU1OC43LC0zNS4xNSA1NTEuMDEsLTQyLjQ0IDU1Ny4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},4241:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjEzNHB0IiBoZWlnaHQ9IjExNnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDEzNC4wMCAxMTYuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTEyKSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTExMiAxMzAsLTExMiAxMzAsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTU0LjY1LC03Mi43NkM1MC4yOSwtNjQuMjggNDQuODUsLTUzLjcxIDM5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjQyLjk5LC00Mi40NCAzNS4zLC0zNS4xNSAzNi43NywtNDUuNjQgNDIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNzEuMzUsLTcyLjc2Qzc1LjcxLC02NC4yOCA4MS4xNSwtNTMuNzEgODYuMDQsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iODkuMjMsLTQ1LjY0IDkwLjcsLTM1LjE1IDgzLjAxLC00Mi40NCA4OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},5018:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjEzNHB0IiBoZWlnaHQ9IjExNnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDEzNC4wMCAxMTYuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTEyKSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xMTIgMTMwLC0xMTIgMTMwLDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iNjMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjYzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTU0LjY1LC03Mi43NkM1MC4yOSwtNjQuMjggNDQuODUsLTUzLjcxIDM5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjQyLjk5LC00Mi40NCAzNS4zLC0zNS4xNSAzNi43NywtNDUuNjQgNDIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNNzEuMzUsLTcyLjc2Qzc1LjcxLC02NC4yOCA4MS4xNSwtNTMuNzEgODYuMDQsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iODkuMjMsLTQ1LjY0IDkwLjcsLTM1LjE1IDgzLjAxLC00Mi40NCA4OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},9232:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjE3MHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDE3MC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTE4NCAxNjYsLTE4NCAxNjYsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik05MC42NSwtMTQ0Ljc2Qzg2LjI5LC0xMzYuMjggODAuODUsLTEyNS43MSA3NS45NiwtMTE2LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9Ijc4Ljk5LC0xMTQuNDQgNzEuMywtMTA3LjE1IDcyLjc3LC0xMTcuNjQgNzguOTksLTExNC40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjEzNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMDcuMzUsLTE0NC43NkMxMTEuNzEsLTEzNi4yOCAxMTcuMTUsLTEyNS43MSAxMjIuMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEyNS4yMywtMTE3LjY0IDEyNi43LC0xMDcuMTUgMTE5LjAxLC0xMTQuNDQgMTI1LjIzLC0xMTcuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O0wxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},8491:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjE3MHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDE3MC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xODQgMTY2LC0xODQgMTY2LDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NTwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTkwLjY1LC0xNDQuNzZDODYuMjksLTEzNi4yOCA4MC44NSwtMTI1LjcxIDc1Ljk2LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9Ijc4Ljk5LC0xMTQuNDQgNzEuMywtMTA3LjE1IDcyLjc3LC0xMTcuNjQgNzguOTksLTExNC40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjEzNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMDcuMzUsLTE0NC43NkMxMTEuNzEsLTEzNi4yOCAxMTcuMTUsLTEyNS43MSAxMjIuMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEyNS4yMywtMTE3LjY0IDEyNi43LC0xMDcuMTUgMTE5LjAxLC0xMTQuNDQgMTI1LjIzLC0xMTcuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O0wxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},3559:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjI3OHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDI3OC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTE4NCAyNzQsLTE4NCAyNzQsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTI2LjY1LC0xNDQuNzZDMTIyLjI5LC0xMzYuMjggMTE2Ljg1LC0xMjUuNzEgMTExLjk2LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTE0Ljk5LC0xMTQuNDQgMTA3LjMsLTEwNy4xNSAxMDguNzcsLTExNy42NCAxMTQuOTksLTExNC40NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTQzLjM1LC0xNDQuNzZDMTQ3LjcxLC0xMzYuMjggMTUzLjE1LC0xMjUuNzEgMTU4LjA0LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTYxLjIzLC0xMTcuNjQgMTYyLjcsLTEwNy4xNSAxNTUuMDEsLTExNC40NCAxNjEuMjMsLTExNy42NCIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtMMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC03MS43QzE3MSwtNjMuOTggMTcxLC01NC43MSAxNzEsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC00Ni4xIDE3MSwtMzYuMSAxNjcuNSwtNDYuMSAxNzQuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xODUuNTcsLTc0LjgzQzE5NS43NSwtNjQuOTQgMjA5LjUyLC01MS41NSAyMjEuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMy40NywtNDIuODcgMjI4LjIsLTMzLjM4IDIxOC41OSwtMzcuODUgMjIzLjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},4485:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjI3OHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDI3OC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xODQgMjc0LC0xODQgMjc0LDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xMjYuNjUsLTE0NC43NkMxMjIuMjksLTEzNi4yOCAxMTYuODUsLTEyNS43MSAxMTEuOTYsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTE0Ljk5LC0xMTQuNDQgMTA3LjMsLTEwNy4xNSAxMDguNzcsLTExNy42NCAxMTQuOTksLTExNC40NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xNDMuMzUsLTE0NC43NkMxNDcuNzEsLTEzNi4yOCAxNTMuMTUsLTEyNS43MSAxNTguMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTYxLjIzLC0xMTcuNjQgMTYyLjcsLTEwNy4xNSAxNTUuMDEsLTExNC40NCAxNjEuMjMsLTExNy42NCIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtMMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC03MS43QzE3MSwtNjMuOTggMTcxLC01NC43MSAxNzEsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC00Ni4xIDE3MSwtMzYuMSAxNjcuNSwtNDYuMSAxNzQuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xODUuNTcsLTc0LjgzQzE5NS43NSwtNjQuOTQgMjA5LjUyLC01MS41NSAyMjEuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMy40NywtNDIuODcgMjI4LjIsLTMzLjM4IDIxOC41OSwtMzcuODUgMjIzLjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},9034:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiAzMTAsLTI1NiAzMTAsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NTwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNDMuMzUsLTIxNi43NkMxNDcuNzEsLTIwOC4yOCAxNTMuMTUsLTE5Ny43MSAxNTguMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE2MS4yMywtMTg5LjY0IDE2Mi43LC0xNzkuMTUgMTU1LjAxLC0xODYuNDQgMTYxLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O0wxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7TDE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjUxLjQxLC0xMDkuODUgNDEuOCwtMTA1LjM4IDQ2LjUzLC0xMTQuODcgNTEuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC0xNDMuN0M5OSwtMTM1Ljk4IDk5LC0xMjYuNzEgOTksLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMDIuNSwtMTE4LjEgOTksLTEwOC4xIDk1LjUsLTExOC4xIDEwMi41LC0xMTguMSIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xODwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMjMuNDcsLTExNC44NyAyMjguMiwtMTA1LjM4IDIxOC41OSwtMTA5Ljg1IDIyMy40NywtMTE0Ljg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjA3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIzNC42NSwtNzIuNzZDMjMwLjI5LC02NC4yOCAyMjQuODUsLTUzLjcxIDIxOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyMjIuOTksLTQyLjQ0IDIxNS4zLC0zNS4xNSAyMTYuNzcsLTQ1LjY0IDIyMi45OSwtNDIuNDQiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlOSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjUxLjM1LC03Mi43NkMyNTUuNzEsLTY0LjI4IDI2MS4xNSwtNTMuNzEgMjY2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjI2OS4yMywtNDUuNjQgMjcwLjcsLTM1LjE1IDI2My4wMSwtNDIuNDQgMjY5LjIzLC00NS42NCIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},3037:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMzEwLC0yNTYgMzEwLDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMjYuNjUsLTIxNi43NkMxMjIuMjksLTIwOC4yOCAxMTYuODUsLTE5Ny43MSAxMTEuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjExNC45OSwtMTg2LjQ0IDEwNy4zLC0xNzkuMTUgMTA4Ljc3LC0xODkuNjQgMTE0Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTQzLjM1LC0yMTYuNzZDMTQ3LjcxLC0yMDguMjggMTUzLjE1LC0xOTcuNzEgMTU4LjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNjEuMjMsLTE4OS42NCAxNjIuNywtMTc5LjE1IDE1NS4wMSwtMTg2LjQ0IDE2MS4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtMMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O0wxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNODQuNDMsLTE0Ni44M0M3NC4yNSwtMTM2Ljk0IDYwLjQ4LC0xMjMuNTUgNDguOTcsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xODwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjIzLjQ3LC0xMTQuODcgMjI4LjIsLTEwNS4zOCAyMTguNTksLTEwOS44NSAyMjMuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMzQuNjUsLTcyLjc2QzIzMC4yOSwtNjQuMjggMjI0Ljg1LC01My43MSAyMTkuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjIyLjk5LC00Mi40NCAyMTUuMywtMzUuMTUgMjE2Ljc3LC00NS42NCAyMjIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjc5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},4236:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiAzMTAsLTI1NiAzMTAsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NTwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNDMuMzUsLTIxNi43NkMxNDcuNzEsLTIwOC4yOCAxNTMuMTUsLTE5Ny43MSAxNTguMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE2MS4yMywtMTg5LjY0IDE2Mi43LC0xNzkuMTUgMTU1LjAxLC0xODYuNDQgMTYxLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MjwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDsxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjUxLjQxLC0xMDkuODUgNDEuOCwtMTA1LjM4IDQ2LjUzLC0xMTQuODcgNTEuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC0xNDMuN0M5OSwtMTM1Ljk4IDk5LC0xMjYuNzEgOTksLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxMDIuNSwtMTE4LjEgOTksLTEwOC4xIDk1LjUsLTExOC4xIDEwMi41LC0xMTguMSIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI3LC03MS43QzI3LC02My45OCAyNywtNTQuNzEgMjcsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjMwLjUsLTQ2LjEgMjcsLTM2LjEgMjMuNSwtNDYuMSAzMC41LC00Ni4xIi8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNNDEuNTcsLTc0LjgzQzUxLjc1LC02NC45NCA2NS41MiwtNTEuNTUgNzcuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9Ijc5LjQ3LC00Mi44NyA4NC4yLC0zMy4zOCA3NC41OSwtMzcuODUgNzkuNDcsLTQyLjg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE3MSwtMTQzLjdDMTcxLC0xMzUuOTggMTcxLC0xMjYuNzEgMTcxLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTc0LjUsLTExOC4xIDE3MSwtMTA4LjEgMTY3LjUsLTExOC4xIDE3NC41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE4PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTg1LjU3LC0xNDYuODNDMTk1Ljc1LC0xMzYuOTQgMjA5LjUyLC0xMjMuNTUgMjIxLjAzLC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjIyMy40NywtMTE0Ljg3IDIyOC4yLC0xMDUuMzggMjE4LjU5LC0xMDkuODUgMjIzLjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTAiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjA3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIzNC42NSwtNzIuNzZDMjMwLjI5LC02NC4yOCAyMjQuODUsLTUzLjcxIDIxOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyMjIuOTksLTQyLjQ0IDIxNS4zLC0zNS4xNSAyMTYuNzcsLTQ1LjY0IDIyMi45OSwtNDIuNDQiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjc5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNTEuMzUsLTcyLjc2QzI1NS43MSwtNjQuMjggMjYxLjE1LC01My43MSAyNjYuMDQsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjY5LjIzLC00NS42NCAyNzAuNywtMzUuMTUgMjYzLjAxLC00Mi40NCAyNjkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},4961:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMzEwLC0yNTYgMzEwLDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMjYuNjUsLTIxNi43NkMxMjIuMjksLTIwOC4yOCAxMTYuODUsLTE5Ny43MSAxMTEuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjExNC45OSwtMTg2LjQ0IDEwNy4zLC0xNzkuMTUgMTA4Ljc3LC0xODkuNjQgMTE0Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTQzLjM1LC0yMTYuNzZDMTQ3LjcxLC0yMDguMjggMTUzLjE1LC0xOTcuNzEgMTU4LjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNjEuMjMsLTE4OS42NCAxNjIuNywtMTc5LjE1IDE1NS4wMSwtMTg2LjQ0IDE2MS4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MjwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDsxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNywtNzEuN0MyNywtNjMuOTggMjcsLTU0LjcxIDI3LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzMC41LC00Ni4xIDI3LC0zNi4xIDIzLjUsLTQ2LjEgMzAuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTQxLjU3LC03NC44M0M1MS43NSwtNjQuOTQgNjUuNTIsLTUxLjU1IDc3LjAzLC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI3OS40NywtNDIuODcgODQuMiwtMzMuMzggNzQuNTksLTM3Ljg1IDc5LjQ3LC00Mi44NyIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGU5IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjE4PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTg1LjU3LC0xNDYuODNDMTk1Ljc1LC0xMzYuOTQgMjA5LjUyLC0xMjMuNTUgMjIxLjAzLC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMjMuNDcsLTExNC44NyAyMjguMiwtMTA1LjM4IDIxOC41OSwtMTA5Ljg1IDIyMy40NywtMTE0Ljg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTEwIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMzQuNjUsLTcyLjc2QzIzMC4yOSwtNjQuMjggMjI0Ljg1LC01My43MSAyMTkuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjIyLjk5LC00Mi40NCAyMTUuMywtMzUuMTUgMjE2Ljc3LC00NS42NCAyMjIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjUxLjM1LC03Mi43NkMyNTUuNzEsLTY0LjI4IDI2MS4xNSwtNTMuNzEgMjY2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjI2OS4yMywtNDUuNjQgMjcwLjcsLTM1LjE1IDI2My4wMSwtNDIuNDQgMjY5LjIzLC00NS42NCIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},376:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiA0MTgsLTI1NiA0MTgsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyMDciIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyMDciIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xOTguNjUsLTIxNi43NkMxOTQuMjksLTIwOC4yOCAxODguODUsLTE5Ny43MSAxODMuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE4Ni45OSwtMTg2LjQ0IDE3OS4zLC0xNzkuMTUgMTgwLjc3LC0xODkuNjQgMTg2Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTM5MiAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDUzOTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMjQzIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDUzOTIgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjA1MzkyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIxNS4zNSwtMjE2Ljc2QzIxOS43MSwtMjA4LjI4IDIyNS4xNSwtMTk3LjcxIDIzMC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjMzLjIzLC0xODkuNjQgMjM0LjcsLTE3OS4xNSAyMjcuMDEsLTE4Ni40NCAyMzMuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4yPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTU2LjQzLC0xNDYuODNDMTQ2LjI1LC0xMzYuOTQgMTMyLjQ4LC0xMjMuNTUgMTIwLjk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjEyMy40MSwtMTA5Ljg1IDExMy44LC0xMDUuMzggMTE4LjUzLC0xMTQuODcgMTIzLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTc0LjgzQzc0LjI1LC02NC45NCA2MC40OCwtNTEuNTUgNDguOTcsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjUxLjQxLC0zNy44NSA0MS44LC0zMy4zOCA0Ni41MywtNDIuODcgNTEuNDEsLTM3Ljg1Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNOTksLTcxLjdDOTksLTYzLjk4IDk5LC01NC43MSA5OSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTQ2LjEgOTksLTM2LjEgOTUuNSwtNDYuMSAxMDIuNSwtNDYuMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjQzLC0xNDMuN0MyNDMsLTEzNS45OCAyNDMsLTEyNi43MSAyNDMsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjQ2LjUsLTExOC4xIDI0MywtMTA4LjEgMjM5LjUsLTExOC4xIDI0Ni41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjMxNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzE1IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xODwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0yNTcuNTcsLTE0Ni44M0MyNjcuNzUsLTEzNi45NCAyODEuNTIsLTEyMy41NSAyOTMuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjk1LjQ3LC0xMTQuODcgMzAwLjIsLTEwNS4zOCAyOTAuNTksLTEwOS44NSAyOTUuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU5IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlOCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yMjguNDMsLTc0LjgzQzIxOC4yNSwtNjQuOTQgMjA0LjQ4LC01MS41NSAxOTIuOTcsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE5NS40MSwtMzcuODUgMTg1LjgsLTMzLjM4IDE5MC41MywtNDIuODcgMTk1LjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNDMiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtSMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O1IxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjQzLC03MS43QzI0MywtNjMuOTggMjQzLC01NC43MSAyNDMsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjI0Ni41LC00Ni4xIDI0MywtMzYuMSAyMzkuNSwtNDYuMSAyNDYuNSwtNDYuMSIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIzMTUiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjgmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTMxNSwtNzEuN0MzMTUsLTYzLjk4IDMxNSwtNTQuNzEgMzE1LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzMTguNSwtNDYuMSAzMTUsLTM2LjEgMzExLjUsLTQ2LjEgMzE4LjUsLTQ2LjEiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMjkuNTcsLTc0LjgzQzMzOS43NSwtNjQuOTQgMzUzLjUyLC01MS41NSAzNjUuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjM2Ny40NywtNDIuODcgMzcyLjIsLTMzLjM4IDM2Mi41OSwtMzcuODUgMzY3LjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},6061:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgNDE4LC0yNTYgNDE4LDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjA3IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjA3IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE5OC42NSwtMjE2Ljc2QzE5NC4yOSwtMjA4LjI4IDE4OC44NSwtMTk3LjcxIDE4My45NiwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTg2Ljk5LC0xODYuNDQgMTc5LjMsLTE3OS4xNSAxODAuNzcsLTE4OS42NCAxODYuOTksLTE4Ni40NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNDMiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjE1PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjA1MzkyIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwNTM5MjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yMTUuMzUsLTIxNi43NkMyMTkuNzEsLTIwOC4yOCAyMjUuMTUsLTE5Ny43MSAyMzAuMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIzMy4yMywtMTg5LjY0IDIzNC43LC0xNzkuMTUgMjI3LjAxLC0xODYuNDQgMjMzLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTU2LjQzLC0xNDYuODNDMTQ2LjI1LC0xMzYuOTQgMTMyLjQ4LC0xMjMuNTUgMTIwLjk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIxMjMuNDEsLTEwOS44NSAxMTMuOCwtMTA1LjM4IDExOC41MywtMTE0Ljg3IDEyMy40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE3MSwtMTQzLjdDMTcxLC0xMzUuOTggMTcxLC0xMjYuNzEgMTcxLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTc0LjUsLTExOC4xIDE3MSwtMTA4LjEgMTY3LjUsLTExOC4xIDE3NC41LC0xMTguMSIvPgo8L2c+CjwhLS0gTDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjQzLC0xNDMuN0MyNDMsLTEzNS45OCAyNDMsLTEyNi43MSAyNDMsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjI0Ni41LC0xMTguMSAyNDMsLTEwOC4xIDIzOS41LC0xMTguMSAyNDYuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIzMTUiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMxNSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xODwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0yNTcuNTcsLTE0Ni44M0MyNjcuNzUsLTEzNi45NCAyODEuNTIsLTEyMy41NSAyOTMuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjI5NS40NywtMTE0Ljg3IDMwMC4yLC0xMDUuMzggMjkwLjU5LC0xMDkuODUgMjk1LjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlOSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0O0wxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjI4LjQzLC03NC44M0MyMTguMjUsLTY0Ljk0IDIwNC40OCwtNTEuNTUgMTkyLjk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxOTUuNDEsLTM3Ljg1IDE4NS44LC0zMy4zOCAxOTAuNTMsLTQyLjg3IDE5NS40MSwtMzcuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJub2RlMTAiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjQzIiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7UjE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtSMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI0MywtNzEuN0MyNDMsLTYzLjk4IDI0MywtNTQuNzEgMjQzLC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNDYuNSwtNDYuMSAyNDMsLTM2LjEgMjM5LjUsLTQ2LjEgMjQ2LjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMTUsLTcxLjdDMzE1LC02My45OCAzMTUsLTU0LjcxIDMxNSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzE4LjUsLTQ2LjEgMzE1LC0zNi4xIDMxMS41LC00Ni4xIDMxOC41LC00Ni4xIi8+CjwvZz4KPCEtLSBSMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjM4NyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDM2OCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzI5LjU3LC03NC44M0MzMzkuNzUsLTY0Ljk0IDM1My41MiwtNTEuNTUgMzY1LjAzLC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNjcuNDcsLTQyLjg3IDM3Mi4yLC0zMy4zOCAzNjIuNTksLTM3Ljg1IDM2Ny40NywtNDIuODciLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},9010:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjMzMnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAzMzIuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMzI4KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTMyOCA0MTgsLTMyOCA0MTgsNCAtNCw0Ii8+CjwhLS0gMTQwMzk5ODA1OTEwNjcyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyMDciIGN5PSItMzA2IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyMDciIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xOTguNjUsLTI4OC43NkMxOTQuMjksLTI4MC4yOCAxODguODUsLTI2OS43MSAxODMuOTYsLTI2MC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE4Ni45OSwtMjU4LjQ0IDE3OS4zLC0yNTEuMTUgMTgwLjc3LC0yNjEuNjQgMTg2Ljk5LC0yNTguNDQiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTM5MiAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDUzOTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE1PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA1NjA1MzkyIC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwNTM5MjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjE1LjM1LC0yODguNzZDMjE5LjcxLC0yODAuMjggMjI1LjE1LC0yNjkuNzEgMjMwLjA0LC0yNjAuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjMzLjIzLC0yNjEuNjQgMjM0LjcsLTI1MS4xNSAyMjcuMDEsLTI1OC40NCAyMzMuMjMsLTI2MS42NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDsxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xNTYuNDMsLTIxOC44M0MxNDYuMjUsLTIwOC45NCAxMzIuNDgsLTE5NS41NSAxMjAuOTcsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTIzLjQxLC0xODEuODUgMTEzLjgsLTE3Ny4zOCAxMTguNTMsLTE4Ni44NyAxMjMuNDEsLTE4MS44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNDE0MjkyOCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDQxNDI5MjgmIzQ1OyZndDtSMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC0yMTUuN0MxNzEsLTIwNy45OCAxNzEsLTE5OC43MSAxNzEsLTE5MC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNzQuNSwtMTkwLjEgMTcxLC0xODAuMSAxNjcuNSwtMTkwLjEgMTc0LjUsLTE5MC4xIi8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtMMTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzMDQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTE0Ni44M0M3NC4yNSwtMTM2Ljk0IDYwLjQ4LC0xMjMuNTUgNDguOTcsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O1IxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMjQzIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDUzOTImIzQ1OyZndDsxNDAzOTk4MDU2MDMyODAgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI0MywtMjE1LjdDMjQzLC0yMDcuOTggMjQzLC0xOTguNzEgMjQzLC0xOTAuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjQ2LjUsLTE5MC4xIDI0MywtMTgwLjEgMjM5LjUsLTE5MC4xIDI0Ni41LC0xOTAuMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMzE1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzE1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDUzOTImIzQ1OyZndDsxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNTcuNTcsLTIxOC44M0MyNjcuNzUsLTIwOC45NCAyODEuNTIsLTE5NS41NSAyOTMuMDMsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyOTUuNDcsLTE4Ni44NyAzMDAuMiwtMTc3LjM4IDI5MC41OSwtMTgxLjg1IDI5NS40NywtMTg2Ljg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIyOC40MywtMTQ2LjgzQzIxOC4yNSwtMTM2Ljk0IDIwNC40OCwtMTIzLjU1IDE5Mi45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE5NS40MSwtMTA5Ljg1IDE4NS44LC0xMDUuMzggMTkwLjUzLC0xMTQuODcgMTk1LjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTM8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDU2MDU0NTYgLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7MTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0yNDMsLTE0My43QzI0MywtMTM1Ljk4IDI0MywtMTI2LjcxIDI0MywtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjA1NDU2IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTQ1NiYjNDU7Jmd0O0wxNDAzOTk4MDU2MDU0NTYgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTQ1NiYjNDU7Jmd0O0wxNDAzOTk4MDU2MDU0NTY8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTYwNTQ1NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDU0NTYmIzQ1OyZndDtSMTQwMzk5ODA1NjA1NDU2IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDU0NTYmIzQ1OyZndDtSMTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMTUsLTE0My43QzMxNSwtMTM1Ljk4IDMxNSwtMTI2LjcxIDMxNSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjMxOC41LC0xMTguMSAzMTUsLTEwOC4xIDMxMS41LC0xMTguMSAzMTguNSwtMTE4LjEiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMjkuNTcsLTE0Ni44M0MzMzkuNzUsLTEzNi45NCAzNTMuNTIsLTEyMy41NSAzNjUuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzNjcuNDcsLTExNC44NyAzNzIuMiwtMTA1LjM4IDM2Mi41OSwtMTA5Ljg1IDM2Ny40NywtMTE0Ljg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},7115:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjMzMnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAzMzIuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMzI4KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0zMjggNDE4LC0zMjggNDE4LDQgLTQsNCIvPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjA3IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjA3IiB5PSItMzAyLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1OTEwNjcyJiM0NTsmZ3Q7MTQwMzk5ODA0MTQyOTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE5OC42NSwtMjg4Ljc2QzE5NC4yOSwtMjgwLjI4IDE4OC44NSwtMjY5LjcxIDE4My45NiwtMjYwLjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTg2Ljk5LC0yNTguNDQgMTc5LjMsLTI1MS4xNSAxODAuNzcsLTI2MS42NCAxODYuOTksLTI1OC40NCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xNTwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTkxMDY3MiYjNDU7Jmd0OzE0MDM5OTgwNTYwNTM5MiAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU5MTA2NzImIzQ1OyZndDsxNDAzOTk4MDU2MDUzOTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTIxNS4zNSwtMjg4Ljc2QzIxOS43MSwtMjgwLjI4IDIyNS4xNSwtMjY5LjcxIDIzMC4wNCwtMjYwLjIiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMzMuMjMsLTI2MS42NCAyMzQuNywtMjUxLjE1IDIyNy4wMSwtMjU4LjQ0IDIzMy4yMywtMjYxLjY0Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7MTQwMzk5ODA1NzAwMzA0IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0OzE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTU2LjQzLC0yMTguODNDMTQ2LjI1LC0yMDguOTQgMTMyLjQ4LC0xOTUuNTUgMTIwLjk3LC0xODQuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIxMjMuNDEsLTE4MS44NSAxMTMuOCwtMTc3LjM4IDExOC41MywtMTg2Ljg3IDEyMy40MSwtMTgxLjg1Ii8+CjwvZz4KPCEtLSBSMTQwMzk5ODA0MTQyOTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDQxNDI5Mjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNDE0MjkyOCYjNDU7Jmd0O1IxNDAzOTk4MDQxNDI5MjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA0MTQyOTI4JiM0NTsmZ3Q7UjE0MDM5OTgwNDE0MjkyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzEsLTIxNS43QzE3MSwtMjA3Ljk4IDE3MSwtMTk4LjcxIDE3MSwtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC0xOTAuMSAxNzEsLTE4MC4xIDE2Ny41LC0xOTAuMSAxNzQuNSwtMTkwLjEiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDMwNCYjNDU7Jmd0O0wxNDAzOTk4MDU3MDAzMDQgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDMwNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjUxLjQxLC0xMDkuODUgNDEuOCwtMTA1LjM4IDQ2LjUzLC0xMTQuODcgNTEuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzA0JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDMwNCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU3MDAzMDQmIzQ1OyZndDtSMTQwMzk5ODA1NzAwMzA0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC0xNDMuN0M5OSwtMTM1Ljk4IDk5LC0xMjYuNzEgOTksLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMDIuNSwtMTE4LjEgOTksLTEwOC4xIDk1LjUsLTExOC4xIDEwMi41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNDMiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTQwMzk5ODA1NjA1MzkyJiM0NTsmZ3Q7MTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTYwMzI4MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNDMsLTIxNS43QzI0MywtMjA3Ljk4IDI0MywtMTk4LjcxIDI0MywtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjI0Ni41LC0xOTAuMSAyNDMsLTE4MC4xIDIzOS41LC0xOTAuMSAyNDYuNSwtMTkwLjEiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9Im5vZGUxMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjMxNSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMxNSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDUzOTImIzQ1OyZndDsxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTM5MiYjNDU7Jmd0OzE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNTcuNTcsLTIxOC44M0MyNjcuNzUsLTIwOC45NCAyODEuNTIsLTE5NS41NSAyOTMuMDMsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyOTUuNDcsLTE4Ni44NyAzMDAuMiwtMTc3LjM4IDI5MC41OSwtMTgxLjg1IDI5NS40NywtMTg2Ljg3Ii8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjAzMjgwIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU2MDMyODA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NjAzMjgwJiM0NTsmZ3Q7TDE0MDM5OTgwNTYwMzI4MCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDtMMTQwMzk5ODA1NjAzMjgwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTIyOC40MywtMTQ2LjgzQzIxOC4yNSwtMTM2Ljk0IDIwNC40OCwtMTIzLjU1IDE5Mi45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE5NS40MSwtMTA5Ljg1IDE4NS44LC0xMDUuMzggMTkwLjUzLC0xMTQuODcgMTk1LjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMzwvdGV4dD4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwMzI4MCYjNDU7Jmd0OzE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDMyODAmIzQ1OyZndDsxNDAzOTk4MDU2MDU0NTY8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTI0MywtMTQzLjdDMjQzLC0xMzUuOTggMjQzLC0xMjYuNzEgMjQzLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTQwMzk5ODA1NjA1NDU2IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDE0MDM5OTgwNTYwNTQ1NiYjNDU7Jmd0O0wxNDAzOTk4MDU2MDU0NTYgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjE0MDM5OTgwNTYwNTQ1NiYjNDU7Jmd0O0wxNDAzOTk4MDU2MDU0NTY8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjE0MDM5OTgwNTYwNTQ1NiAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjE0MDM5OTgwNTYwNTQ1NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxNDAzOTk4MDU2MDU0NTYmIzQ1OyZndDtSMTQwMzk5ODA1NjA1NDU2IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xNDAzOTk4MDU2MDU0NTYmIzQ1OyZndDtSMTQwMzk5ODA1NjA1NDU2PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIEwxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7TDE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMTUsLTE0My43QzMxNSwtMTM1Ljk4IDMxNSwtMTI2LjcxIDMxNSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMxOC41LC0xMTguMSAzMTUsLTEwOC4xIDMxMS41LC0xMTguMSAzMTguNSwtMTE4LjEiLz4KPC9nPgo8IS0tIFIxNDAzOTk4MDU3MDAzNjggLS0+CjxnIGlkPSJub2RlMTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxNDAzOTk4MDU3MDAzNjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2OCAtLT4KPGcgaWQ9ImVkZ2UxNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTQwMzk5ODA1NzAwMzY4JiM0NTsmZ3Q7UjE0MDM5OTgwNTcwMDM2ODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMjkuNTcsLTE0Ni44M0MzMzkuNzUsLTEzNi45NCAzNTMuNTIsLTEyMy41NSAzNjUuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNjcuNDcsLTExNC44NyAzNzIuMiwtMTA1LjM4IDM2Mi41OSwtMTA5Ljg1IDM2Ny40NywtMTE0Ljg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2399:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/br_7_dark-48445480725921bc67664cac9f225476.svg"},7239:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/br_7_light-e3494c1dc9b1d352580427c76be40a01.svg"},2705:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/br_8_dark-e63a22ae61187d5745542c84a04ded26.svg"},1461:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/br_8_light-10d25c55c1838a408ab5dad21a9da058.svg"},3591:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjEzNHB0IiBoZWlnaHQ9IjExNnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDEzNC4wMCAxMTYuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTEyKSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTExMiAxMzAsLTExMiAxMzAsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iNjMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjYzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xMjwvdGV4dD4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtSMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2227:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjEzNHB0IiBoZWlnaHQ9IjExNnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDEzNC4wMCAxMTYuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTEyKSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xMTIgMTMwLC0xMTIgMTMwLDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjYzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI2MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMjwvdGV4dD4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtSMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},7690:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjE3MHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDE3MC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTE4NCAxNjYsLTE4NCAxNjYsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik05MC42NSwtMTQ0Ljc2Qzg2LjI5LC0xMzYuMjggODAuODUsLTEyNS43MSA3NS45NiwtMTE2LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9Ijc4Ljk5LC0xMTQuNDQgNzEuMywtMTA3LjE1IDcyLjc3LC0xMTcuNjQgNzguOTksLTExNC40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjEzNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xMDcuMzUsLTE0NC43NkMxMTEuNzEsLTEzNi4yOCAxMTcuMTUsLTEyNS43MSAxMjIuMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEyNS4yMywtMTE3LjY0IDEyNi43LC0xMDcuMTUgMTE5LjAxLC0xMTQuNDQgMTI1LjIzLC0xMTcuNjQiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O0wxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},6805:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjE3MHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDE3MC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xODQgMTY2LC0xODQgMTY2LDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI2MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iNjMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTkwLjY1LC0xNDQuNzZDODYuMjksLTEzNi4yOCA4MC44NSwtMTI1LjcxIDc1Ljk2LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9Ijc4Ljk5LC0xMTQuNDQgNzEuMywtMTA3LjE1IDcyLjc3LC0xMTcuNjQgNzguOTksLTExNC40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjEzNSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xMDcuMzUsLTE0NC43NkMxMTEuNzEsLTEzNi4yOCAxMTcuMTUsLTEyNS43MSAxMjIuMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEyNS4yMywtMTE3LjY0IDEyNi43LC0xMDcuMTUgMTE5LjAxLC0xMTQuNDQgMTI1LjIzLC0xMTcuNjQiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O0wxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik01NC42NSwtNzIuNzZDNTAuMjksLTY0LjI4IDQ0Ljg1LC01My43MSAzOS45NiwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI0Mi45OSwtNDIuNDQgMzUuMywtMzUuMTUgMzYuNzcsLTQ1LjY0IDQyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTcxLjM1LC03Mi43NkM3NS43MSwtNjQuMjggODEuMTUsLTUzLjcxIDg2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9Ijg5LjIzLC00NS42NCA5MC43LC0zNS4xNSA4My4wMSwtNDIuNDQgODkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},9861:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjI3OHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDI3OC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTE4NCAyNzQsLTE4NCAyNzQsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxMzUiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxMzUiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTI2LjY1LC0xNDQuNzZDMTIyLjI5LC0xMzYuMjggMTE2Ljg1LC0xMjUuNzEgMTExLjk2LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTE0Ljk5LC0xMTQuNDQgMTA3LjMsLTEwNy4xNSAxMDguNzcsLTExNy42NCAxMTQuOTksLTExNC40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTQiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTQzLjM1LC0xNDQuNzZDMTQ3LjcxLC0xMzYuMjggMTUzLjE1LC0xMjUuNzEgMTU4LjA0LC0xMTYuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTYxLjIzLC0xMTcuNjQgMTYyLjcsLTEwNy4xNSAxNTUuMDEsLTExNC40NCAxNjEuMjMsLTExNy42NCIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtMMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC03MS43QzE3MSwtNjMuOTggMTcxLC01NC43MSAxNzEsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC00Ni4xIDE3MSwtMzYuMSAxNjcuNSwtNDYuMSAxNzQuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xODUuNTcsLTc0LjgzQzE5NS43NSwtNjQuOTQgMjA5LjUyLC01MS41NSAyMjEuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMy40NywtNDIuODcgMjI4LjIsLTMzLjM4IDIxOC41OSwtMzcuODUgMjIzLjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},7676:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjI3OHB0IiBoZWlnaHQ9IjE4OHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDI3OC4wMCAxODguMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMTg0KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0xODQgMjc0LC0xODQgMjc0LDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTM1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xMjYuNjUsLTE0NC43NkMxMjIuMjksLTEzNi4yOCAxMTYuODUsLTEyNS43MSAxMTEuOTYsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTE0Ljk5LC0xMTQuNDQgMTA3LjMsLTEwNy4xNSAxMDguNzcsLTExNy42NCAxMTQuOTksLTExNC40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xNDMuMzUsLTE0NC43NkMxNDcuNzEsLTEzNi4yOCAxNTMuMTUsLTEyNS43MSAxNTguMDQsLTExNi4yIi8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTYxLjIzLC0xMTcuNjQgMTYyLjcsLTEwNy4xNSAxNTUuMDEsLTExNC40NCAxNjEuMjMsLTExNy42NCIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtMMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC03MS43QzE3MSwtNjMuOTggMTcxLC01NC43MSAxNzEsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC00Ni4xIDE3MSwtMzYuMSAxNjcuNSwtNDYuMSAxNzQuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xODUuNTcsLTc0LjgzQzE5NS43NSwtNjQuOTQgMjA5LjUyLC01MS41NSAyMjEuMDMsLTQwLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMy40NywtNDIuODcgMjI4LjIsLTMzLjM4IDIxOC41OSwtMzcuODUgMjIzLjQ3LC00Mi44NyIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},4110:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiAzMTAsLTI1NiAzMTAsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTEyNi42NSwtMjE2Ljc2QzEyMi4yOSwtMjA4LjI4IDExNi44NSwtMTk3LjcxIDExMS45NiwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTE0Ljk5LC0xODYuNDQgMTA3LjMsLTE3OS4xNSAxMDguNzcsLTE4OS42NCAxMTQuOTksLTE4Ni40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTQzLjM1LC0yMTYuNzZDMTQ3LjcxLC0yMDguMjggMTUzLjE1LC0xOTcuNzEgMTU4LjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNjEuMjMsLTE4OS42NCAxNjIuNywtMTc5LjE1IDE1NS4wMSwtMTg2LjQ0IDE2MS4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtMMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O0wxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTE0Ni44M0M3NC4yNSwtMTM2Ljk0IDYwLjQ4LC0xMjMuNTUgNDguOTcsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xODUuNTcsLTE0Ni44M0MxOTUuNzUsLTEzNi45NCAyMDkuNTIsLTEyMy41NSAyMjEuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjIzLjQ3LC0xMTQuODcgMjI4LjIsLTEwNS4zOCAyMTguNTksLTEwOS44NSAyMjMuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yMzQuNjUsLTcyLjc2QzIzMC4yOSwtNjQuMjggMjI0Ljg1LC01My43MSAyMTkuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjIyLjk5LC00Mi40NCAyMTUuMywtMzUuMTUgMjE2Ljc3LC00NS42NCAyMjIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjc5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},7632:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMzEwLC0yNTYgMzEwLDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjEzNSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjEzNSIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE0My4zNSwtMjE2Ljc2QzE0Ny43MSwtMjA4LjI4IDE1My4xNSwtMTk3LjcxIDE1OC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYxLjIzLC0xODkuNjQgMTYyLjcsLTE3OS4xNSAxNTUuMDEsLTE4Ni40NCAxNjEuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7TDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtMMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTg0LjQzLC0xNDYuODNDNzQuMjUsLTEzNi45NCA2MC40OCwtMTIzLjU1IDQ4Ljk3LC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE3MSwtMTQzLjdDMTcxLC0xMzUuOTggMTcxLC0xMjYuNzEgMTcxLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTc0LjUsLTExOC4xIDE3MSwtMTA4LjEgMTY3LjUsLTExOC4xIDE3NC41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xODUuNTcsLTE0Ni44M0MxOTUuNzUsLTEzNi45NCAyMDkuNTIsLTEyMy41NSAyMjEuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJyZWQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjIyMy40NywtMTE0Ljg3IDIyOC4yLC0xMDUuMzggMjE4LjU5LC0xMDkuODUgMjIzLjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyMDciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtMMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGU5IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlOCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNTEuMzUsLTcyLjc2QzI1NS43MSwtNjQuMjggMjYxLjE1LC01My43MSAyNjYuMDQsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjY5LjIzLC00NS42NCAyNzAuNywtMzUuMTUgMjYzLjAxLC00Mi40NCAyNjkuMjMsLTQ1LjY0Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},9418:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiAzMTAsLTI1NiAzMTAsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMTM1IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTM1IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTEyNi42NSwtMjE2Ljc2QzEyMi4yOSwtMjA4LjI4IDExNi44NSwtMTk3LjcxIDExMS45NiwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTE0Ljk5LC0xODYuNDQgMTA3LjMsLTE3OS4xNSAxMDguNzcsLTE4OS42NCAxMTQuOTksLTE4Ni40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTQzLjM1LC0yMTYuNzZDMTQ3LjcxLC0yMDguMjggMTUzLjE1LC0xOTcuNzEgMTU4LjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNjEuMjMsLTE4OS42NCAxNjIuNywtMTc5LjE1IDE1NS4wMSwtMTg2LjQ0IDE2MS4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjciIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJub2RlNiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNywtNzEuN0MyNywtNjMuOTggMjcsLTU0LjcxIDI3LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzMC41LC00Ni4xIDI3LC0zNi4xIDIzLjUsLTQ2LjEgMzAuNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtSMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTQxLjU3LC03NC44M0M1MS43NSwtNjQuOTQgNjUuNTIsLTUxLjU1IDc3LjAzLC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI3OS40NywtNDIuODcgODQuMiwtMzMuMzggNzQuNTksLTM3Ljg1IDc5LjQ3LC00Mi44NyIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGU5IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xODwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMjMuNDcsLTExNC44NyAyMjguMiwtMTA1LjM4IDIxOC41OSwtMTA5Ljg1IDIyMy40NywtMTE0Ljg3Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTEwIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yMzQuNjUsLTcyLjc2QzIzMC4yOSwtNjQuMjggMjI0Ljg1LC01My43MSAyMTkuOTYsLTQ0LjIiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjIyLjk5LC00Mi40NCAyMTUuMywtMzUuMTUgMjE2Ljc3LC00NS42NCAyMjIuOTksLTQyLjQ0Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjUxLjM1LC03Mi43NkMyNTUuNzEsLTY0LjI4IDI2MS4xNSwtNTMuNzEgMjY2LjA0LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjI2OS4yMywtNDUuNjQgMjcwLjcsLTM1LjE1IDI2My4wMSwtNDIuNDQgMjY5LjIzLC00NS42NCIvPgo8L2c+CjwvZz4KPC9zdmc+Cg=="},7109:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjMxNHB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDMxNC4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgMzEwLC0yNTYgMzEwLDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjEzNSIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjEzNSIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+NTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTI2LjY1LC0yMTYuNzZDMTIyLjI5LC0yMDguMjggMTE2Ljg1LC0xOTcuNzEgMTExLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMTQuOTksLTE4Ni40NCAxMDcuMywtMTc5LjE1IDEwOC43NywtMTg5LjY0IDExNC45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjE3MSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE0My4zNSwtMjE2Ljc2QzE0Ny43MSwtMjA4LjI4IDE1My4xNSwtMTk3LjcxIDE1OC4wNCwtMTg4LjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTYxLjIzLC0xODkuNjQgMTYyLjcsLTE3OS4xNSAxNTUuMDEsLTE4Ni40NCAxNjEuMjMsLTE4OS42NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI3IiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iNTEuNDEsLTEwOS44NSA0MS44LC0xMDUuMzggNDYuNTMsLTExNC44NyA1MS40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iOTkiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNOTksLTE0My43Qzk5LC0xMzUuOTggOTksLTEyNi43MSA5OSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjEwMi41LC0xMTguMSA5OSwtMTA4LjEgOTUuNSwtMTE4LjEgMTAyLjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtMMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjcsLTcxLjdDMjcsLTYzLjk4IDI3LC01NC43MSAyNywtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzAuNSwtNDYuMSAyNywtMzYuMSAyMy41LC00Ni4xIDMwLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik00MS41NywtNzQuODNDNTEuNzUsLTY0Ljk0IDY1LjUyLC01MS41NSA3Ny4wMywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNzkuNDcsLTQyLjg3IDg0LjIsLTMzLjM4IDc0LjU5LC0zNy44NSA3OS40NywtNDIuODciLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMTcxLC0xNDMuN0MxNzEsLTEzNS45OCAxNzEsLTEyNi43MSAxNzEsLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxNzQuNSwtMTE4LjEgMTcxLC0xMDguMSAxNjcuNSwtMTE4LjEgMTc0LjUsLTExOC4xIi8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlOSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xODwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE4NS41NywtMTQ2LjgzQzE5NS43NSwtMTM2Ljk0IDIwOS41MiwtMTIzLjU1IDIyMS4wMywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjIzLjQ3LC0xMTQuODcgMjI4LjIsLTEwNS4zOCAyMTguNTksLTEwOS44NSAyMjMuNDcsLTExNC44NyIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyMDciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtMMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0iZWRnZTkiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0iZWRnZTEwIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},3533:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTI1NiA0MTgsLTI1NiA0MTgsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjA3IiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjA3IiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+NTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2UxIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTk4LjY1LC0yMTYuNzZDMTk0LjI5LC0yMDguMjggMTg4Ljg1LC0xOTcuNzEgMTgzLjk2LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxODYuOTksLTE4Ni40NCAxNzkuMywtMTc5LjE1IDE4MC43NywtMTg5LjY0IDE4Ni45OSwtMTg2LjQ0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQgLS0+CjxnIGlkPSJub2RlNyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkzNDI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgY3g9IjI0MyIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE1PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkzNDI0IC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yMTUuMzUsLTIxNi43NkMyMTkuNzEsLTIwOC4yOCAyMjUuMTUsLTE5Ny43MSAyMzAuMDQsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIzMy4yMywtMTg5LjY0IDIzNC43LC0xNzkuMTUgMjI3LjAxLC0xODYuNDQgMjMzLjIzLC0xODkuNjQiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGUzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0OzEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE1Ni40MywtMTQ2LjgzQzE0Ni4yNSwtMTM2Ljk0IDEzMi40OCwtMTIzLjU1IDEyMC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIxMjMuNDEsLTEwOS44NSAxMTMuOCwtMTA1LjM4IDExOC41MywtMTE0Ljg3IDEyMy40MSwtMTA5Ljg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9ImVkZ2U1IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTE3MSwtMTQzLjdDMTcxLC0xMzUuOTggMTcxLC0xMjYuNzEgMTcxLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTc0LjUsLTExOC4xIDE3MSwtMTA4LjEgMTY3LjUsLTExOC4xIDE3NC41LC0xMTguMSIvPgo8L2c+CjwhLS0gTDEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGU0IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI3IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7TDEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2UzIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtMMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTg0LjQzLC03NC44M0M3NC4yNSwtNjQuOTQgNjAuNDgsLTUxLjU1IDQ4Ljk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMzcuODUgNDEuOCwtMzMuMzggNDYuNTMsLTQyLjg3IDUxLjQxLC0zNy44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtSMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTk5LC03MS43Qzk5LC02My45OCA5OSwtNTQuNzEgOTksLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjEwMi41LC00Ni4xIDk5LC0zNi4xIDk1LjUsLTQ2LjEgMTAyLjUsLTQ2LjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItODYuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTI0MywtMTQzLjdDMjQzLC0xMzUuOTggMjQzLC0xMjYuNzEgMjQzLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjI0Ni41LC0xMTguMSAyNDMsLTEwOC4xIDIzOS41LC0xMTguMSAyNDYuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIzMTUiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMxNSIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjU3LjU3LC0xNDYuODNDMjY3Ljc1LC0xMzYuOTQgMjgxLjUyLC0xMjMuNTUgMjkzLjAzLC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0icmVkIiBwb2ludHM9IjI5NS40NywtMTE0Ljg3IDMwMC4yLC0xMDUuMzggMjkwLjU5LC0xMDkuODUgMjk1LjQ3LC0xMTQuODciLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlOSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIxNzEiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTgiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O0wxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjI4LjQzLC03NC44M0MyMTguMjUsLTY0Ljk0IDIwNC40OCwtNTEuNTUgMTkyLjk3LC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxOTUuNDEsLTM3Ljg1IDE4NS44LC0zMy4zOCAxOTAuNTMsLTQyLjg3IDE5NS40MSwtMzcuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlMTAiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjQzIiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtSMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI0MywtNzEuN0MyNDMsLTYzLjk4IDI0MywtNTQuNzEgMjQzLC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyNDYuNSwtNDYuMSAyNDMsLTM2LjEgMjM5LjUsLTQ2LjEgMjQ2LjUsLTQ2LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMTUsLTcxLjdDMzE1LC02My45OCAzMTUsLTU0LjcxIDMxNSwtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMzE4LjUsLTQ2LjEgMzE1LC0zNi4xIDMxMS41LC00Ni4xIDMxOC41LC00Ni4xIi8+CjwvZz4KPCEtLSBSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjM4NyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMzI5LjU3LC03NC44M0MzMzkuNzUsLTY0Ljk0IDM1My41MiwtNTEuNTUgMzY1LjAzLC00MC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzNjcuNDcsLTQyLjg3IDM3Mi4yLC0zMy4zOCAzNjIuNTksLTM3Ljg1IDM2Ny40NywtNDIuODciLz4KPC9nPgo8L2c+Cjwvc3ZnPgo="},8998:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjI2MHB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAyNjAuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMjU2KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0yNTYgNDE4LC0yNTYgNDE4LDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjIwNyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjIwNyIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+OTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGUyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMTcxIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xOTguNjUsLTIxNi43NkMxOTQuMjksLTIwOC4yOCAxODguODUsLTE5Ny43MSAxODMuOTYsLTE4OC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE4Ni45OSwtMTg2LjQ0IDE3OS4zLC0xNzkuMTUgMTgwLjc3LC0xODkuNjQgMTg2Ljk5LC0xODYuNDQiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQyNCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjQzIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xNTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQyNCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTM0MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjE1LjM1LC0yMTYuNzZDMjE5LjcxLC0yMDguMjggMjI1LjE1LC0xOTcuNzEgMjMwLjA0LC0xODguMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyMzMuMjMsLTE4OS42NCAyMzQuNywtMTc5LjE1IDIyNy4wMSwtMTg2LjQ0IDIzMy4yMywtMTg5LjY0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iOTkiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0OzEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2UyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTE1Ni40MywtMTQ2LjgzQzE0Ni4yNSwtMTM2Ljk0IDEzMi40OCwtMTIzLjU1IDEyMC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InJlZCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTIzLjQxLC0xMDkuODUgMTEzLjgsLTEwNS4zOCAxMTguNTMsLTExNC44NyAxMjMuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzEsLTE0My43QzE3MSwtMTM1Ljk4IDE3MSwtMTI2LjcxIDE3MSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC0xMTguMSAxNzEsLTEwOC4xIDE2Ny41LC0xMTguMSAxNzQuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtNzQuODNDNzQuMjUsLTY0Ljk0IDYwLjQ4LC01MS41NSA0OC45NywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iNTEuNDEsLTM3Ljg1IDQxLjgsLTMzLjM4IDQ2LjUzLC00Mi44NyA1MS40MSwtMzcuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik05OSwtNzEuN0M5OSwtNjMuOTggOTksLTU0LjcxIDk5LC00Ni4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMDIuNSwtNDYuMSA5OSwtMzYuMSA5NS41LC00Ni4xIDEwMi41LC00Ni4xIi8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJub2RlOCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMjwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U3IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTI0MywtMTQzLjdDMjQzLC0xMzUuOTggMjQzLC0xMjYuNzEgMjQzLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIzMTUiIHk9Ii04Ni4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjU3LjU3LC0xNDYuODNDMjY3Ljc1LC0xMzYuOTQgMjgxLjUyLC0xMjMuNTUgMjkzLjAzLC0xMTIuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyOTUuNDcsLTExNC44NyAzMDAuMiwtMTA1LjM4IDI5MC41OSwtMTA5Ljg1IDI5NS40NywtMTE0Ljg3Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTE4IiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTIyOC40MywtNzQuODNDMjE4LjI1LC02NC45NCAyMDQuNDgsLTUxLjU1IDE5Mi45NywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTk1LjQxLC0zNy44NSAxODUuOCwtMzMuMzggMTkwLjUzLC00Mi44NyAxOTUuNDEsLTM3Ljg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTEwIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjI0MyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0O1IxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7UjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNDMsLTcxLjdDMjQzLC02My45OCAyNDMsLTU0LjcxIDI0MywtNDYuMTEiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMjQ2LjUsLTQ2LjEgMjQzLC0zNi4xIDIzOS41LC00Ni4xIDI0Ni41LC00Ni4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTEyIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjMxNSIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4NzgyNCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMzE1LC03MS43QzMxNSwtNjMuOTggMzE1LC01NC43MSAzMTUsLTQ2LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMxOC41LC00Ni4xIDMxNSwtMzYuMSAzMTEuNSwtNDYuMSAzMTguNSwtNDYuMSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIzODciIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0iZWRnZTEyIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQmIzQ1OyZndDtSMTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTMyOS41NywtNzQuODNDMzM5Ljc1LC02NC45NCAzNTMuNTIsLTUxLjU1IDM2NS4wMywtNDAuMzYiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMzY3LjQ3LC00Mi44NyAzNzIuMiwtMzMuMzggMzYyLjU5LC0zNy44NSAzNjcuNDcsLTQyLjg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},4269:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjMzMnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAzMzIuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMzI4KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSIjMWIxYjFkIiBzdHJva2U9InRyYW5zcGFyZW50IiBwb2ludHM9Ii00LDQgLTQsLTMyOCA0MTgsLTMyOCA0MTgsNCAtNCw0Ii8+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2IC0tPgo8ZyBpZD0ibm9kZTEiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIyMDciIGN5PSItMzA2IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyMDciIHk9Ii0zMDIuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGN4PSIxNzEiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiIGZpbGw9IndoaXRlIj41PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTEiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0xOTguNjUsLTI4OC43NkMxOTQuMjksLTI4MC4yOCAxODguODUsLTI2OS43MSAxODMuOTYsLTI2MC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE4Ni45OSwtMjU4LjQ0IDE3OS4zLC0yNTEuMTUgMTgwLjc3LC0yNjEuNjQgMTg2Ljk5LC0yNTguNDQiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQyNCAtLT4KPGcgaWQ9Im5vZGU3IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgY3g9IjI0MyIgY3k9Ii0yMzQiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTIzMC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjE1PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM1NzkzNDI0IC0tPgo8ZyBpZD0iZWRnZTYiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMjE1LjM1LC0yODguNzZDMjE5LjcxLC0yODAuMjggMjI1LjE1LC0yNjkuNzEgMjMwLjA0LC0yNjAuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMjMzLjIzLC0yNjEuNjQgMjM0LjcsLTI1MS4xNSAyMjcuMDEsLTI1OC40NCAyMzMuMjMsLTI2MS42NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0ibm9kZTMiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iOTkiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSI5OSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCIgZmlsbD0id2hpdGUiPjI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDsxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMiIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0xNTYuNDMsLTIxOC44M0MxNDYuMjUsLTIwOC45NCAxMzIuNDgsLTE5NS41NSAxMjAuOTcsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJyZWQiIHBvaW50cz0iMTIzLjQxLC0xODEuODUgMTEzLjgsLTE3Ny4zOCAxMTguNTMsLTE4Ni44NyAxMjMuNDEsLTE4MS44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNjA5ODEyOCAtLT4KPGcgaWQ9Im5vZGU2IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjE3MSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzYwOTgxMjgmIzQ1OyZndDtSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0iZWRnZTUiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMTcxLC0yMTUuN0MxNzEsLTIwNy45OCAxNzEsLTE5OC43MSAxNzEsLTE5MC4xMSIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIxNzQuNSwtMTkwLjEgMTcxLC0xODAuMSAxNjcuNSwtMTkwLjEgMTc0LjUsLTE5MC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0ibm9kZTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMjciIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtMMTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0iZWRnZTMiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjA8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNODQuNDMsLTE0Ni44M0M3NC4yNSwtMTM2Ljk0IDYwLjQ4LC0xMjMuNTUgNDguOTcsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSI1MS40MSwtMTA5Ljg1IDQxLjgsLTEwNS4zOCA0Ni41MywtMTE0Ljg3IDUxLjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNSIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSI5OSIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O1IxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik05OSwtMTQzLjdDOTksLTEzNS45OCA5OSwtMTI2LjcxIDk5LC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMTAyLjUsLTExOC4xIDk5LC0xMDguMSA5NS41LC0xMTguMSAxMDIuNSwtMTE4LjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9Im5vZGU4IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMjQzIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTI8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU3OTEzMTIgLS0+CjxnIGlkPSJlZGdlNyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkzNDI0JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI0MywtMjE1LjdDMjQzLC0yMDcuOTggMjQzLC0xOTguNzEgMjQzLC0xOTAuMTEiLz4KPHBvbHlnb24gZmlsbD0idHJhbnNwYXJlbnQiIHN0cm9rZT0id2hpdGUiIHBvaW50cz0iMjQ2LjUsLTE5MC4xIDI0MywtMTgwLjEgMjM5LjUsLTE5MC4xIDI0Ni41LC0xOTAuMSIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0IC0tPgo8ZyBpZD0ibm9kZTEzIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBjeD0iMzE1IiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMzE1IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0yNTcuNTcsLTIxOC44M0MyNjcuNzUsLTIwOC45NCAyODEuNTIsLTE5NS41NSAyOTMuMDMsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyOTUuNDcsLTE4Ni44NyAzMDAuMiwtMTc3LjM4IDI5MC41OSwtMTgxLjg1IDI5NS40NywtMTg2Ljg3Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTIyOC40MywtMTQ2LjgzQzIxOC4yNSwtMTM2Ljk0IDIwNC40OCwtMTIzLjU1IDE5Mi45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjE5NS40MSwtMTA5Ljg1IDE4NS44LC0xMDUuMzggMTkwLjUzLC0xMTQuODcgMTk1LjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIiBmaWxsPSJ3aGl0ZSI+MTM8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU3OTM0ODggLS0+CjxnIGlkPSJlZGdlOSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7MTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGQ9Ik0yNDMsLTE0My43QzI0MywtMTM1Ljk4IDI0MywtMTI2LjcxIDI0MywtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkzNDg4IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQ4OCYjNDU7Jmd0O0wxMzk2NjA0MzU3OTM0ODggLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQ4OCYjNDU7Jmd0O0wxMzk2NjA0MzU3OTM0ODg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTc5MzQ4ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0ODgmIzQ1OyZndDtSMTM5NjYwNDM1NzkzNDg4IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0ODgmIzQ1OyZndDtSMTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJ3aGl0ZSIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMTUsLTE0My43QzMxNSwtMTM1Ljk4IDMxNSwtMTI2LjcxIDMxNSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9InRyYW5zcGFyZW50IiBzdHJva2U9IndoaXRlIiBwb2ludHM9IjMxOC41LC0xMTguMSAzMTUsLTEwOC4xIDMxMS41LC0xMTguMSAzMTguNSwtMTE4LjEiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIGQ9Ik0zMjkuNTcsLTE0Ni44M0MzMzkuNzUsLTEzNi45NCAzNTMuNTIsLTEyMy41NSAzNjUuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJ0cmFuc3BhcmVudCIgc3Ryb2tlPSJ3aGl0ZSIgcG9pbnRzPSIzNjcuNDcsLTExNC44NyAzNzIuMiwtMTA1LjM4IDM2Mi41OSwtMTA5Ljg1IDM2Ny40NywtMTE0Ljg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},2366:(I,M,i)=>{i.d(M,{Z:()=>N});const N="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIKICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8IS0tIEdlbmVyYXRlZCBieSBncmFwaHZpeiB2ZXJzaW9uIDIuNDMuMCAoMCkKIC0tPgo8IS0tIFRpdGxlOiBSQlRyZWUgUGFnZXM6IDEgLS0+Cjxzdmcgd2lkdGg9IjQyMnB0IiBoZWlnaHQ9IjMzMnB0Igogdmlld0JveD0iMC4wMCAwLjAwIDQyMi4wMCAzMzIuMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgo8ZyBpZD0iZ3JhcGgwIiBjbGFzcz0iZ3JhcGgiIHRyYW5zZm9ybT0ic2NhbGUoMSAxKSByb3RhdGUoMCkgdHJhbnNsYXRlKDQgMzI4KSI+Cjx0aXRsZT5SQlRyZWU8L3RpdGxlPgo8cG9seWdvbiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgcG9pbnRzPSItNCw0IC00LC0zMjggNDE4LC0zMjggNDE4LDQgLTQsNCIvPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiAtLT4KPGcgaWQ9Im5vZGUxIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzY8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBjeD0iMjA3IiBjeT0iLTMwNiIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjA3IiB5PSItMzAyLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj45PC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTIiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIxNzEiIGN5PSItMjM0IiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIxNzEiIHk9Ii0yMzAuMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjU8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlMSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM0MjQ3Mzc2JiM0NTsmZ3Q7MTM5NjYwNDM2MDk4MTI4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTE5OC42NSwtMjg4Ljc2QzE5NC4yOSwtMjgwLjI4IDE4OC44NSwtMjY5LjcxIDE4My45NiwtMjYwLjIiLz4KPHBvbHlnb24gZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHBvaW50cz0iMTg2Ljk5LC0yNTguNDQgMTc5LjMsLTI1MS4xNSAxODAuNzcsLTI2MS42NCAxODYuOTksLTI1OC40NCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkzNDI0IC0tPgo8ZyBpZD0ibm9kZTciIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBjeD0iMjQzIiBjeT0iLTIzNCIgcng9IjI3IiByeT0iMTgiLz4KPHRleHQgdGV4dC1hbmNob3I9Im1pZGRsZSIgeD0iMjQzIiB5PSItMjMwLjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xNTwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNDI0NzM3NiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQyNCAtLT4KPGcgaWQ9ImVkZ2U2IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzQyNDczNzYmIzQ1OyZndDsxMzk2NjA0MzU3OTM0MjQ8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTIxNS4zNSwtMjg4Ljc2QzIxOS43MSwtMjgwLjI4IDIyNS4xNSwtMjY5LjcxIDIzMC4wNCwtMjYwLjIiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyMzMuMjMsLTI2MS42NCAyMzQuNywtMjUxLjE1IDIyNy4wMSwtMjU4LjQ0IDIzMy4yMywtMjYxLjY0Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSI5OSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk5IiB5PSItMTU4LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4yPC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7MTM5NjYwNDM1ODg3NzYwIC0tPgo8ZyBpZD0iZWRnZTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0OzEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBkPSJNMTU2LjQzLC0yMTguODNDMTQ2LjI1LC0yMDguOTQgMTMyLjQ4LC0xOTUuNTUgMTIwLjk3LC0xODQuMzYiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIxMjMuNDEsLTE4MS44NSAxMTMuOCwtMTc3LjM4IDExOC41MywtMTg2Ljg3IDEyMy40MSwtMTgxLjg1Ii8+CjwvZz4KPCEtLSBSMTM5NjYwNDM2MDk4MTI4IC0tPgo8ZyBpZD0ibm9kZTYiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzYwOTgxMjg8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTE2MiIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNjA5ODEyOCYjNDU7Jmd0O1IxMzk2NjA0MzYwOTgxMjggLS0+CjxnIGlkPSJlZGdlNSIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM2MDk4MTI4JiM0NTsmZ3Q7UjEzOTY2MDQzNjA5ODEyODwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0xNzEsLTIxNS43QzE3MSwtMjA3Ljk4IDE3MSwtMTk4LjcxIDE3MSwtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE3NC41LC0xOTAuMSAxNzEsLTE4MC4xIDE2Ny41LC0xOTAuMSAxNzQuNSwtMTkwLjEiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJub2RlNCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNyIgY3k9Ii05MCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4Nzc2MCYjNDU7Jmd0O0wxMzk2NjA0MzU4ODc3NjAgLS0+CjxnIGlkPSJlZGdlMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7TDEzOTY2MDQzNTg4Nzc2MDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik04NC40MywtMTQ2LjgzQzc0LjI1LC0xMzYuOTQgNjAuNDgsLTEyMy41NSA0OC45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjUxLjQxLC0xMDkuODUgNDEuOCwtMTA1LjM4IDQ2LjUzLC0xMTQuODcgNTEuNDEsLTEwOS44NSIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9Im5vZGU1IiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5SMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9Ijk5IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3NzYwJiM0NTsmZ3Q7UjEzOTY2MDQzNTg4Nzc2MCAtLT4KPGcgaWQ9ImVkZ2U0IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU4ODc3NjAmIzQ1OyZndDtSMTM5NjYwNDM1ODg3NzYwPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTk5LC0xNDMuN0M5OSwtMTM1Ljk4IDk5LC0xMjYuNzEgOTksLTExOC4xMSIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIxMDIuNSwtMTE4LjEgOTksLTEwOC4xIDk1LjUsLTExOC4xIDEwMi41LC0xMTguMSIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTgiIGNsYXNzPSJub2RlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGN4PSIyNDMiIGN5PSItMTYyIiByeD0iMjciIHJ5PSIxOCIvPgo8dGV4dCB0ZXh0LWFuY2hvcj0ibWlkZGxlIiB4PSIyNDMiIHk9Ii0xNTguMyIgZm9udC1mYW1pbHk9IidDYXNjYWRpYSBDb2RlIFBMJywgJ0pldEJyYWlucyBNb25vJywgJ0lvc2V2a2EnLCAnRmlyYSBDb2RlJywgJ0hhY2snLCBtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMTQuMDAiPjEyPC90ZXh0Pgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkzNDI0JiM0NTsmZ3Q7MTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0iZWRnZTciIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTc5MTMxMjwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNDMsLTIxNS43QzI0MywtMjA3Ljk4IDI0MywtMTk4LjcxIDI0MywtMTkwLjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjI0Ni41LC0xOTAuMSAyNDMsLTE4MC4xIDIzOS41LC0xOTAuMSAyNDYuNSwtMTkwLjEiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9Im5vZGUxMyIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgY3g9IjMxNSIgY3k9Ii0xNjIiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjMxNSIgeT0iLTE1OC4zIiBmb250LWZhbWlseT0iJ0Nhc2NhZGlhIENvZGUgUEwnLCAnSmV0QnJhaW5zIE1vbm8nLCAnSW9zZXZrYScsICdGaXJhIENvZGUnLCAnSGFjaycsIG1vbm9zcGFjZSIgZm9udC1zaXplPSIxNC4wMCI+MTg8L3RleHQ+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0MjQmIzQ1OyZndDsxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJlZGdlMTIiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQyNCYjNDU7Jmd0OzEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0yNTcuNTcsLTIxOC44M0MyNjcuNzUsLTIwOC45NCAyODEuNTIsLTE5NS41NSAyOTMuMDMsLTE4NC4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyOTUuNDcsLTE4Ni44NyAzMDAuMiwtMTc3LjM4IDI5MC41OSwtMTgxLjg1IDI5NS40NywtMTg2Ljg3Ii8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkxMzEyIC0tPgo8ZyBpZD0ibm9kZTkiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU3OTEzMTI8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMTcxIiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1NzkxMzEyJiM0NTsmZ3Q7TDEzOTY2MDQzNTc5MTMxMiAtLT4KPGcgaWQ9ImVkZ2U4IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDtMMTM5NjYwNDM1NzkxMzEyPC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTIyOC40MywtMTQ2LjgzQzIxOC4yNSwtMTM2Ljk0IDIwNC40OCwtMTIzLjU1IDE5Mi45NywtMTEyLjM2Ii8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjE5NS40MSwtMTA5Ljg1IDE4NS44LC0xMDUuMzggMTkwLjUzLC0xMTQuODcgMTk1LjQxLC0xMDkuODUiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9Im5vZGUxMCIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+MTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJyZWQiIGN4PSIyNDMiIGN5PSItOTAiIHJ4PSIyNyIgcnk9IjE4Ii8+Cjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9IjI0MyIgeT0iLTg2LjMiIGZvbnQtZmFtaWx5PSInQ2FzY2FkaWEgQ29kZSBQTCcsICdKZXRCcmFpbnMgTW9ubycsICdJb3NldmthJywgJ0ZpcmEgQ29kZScsICdIYWNrJywgbW9ub3NwYWNlIiBmb250LXNpemU9IjE0LjAwIj4xMzwvdGV4dD4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MTMxMiYjNDU7Jmd0OzEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9ImVkZ2U5IiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTEzMTImIzQ1OyZndDsxMzk2NjA0MzU3OTM0ODg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9InJlZCIgZD0iTTI0MywtMTQzLjdDMjQzLC0xMzUuOTggMjQzLC0xMjYuNzEgMjQzLC0xMTguMTEiLz4KPHBvbHlnb24gZmlsbD0icmVkIiBzdHJva2U9InJlZCIgcG9pbnRzPSIyNDYuNSwtMTE4LjEgMjQzLC0xMDguMSAyMzkuNSwtMTE4LjEgMjQ2LjUsLTExOC4xIi8+CjwvZz4KPCEtLSBMMTM5NjYwNDM1NzkzNDg4IC0tPgo8ZyBpZD0ibm9kZTExIiBjbGFzcz0ibm9kZSI+Cjx0aXRsZT5MMTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPGVsbGlwc2UgZmlsbD0ibm9uZSIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgY3g9IjIwNyIgY3k9Ii0xOCIgcng9IjI3IiByeT0iMTgiLz4KPC9nPgo8IS0tIDEzOTY2MDQzNTc5MzQ4OCYjNDU7Jmd0O0wxMzk2NjA0MzU3OTM0ODggLS0+CjxnIGlkPSJlZGdlMTAiIGNsYXNzPSJlZGdlIj4KPHRpdGxlPjEzOTY2MDQzNTc5MzQ4OCYjNDU7Jmd0O0wxMzk2NjA0MzU3OTM0ODg8L3RpdGxlPgo8cGF0aCBmaWxsPSJub25lIiBzdHJva2U9ImJsYWNrIiBkPSJNMjM0LjY1LC03Mi43NkMyMzAuMjksLTY0LjI4IDIyNC44NSwtNTMuNzEgMjE5Ljk2LC00NC4yIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjIyMi45OSwtNDIuNDQgMjE1LjMsLTM1LjE1IDIxNi43NywtNDUuNjQgMjIyLjk5LC00Mi40NCIvPgo8L2c+CjwhLS0gUjEzOTY2MDQzNTc5MzQ4OCAtLT4KPGcgaWQ9Im5vZGUxMiIgY2xhc3M9Im5vZGUiPgo8dGl0bGU+UjEzOTY2MDQzNTc5MzQ4ODwvdGl0bGU+CjxlbGxpcHNlIGZpbGw9Im5vbmUiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGN4PSIyNzkiIGN5PSItMTgiIHJ4PSIyNyIgcnk9IjE4Ii8+CjwvZz4KPCEtLSAxMzk2NjA0MzU3OTM0ODgmIzQ1OyZndDtSMTM5NjYwNDM1NzkzNDg4IC0tPgo8ZyBpZD0iZWRnZTExIiBjbGFzcz0iZWRnZSI+Cjx0aXRsZT4xMzk2NjA0MzU3OTM0ODgmIzQ1OyZndDtSMTM5NjYwNDM1NzkzNDg4PC90aXRsZT4KPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSJibGFjayIgZD0iTTI1MS4zNSwtNzIuNzZDMjU1LjcxLC02NC4yOCAyNjEuMTUsLTUzLjcxIDI2Ni4wNCwtNDQuMiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIyNjkuMjMsLTQ1LjY0IDI3MC43LC0zNS4xNSAyNjMuMDEsLTQyLjQ0IDI2OS4yMywtNDUuNjQiLz4KPC9nPgo8IS0tIEwxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTQiIGNsYXNzPSJub2RlIj4KPHRpdGxlPkwxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzE1IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxMyIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7TDEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMTUsLTE0My43QzMxNSwtMTM1Ljk4IDMxNSwtMTI2LjcxIDMxNSwtMTE4LjExIi8+Cjxwb2x5Z29uIGZpbGw9ImJsYWNrIiBzdHJva2U9ImJsYWNrIiBwb2ludHM9IjMxOC41LC0xMTguMSAzMTUsLTEwOC4xIDMxMS41LC0xMTguMSAzMTguNSwtMTE4LjEiLz4KPC9nPgo8IS0tIFIxMzk2NjA0MzU4ODc4MjQgLS0+CjxnIGlkPSJub2RlMTUiIGNsYXNzPSJub2RlIj4KPHRpdGxlPlIxMzk2NjA0MzU4ODc4MjQ8L3RpdGxlPgo8ZWxsaXBzZSBmaWxsPSJub25lIiBzdHJva2U9InRyYW5zcGFyZW50IiBjeD0iMzg3IiBjeT0iLTkwIiByeD0iMjciIHJ5PSIxOCIvPgo8L2c+CjwhLS0gMTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNCAtLT4KPGcgaWQ9ImVkZ2UxNCIgY2xhc3M9ImVkZ2UiPgo8dGl0bGU+MTM5NjYwNDM1ODg3ODI0JiM0NTsmZ3Q7UjEzOTY2MDQzNTg4NzgyNDwvdGl0bGU+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iYmxhY2siIGQ9Ik0zMjkuNTcsLTE0Ni44M0MzMzkuNzUsLTEzNi45NCAzNTMuNTIsLTEyMy41NSAzNjUuMDMsLTExMi4zNiIvPgo8cG9seWdvbiBmaWxsPSJibGFjayIgc3Ryb2tlPSJibGFjayIgcG9pbnRzPSIzNjcuNDcsLTExNC44NyAzNzIuMiwtMTA1LjM4IDM2Mi41OSwtMTA5Ljg1IDM2Ny40NywtMTE0Ljg3Ii8+CjwvZz4KPC9nPgo8L3N2Zz4K"},122:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rr_7_dark-f8796e7eda13a89d198098744b079384.svg"},3927:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rr_7_light-f03b9073d10947b0af1a226ee8e12fa4.svg"},2476:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rr_8_dark-f1562f7fd1dc9442e496260e74447d03.svg"},5509:(I,M,i)=>{i.d(M,{Z:()=>N});const N=i.p+"assets/images/rr_8_light-7531279bbbb44b4e206fe5040b38df4d.svg"}}]); \ No newline at end of file diff --git a/assets/js/4200b1a9.e4798bae.js b/assets/js/4200b1a9.7692be27.js similarity index 99% rename from assets/js/4200b1a9.e4798bae.js rename to assets/js/4200b1a9.7692be27.js index 1e15330..9116223 100644 --- a/assets/js/4200b1a9.e4798bae.js +++ b/assets/js/4200b1a9.7692be27.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[866],{4612:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"/2023/08/02/copr","metadata":{"permalink":"/blog/2023/08/02/copr","editUrl":"https://gitlab.com/mfocko/blog/tree/main/blog/2023-08-02-copr.md","source":"@site/blog/2023-08-02-copr.md","title":"How can Copr help with broken dependencies","description":"Copr comes to save you when maintainer doesn\'t care.","date":"2023-08-02T00:00:00.000Z","formattedDate":"August 2, 2023","tags":[{"label":"\ud83c\udfed","permalink":"/blog/tags/\ud83c\udfed"},{"label":"red-hat","permalink":"/blog/tags/red-hat"},{"label":"copr","permalink":"/blog/tags/copr"},{"label":"admin","permalink":"/blog/tags/admin"},{"label":"vps","permalink":"/blog/tags/vps"}],"readingTime":3.44,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. your opinionated admin","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"How can Copr help with broken dependencies","description":"Copr comes to save you when maintainer doesn\'t care.","date":"2023-08-02T00:00:00.000Z","authors":[{"key":"mf","title":"a.k.a. your opinionated admin"}],"tags":["\ud83c\udfed","red-hat","copr","admin","vps"]},"nextItem":{"title":"4th week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/4th-week"}},"content":"When you decide to run Fedora on your VPS, you might get screwed over by using\\nrandom repositories\u2026\\n\\n\x3c!--truncate--\x3e\\n\\nWhen I \u201creserved\u201d my VPS[^1] back in June \'20, I slapped Fedora on it without\\nthinking. I bet 99% of people would say that I\'m crazy for doing such thing[^2],\\n**BUT** I\'ve been using Fedora on my PCs for some time already and it felt very\\nstable and natural to just use, even for VPS.\\n\\nOne of the first things I\'ve done was setting up a mail server. You may guess\\nwhat\'s the fun part about having a mail server\u2026 Yes, it\'s all the spam you\\nreceive and only then you realize how much \u201ccrap\u201d gets filtered on free mail\\nservices. To battle this problem I chose to use\\n[rspamd](https://github.com/rspamd/rspamd) that had CentOS support, but someone\\nhad a [Copr](https://copr.fedorainfracloud.org/) repository that I used to\\ninstall it.\\n\\n## How does Copr repositories work?\\n\\nIf you have ever used Ubuntu, you might be familiar with the concept since it is\\nvery close to [PPAs](https://help.ubuntu.com/community/PPA).\\n\\ntl;dr of the whole process consists of\\n1. enabling the Copr repository, and\\n2. installing the desired package.\\n\\nSo in shell you would do\\n```\\n# dnf copr enable \u2039copr-repository\u203a\\n# dnf install \u2039package-from-the-repository\u203a\\n```\\n\\nAnd\u2026 that\'s it! Nothing else needed! Simple, right? And literally same process\\nas you would do for the PPA.\\n\\n:::tip AUR\\n\\nOn the other hand, if you are familiar with the archLinux, you definitely know\\nAUR and what it can do for you. Copr repository is pretty similar, but the\\npackages are prebuilt in Copr and Copr repositories can carry the required\\ndependencies for said packages, which simplifies the distribution, and can even\\nhelp with installing singular packages (when you just need the dependency, not\\neverything).\\n\\n:::\\n\\n## My issue\\n\\nNow you might wonder how would I use it on my VPS. It\'s rather simple, once in\\n6 months a new Fedora release comes out. And you need to upgrade to newer\\nrelease\u2026 You don\'t need to do it right away and for such setup it probably isn\'t\\neven recommended.\\n\\n:::tip\\n\\nFedora releases are supported for a year, i.e. they live 6 months till the next\\nrelease and then another 6 months till another release.\\n\\nSome people prefer to run one version \u201cbehind\u201d. If you ever decide to run it on\\nyour home server or in a similar setup, it might be a pretty good idea to\\nfollow. I\'m using the \u201clatest greatest\u201d, cause why not :smile:\\n\\nOne way or another, you still need to bump the release every six months, unless\\nyou\'d bump 2 releases at once every year, which would be a decision, since, at\\nleast I, cannot see any benefits in it\u2026 You don\'t go for \u201cstability\u201d, cause once\\na year you switch to the latest release and then, before you bump, you use one\\nyear old software, so you\'re not even using the latest.\\n\\n:::\\n\\nFast-forward 2 years in the future, new Fedora release came out (October \'22)\\nand I was doing an upgrade. Dependencies of the rspamd have been updated and\\nrspamd builds in Copr have failed and no one fixed it. Cool, so now I can\\nupgrade, but can either ignore the dependencies or uninstall the rspamd\u2026\\n\\n## How can Copr help?\\n\\nI have managed to find\\n[specfile](https://github.com/rspamd/rspamd/blob/master/rpm/rspamd.spec) for the\\nrspamd package that they use for CentOS. There were some files apart from the\\nspecfile, so I had to make an SRPM locally and then\u2026 I just uploaded the SRPM\\nto the Copr to\\n[build](https://copr.fedorainfracloud.org/coprs/mfocko/rspamd/build/5046567/)\\nan RPM.\\n\\nI have switched the previous Copr repository for rspamd with my own and happily\\nproceeded with the upgrade.\\n\\n## Conclusion\\n\\nCopr is heavily used for testing builds on the upstream with\\n[Packit](https://packit.dev). However, as you can see, it is possible to use it\\n**very well** for packaging your own stuff and avoiding issues (such as the one\\nI have described above), if need be.\\n\\n[^1]: [vpsFree.cz](https://vpsfree.cz)\\n[^2]: Even though I\'ve been running archLinux on some Raspberry Pi\'s and also\\n on one of my \u201chome servers\u201d, before getting the VPS. You could say I like\\n to live on the edge\u2026"},{"id":"aoc-2022/4th-week","metadata":{"permalink":"/blog/aoc-2022/4th-week","editUrl":"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/04-week-4.md","source":"@site/blog/aoc-2022/04-week-4.md","title":"4th week of Advent of Code \'22 in Rust","description":"Surviving fourth week in Rust.","date":"2023-07-07T15:14:00.000Z","formattedDate":"July 7, 2023","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":15.175,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"4th week of Advent of Code \'22 in Rust","description":"Surviving fourth week in Rust.","date":"2023-07-07T15:14","slug":"aoc-2022/4th-week","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"How can Copr help with broken dependencies","permalink":"/blog/2023/08/02/copr"},"nextItem":{"title":"3rd week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/3rd-week"}},"content":"Let\'s go through the fourth week of [_Advent of Code_] in Rust.\\n\\n\x3c!--truncate--\x3e\\n\\n## [Day 22: Monkey Map](https://adventofcode.com/2022/day/22)\\n\\n:::info tl;dr\\n\\nSimulating a movement on a 2D map with given instructions. Map becomes a cube in\\nthe 2nd part\u2026\\n\\n:::\\n\\n:::caution Rant\\n\\nThis was the most obnoxious problem of this year\u2026 and a lot of Rust issues have\\nbeen hit.\\n\\n:::\\n\\n### Solution\\n\\nIt seems like a very simple problem to solve, but with very obnoxious changes in\\nthe 2nd part and also it\'s relatively hard to decompose \xbbproperly\xab.\\n\\n#### Column iterator\\n\\nIn the first part of the problem it was needed to know the boundaries of each\\nrow and column, since I stored them in `Vec>` and padded with spaces\\nto ensure I have a rectangular 2D \u201carray\u201d. However when you wanted to go through\\neach row and column to determine the boundaries, it was very easy to do for the\\nrows (cause each row is a `Vec` element), but not for the columns, since they\\nspan multiple rows.\\n\\nFor this use case I have implemented my own _column iterator_:\\n```rust\\npub struct ColumnIterator<\'a, T> {\\n map: &\'a [Vec],\\n column: usize,\\n\\n i: usize,\\n}\\n\\nimpl<\'a, T> ColumnIterator<\'a, T> {\\n pub fn new(map: &\'a [Vec], column: usize) -> ColumnIterator<\'a, T> {\\n Self { map, column, i: 0 }\\n }\\n}\\n\\nimpl<\'a, T> Iterator for ColumnIterator<\'a, T> {\\n type Item = &\'a T;\\n\\n fn next(&mut self) -> Option {\\n if self.i >= self.map.len() {\\n return None;\\n }\\n\\n self.i += 1;\\n Some(&self.map[self.i - 1][self.column])\\n }\\n}\\n```\\n\\nGiven this piece of an iterator, it is very easy to factor out the common\\nfunctionality between the rows and columns into:\\n```rust\\nlet mut find_boundaries = |constructor: fn(usize) -> Orientation,\\n iterator: &mut dyn Iterator,\\n upper_bound,\\n i| {\\n let mut first_non_empty = iterator.enumerate().skip_while(|&(_, &c)| c == \' \');\\n let start = first_non_empty.next().unwrap().0 as isize;\\n\\n let mut last_non_empty = first_non_empty.skip_while(|&(_, &c)| c != \' \');\\n let end = last_non_empty.next().unwrap_or((upper_bound, &\'_\')).0 as isize;\\n\\n boundaries.insert(constructor(i), start..end);\\n};\\n```\\n\\nAnd then use it as such:\\n```rust\\n// construct all horizontal boundaries\\n(0..map.len()).for_each(|row| {\\n find_boundaries(\\n Orientation::horizontal,\\n &mut map[row].iter(),\\n map[row].len(),\\n row,\\n );\\n});\\n\\n// construct all vertical boundaries\\n(0..map[0].len()).for_each(|col| {\\n find_boundaries(\\n Orientation::vertical,\\n &mut ColumnIterator::new(&map, col),\\n map.len(),\\n col,\\n );\\n});\\n```\\n\\n#### Walking around the map\\n\\nOnce the 2nd part got introduced, you start to think about a way how not to\\ncopy-paste a lot of stuff (I haven\'t avoided it anyways\u2026). In this problem, I\'ve\\nchosen to introduce a trait (i.e. _interface_) for 2D and 3D walker.\\n```rust\\ntrait Wrap: Clone {\\n type State;\\n\\n // simulation\\n fn is_blocked(&self) -> bool;\\n fn step(&mut self, steps: isize);\\n fn turn_left(&mut self);\\n fn turn_right(&mut self);\\n\\n // movement\\n fn next(&self) -> (Self::State, Direction);\\n\\n // final answer\\n fn answer(&self) -> Output;\\n}\\n```\\n\\nEach walker maintains its own state and also provides the functions that are\\nused during the simulation. The \u201cpromised\u201d methods are separated into:\\n* _simulation_-related: that are used during the simulation from the `.fold()`\\n* _movement_-related: just a one method that holds most of the logic differences\\n between 2D and 3D\\n* _final answer_: which extracts the _proof of solution_ from the\\n implementation-specific walker\\n\\nBoth 2D and 3D versions borrow the original input and therefore you must\\nannotate the lifetime of it:\\n```rust\\nstruct Wrap2D<\'a> {\\n input: &\'a Input,\\n position: Position,\\n direction: Direction,\\n}\\nimpl<\'a> Wrap2D<\'a> {\\n fn new(input: &\'a Input) -> Wrap2D<\'a> {\\n// \u2026\\n```\\n\\n#### Problems\\n\\nI have used a lot of closures for this problem and once I introduced a parameter\\nthat was of unknown type (apart from the fact it implements a specific trait), I\\ngot suggested a \u201cfix\u201d for the compilation error that resulted in something that\\nwas not possible to parse, cause it, more than likely, violated the grammar.\\n\\nIn a similar fashion, I have been suggested changes that led to a code that\\ndidn\'t make sense by just looking at it (there was no need to try the changes),\\nfor example one suggested change in the closure parameter caused disapperance of\\nthe parameter name. :smile:\\n\\n#### Clippy\\n\\nI have to admit that Clippy was rather helpful here, I\'ll include two examples\\nof rather smart suggestions.\\n\\nWhen writing the parsing for this problem, the first thing I have spotted on the\\n`char` was the `.is_digit()` function that takes a radix as a parameter. Clippy\\nnoticed that I use `radix = 10` and suggested switching to `.is_ascii_digit()`\\nthat does exactly the same thing:\\n```diff\\n- .take_while(|c| c.is_digit(10))\\n+ .take_while(|c| c.is_ascii_digit())\\n```\\n\\nAnother useful suggestion appeared when working with the iterators and I wanted\\nto get the $n$-th element from it. You know the `.skip()`, you know the\\n`.next()`, just \u201cslap\u201d them together and we\'re done for :grin: Well, I got\\nsuggested to use `.nth()` that does exactly the combination of the two mentioned\\nmethods on iterators:\\n```diff\\n- match it.clone().skip(skip).next().unwrap() {\\n+ match it.clone().nth(skip).unwrap() {\\n```\\n\\n## [Day 23: Unstable Diffusion](https://adventofcode.com/2022/day/23)\\n\\n:::info tl;dr\\n\\nSimulating movement of elves around with a set of specific rules.\\n\\n:::\\n\\n### Solution\\n\\nThere\'s not much to mention since it\'s just a cellular automaton simulation\\n(even though the AoC rules for cellular automatons usually get out of hand\\n:wink:).\\n\\nAlthough I had a need to determine boundaries of the elves\' positions and ended\\nup with a nasty DRY violation. Knowing that you you\'re looking for maximum and\\nminimum that are, of course, exactly the same except for initial values and\\ncomparators, it looks like a rather simple fix, but typing in Rust is something\\nelse, right? In the end I settled for a function that computes both boundaries\\nwithout any duplication while using a closure:\\n```rust\\nfn get_bounds(positions: &Input) -> (Vector2D, Vector2D) {\\n let f = |init, cmp: &dyn Fn(isize, isize) -> isize| {\\n positions\\n .iter()\\n .fold(Vector2D::new(init, init), |acc, elf| {\\n Vector2D::new(cmp(acc.x(), elf.x()), cmp(acc.y(), elf.y()))\\n })\\n };\\n\\n (f(isize::MAX, &min::), f(isize::MIN, &max::))\\n}\\n```\\n\\nThis function returns a pair of 2D vectors that represent opposite points of the\\nbounding rectangle of all elves.\\n\\nYou might ask why would we need a closure and the answer is that `positions`\\ncannot be captured from within the nested function, only via closure. One more\\nfun fact on top of that is the type of the comparator\\n```rust\\n&dyn Fn(isize, isize) -> isize\\n```\\nOnce we remove the `dyn` keyword, compiler yells at us and also includes a way\\nhow to get a more thorough explanation of the error by running\\n\\n $ rustc --explain E0782\\n\\nwhich shows us\\n\\n Trait objects must include the `dyn` keyword.\\n \\n Erroneous code example:\\n \\n ```\\n trait Foo {}\\n fn test(arg: Box) {} // error!\\n ```\\n \\n Trait objects are a way to call methods on types that are not known until\\n runtime but conform to some trait.\\n \\n Trait objects should be formed with `Box`, but in the code above\\n `dyn` is left off.\\n \\n This makes it harder to see that `arg` is a trait object and not a\\n simply a heap allocated type called `Foo`.\\n \\n To fix this issue, add `dyn` before the trait name.\\n \\n ```\\n trait Foo {}\\n fn test(arg: Box) {} // ok!\\n ```\\n \\n This used to be allowed before edition 2021, but is now an error.\\n\\n:::danger Rant\\n\\nNot all of the explanations are helpful though, in some cases they might be even\\nmore confusing than helpful, since they address _very simple_ use cases.\\n\\nAs you can see, even in this case there are two sides to the explanations:\\n* it explains why you need to use `dyn`, but\\n* it still mentions that trait objects need to be heap-allocated via `Box`\\n that, as you can see in my snippet, **does not** apply here :smile: IMO it\'s\\n caused by the fact that we are borrowing it and therefore we don\'t need to\\n care about the size or whereabouts of it.\\n\\n:::\\n\\n:::info C++ parallel\\n\\nIf you dive into the explanation above, you can notice that the `Box`\\npattern is very helpful for using types that are not known during compile-time.\\nYou would use a very similar approach in C++ when parsing some data structure\\nfrom input (let\'s say JSON for example).\\n\\nOn the other hand, in this case, it doesn\'t really make much sense, cause you\\ncan clearly see that the types **are known** during the compile-time, which in\\nC++ could be easily resolved by templating the helper function.\\n\\n:::\\n\\n## [Day 24: Blizzard Basin](https://adventofcode.com/2022/day/24)\\n\\n:::info tl;dr\\n\\nNavigating your way through a basin with series of blizzards that move around\\nyou as you move.\\n\\n:::\\n\\n:::caution\\n\\nIt\'s second to last day and I went \u201c_bonkers_\u201d on the Rust :smile: Proceed to\\nread _Solution_ part on your own risk.\\n\\n:::\\n\\n### Solution\\n\\nYou are given a map with blizzards all over the place and you\'re supposed to\\nfind the minimum time it requires you to walk through the basin without getting\\nin any of the blizzards.\\n\\n#### Breakdown\\n\\nRelatively simple, yet a bit annoying, approach can be taken. It\'s technically\\na shortest-path algorithm implementation with some relaxation restrictions and\\nbeing able to stay on one position for some time, so each _vertex_ of the graph\\nis determined by the position on the map and the _timestamp_. I have chosen to\\nuse `Vector3D`, since `x` and `y` attributes can be used for the position\\nand, well, let\'s use `z` for a timestamp, cause why not, right? :wink:\\n\\n#### Evaluating the blizzards\\n\\n:::caution\\n\\nI think that this is the most perverted abuse of the traits in the whole 4 weeks\\nof AoC in Rust\u2026\\n\\n:::\\n\\nThe blizzards move along their respective directions in time and loop around in\\ntheir respective row/column. Each vertex holds position **and** time, so we can\\n_just_ index the basin with the vertex itself, right? Yes, we can :smiling_imp:\\n\\n:::tip Fun fact\\n\\nWhile writing this part, I\'ve recognized unnecessary verbosity in the code and\\ncleaned it up a bit. The changed version is shown here and the original was just\\nmore verbose.\\n\\n:::\\n\\nI\'ll skip the boring parts of checking bounds and entry/exit of the basin :wink:\\nWe can easily calculate positions of the blizzards using a modular arithmetics:\\n```rust\\nimpl Index for Basin {\\n type Output = char;\\n\\n fn index(&self, index: Position) -> &Self::Output {\\n // \u2039skipped boring parts\u203a\\n\\n // We need to account for the loops of the blizzards\\n let width = self.cols - 2;\\n let height = self.rows - 2;\\n\\n let blizzard_origin = |size, d, t, i| ((i - 1 + size + d * (t % size)) % size + 1) as usize;\\n [\\n (\\n index.y() as usize,\\n blizzard_origin(width, -1, index.z(), index.x()),\\n \'>\',\\n ),\\n (\\n index.y() as usize,\\n blizzard_origin(width, 1, index.z(), index.x()),\\n \'<\',\\n ),\\n (\\n blizzard_origin(height, -1, index.z(), index.y()),\\n index.x() as usize,\\n \'v\',\\n ),\\n (\\n blizzard_origin(height, 1, index.z(), index.y()),\\n index.x() as usize,\\n \'^\',\\n ),\\n ]\\n .iter()\\n .find_map(|&(y, x, direction)| {\\n if self.map[y][x] == direction {\\n Some(&self.map[y][x])\\n } else {\\n None\\n }\\n })\\n .unwrap_or(&\'.\')\\n }\\n}\\n```\\n\\nAs you can see, there is an expression for calculating the original position and\\nit\'s used multiple times, so why not take it out to a lambda, right? :wink:\\n\\nI couldn\'t get the `rustfmt` to format the `for`-loop nicely, so I\'ve just\\ndecided to go with iterating over an elements of a slice. I have used, once\\nagain, a combination of two functions (`find_map` in this case) to do 2 things\\nat once and at the end, if we haven\'t found any blizzard, we just return the\\nempty space.\\n\\nI think it\'s a very _nice_ (and naughty) way how to use the `Index` trait, don\'t\\nyou think?\\n\\n#### Shortest-path algorithm\\n\\nFor the shortest path you can choose and adjust any of the common shortest-path\\nalgorithms, in my case, I have decided to use [_A\\\\*_] instead of Dijkstra\'s\\nalgorithm, since it better reflects the _cost_ function.\\n\\n:::info Comparison of costs\\n\\nWith the Dijkstra\'s algorithm I would proceed with the `time` attribute used as\\na priority for the queue.\\n\\nWhereas with the _A\\\\*_, I have chosen to use both time and Manhattan distance\\nthat promotes vertices closer to the exit **and** with a minimum time taken.\\n\\n:::\\n\\nCost function is, of course, a closure :wink:\\n```rust\\nlet cost = |p: Position| p.z() as usize + exit.y().abs_diff(p.y()) + exit.x().abs_diff(p.x());\\n```\\n\\nAnd also for checking the possible moves from the current vertex, I have\\nimplemented, yet another, closure that yields an iterator with the next moves:\\n```rust\\nlet next_positions = |p| {\\n [(0, 0, 1), (0, -1, 1), (0, 1, 1), (-1, 0, 1), (1, 0, 1)]\\n .iter()\\n .filter_map(move |&(x, y, t)| {\\n let next_p = p + Vector3D::new(x, y, t);\\n\\n if basin[next_p] == \'.\' {\\n Some(next_p)\\n } else {\\n None\\n }\\n })\\n};\\n```\\n\\n#### Min-heap\\n\\nIn this case I had a need to use the priority queue taking the elements with the\\nlowest cost as the prioritized ones. Rust only offers you the [`BinaryHeap`] and\\nthat is a max-heap. One of the ways how to achieve a min-heap is to put the\\nelements in wrapped in a [`Reverse`] (as is even showed in the linked [docs of\\nthe `BinaryHeap`]). However the wrapping affects the type of the heap and also\\npopping the most prioritized elements yields values wrapped in the `Reverse`.\\n\\nFor this purpose I have just taken the max-heap and wrapped it as a whole in a\\nseparate structure providing just the desired methods:\\n```rust\\nuse std::cmp::{Ord, Reverse};\\nuse std::collections::BinaryHeap;\\n\\npub struct MinHeap {\\n heap: BinaryHeap>,\\n}\\n\\nimpl MinHeap {\\n pub fn new() -> MinHeap {\\n MinHeap {\\n heap: BinaryHeap::new(),\\n }\\n }\\n\\n pub fn push(&mut self, item: T) {\\n self.heap.push(Reverse(item))\\n }\\n\\n pub fn pop(&mut self) -> Option {\\n self.heap.pop().map(|Reverse(x)| x)\\n }\\n}\\n\\nimpl Default for MinHeap {\\n fn default() -> Self {\\n Self::new()\\n }\\n}\\n```\\n\\nRest is just the algorithm implementation which is not that interesting.\\n\\n## [Day 25: Full of Hot Air](https://adventofcode.com/2022/day/25)\\n\\n:::info tl;dr\\n\\nPlaying around with a numbers in a _special_ base.\\n\\n:::\\n\\nGetting flashbacks to the _IB111 Foundations of Programming_\u2026 Very nice \u201cproblem\u201d\\nwith a rather easy solution, as the last day always seems to be.\\n\\n### Solution\\n\\nImplementing 2 functions, converting from the _SNAFU base_ and back to the _SNAFU_\\n_base_ representation. Let\'s do a bit more though! I have implemented two functions:\\n* `from_snafu`\\n* `to_snafu`\\n\\nNow it is apparent that all I do is number to string and string to number. Hmm\u2026\\nthat sounds familiar, doesn\'t it? Let\'s introduce a structure for the SNAFU numbers\\nand implement the traits that we need.\\n\\nLet\'s start with a structure:\\n```rust\\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\\nstruct SNAFU {\\n value: i64,\\n}\\n```\\n\\n#### Converting from `&str`\\n\\nWe will start by implementing the `FromStr` trait that will help us parse our input.\\nThis is rather simple, I can just take the `from_snafu` function, copy-paste it\\ninto the `from_str` method and the number I get will be wrapped in `Result` and\\n`SNAFU` structure.\\n\\n#### Converting to `String`\\n\\nThis is more fun. In some cases you need to implement only one trait and others\\nare automatically implemented using that one trait. In our case, if you look in\\nthe documentation, you can see that `ToString` trait is automatically implemented\\nfor any type that implements `Display` trait.\\n\\nLet\'s implement the `Display` trait then. We should be able to use the `to_snafu`\\nfunction and just take the `self.value` from the `SNAFU` structure.\\n\\nAnd for the convenience of tests, we can also implement a rather simple `From`\\ntrait for the `SNAFU`.\\n\\n#### Adjusting the code\\n\\nAfter those changes we need to adjust the code and tests.\\n\\nParsing of the input is very easy, before we have used the lines, now we parse\\neverything:\\n```diff\\n fn parse_input>(pathname: P) -> Input {\\n- file_to_lines(pathname)\\n+ file_to_structs(pathname)\\n }\\n```\\n\\nPart 1 needs to be adjusted a bit too:\\n```diff\\n fn part_1(input: &Input) -> Output {\\n- to_snafu(input.iter().map(|s| from_snafu(s)).sum())\\n+ SNAFU::from(input.iter().map(|s| s.value).sum::()).to_string()\\n }\\n```\\n\\nYou can also see that it simplifies the meaning a bit and it is more explicit than\\nthe previous versions.\\n\\nAnd for the tests:\\n```diff\\n #[test]\\n fn test_from() {\\n- for (n, s) in EXAMPLES.iter() {\\n- assert_eq!(from_snafu(s), *n);\\n+ for (&n, s) in EXAMPLES.iter() {\\n+ assert_eq!(s.parse::().unwrap().value, n);\\n }\\n }\\n \\n #[test]\\n fn test_to() {\\n- for (n, s) in EXAMPLES.iter() {\\n- assert_eq!(to_snafu(*n), s.to_string());\\n+ for (&n, s) in EXAMPLES.iter() {\\n+ assert_eq!(SNAFU::from(n).to_string(), s.to_string());\\n }\\n```\\n\\n## Summary\\n\\nLet\'s wrap the whole thing up! Keeping in mind both AoC and the Rust\u2026\\n\\n![Finished advent calendar :smile:](/img/blog/aoc-2022/04-week-4/calendar.png)\\n\\n### Advent of Code\\n\\nThis year was quite fun, even though most of the solutions and posts came in\\nlater on (*cough* in \'23 *cough*). Day 22 was the most obnoxious one\u2026 And also\\nit feels like I used priority queues and tree data structures **a lot** :eyes:\\n\\n### with Rust\\n\\nI must admit that a lot of compiler warnings and errors were very useful. Even\\nthough I still found some instances where they didn\'t help at all or cause even\\nworse issues than I had. Compilation times have been addressed with the caching.\\n\\nBuilding my first tree data structure in Rust has been a very \u201cinteresting\u201d\\njourney. Being able to write a more generic BFS algorithm that allows you to not\\nduplicate code while still mantaining the desired functionality contributes to\\na very readable code.\\n\\nI am definitely much more aware of the basic things that bloated Python is\\nmissing, yet Rust has them\u2026\\n\\nUsing explicit types and writing down placeholder functions with `todo!()`\\nmacros is very pleasant, since it allows you to easily navigate the type system\\nduring the development when you don\'t even need to be sure how are you going to\\nput the smaller pieces together.\\n\\nI have used a plethora of traits and also implemented some of them to either be\\nidiomatic, or exploit the syntactic sugar they offer. Deriving the default trait\\nimplementation is also very helpful in a lot of cases, e.g. debugging output,\\ncopying, equality comparison, etc.\\n\\nI confess to touching more \u201ccursed\u201d parts of the Rust, such as macros to\\ndeclutter the copy-paste for tests or writing my own structures that need to\\ncarry a lifetime for their own fields.\\n\\ntl;dr Relatively pleasant language until you hit brick wall :wink:\\n\\n---\\n\\nSee you next year! Maybe in Rust, maybe not :upside_down_face:\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[_A\\\\*_]: https://en.wikipedia.org/wiki/A*_search_algorithm\\n[`BinaryHeap`]: https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html\\n[`Reverse`]: https://doc.rust-lang.org/std/cmp/struct.Reverse.html\\n[docs of the `BinaryHeap`]: https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#min-heap"},{"id":"aoc-2022/3rd-week","metadata":{"permalink":"/blog/aoc-2022/3rd-week","editUrl":"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/03-week-3.md","source":"@site/blog/aoc-2022/03-week-3.md","title":"3rd week of Advent of Code \'22 in Rust","description":"Surviving third week in Rust.","date":"2023-07-06T21:00:00.000Z","formattedDate":"July 6, 2023","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":11.565,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"3rd week of Advent of Code \'22 in Rust","description":"Surviving third week in Rust.","date":"2023-07-06T21:00","slug":"aoc-2022/3rd-week","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"4th week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/4th-week"},"nextItem":{"title":"Sort the matrix diagonally","permalink":"/blog/leetcode/sort-diagonally"}},"content":"Let\'s go through the third week of [_Advent of Code_] in Rust.\\n\\n\x3c!--truncate--\x3e\\n\\n## [Day 15: Beacon Exclusion Zone](https://adventofcode.com/2022/day/15)\\n\\n:::info tl;dr\\n\\nTriangulating a distress beacon based on the information from the sensors.\\n\\n:::\\n\\n### Solution\\n\\nRelatively easy thing to implement, no major Rust issues hit.\\n\\n## [Day 16: Proboscidea Volcanium](https://adventofcode.com/2022/day/16)\\n\\n:::info tl;dr\\n\\nFinding a max flow in a graph given some time constraints.\\n\\n:::\\n\\n### Solution\\n\\nI have used some interesting things to implement this and make it easier for me.\\n\\n#### Indexing in graph\\n\\nI have come across a situation where I needed to keep more information regarding\\nthe graph\u2026 In that case you can, of course, create a structure and keep it in,\\nbut once you have multiple members in the structure it gets harder to work with\\nsince you need to address the fields in the structure. When you work with graph,\\nyou frequently need to access the vertices and in this case it felt a lot easier\\nto implement the indexing in a graph, rather than explicitly access the\\nunderlying data structure.\\n\\nHere you can see a rather short snippet from the solution that allows you to\\n\u201cindex\u201d the graph:\\n```rust\\nimpl Index<&str> for Graph {\\n type Output = Vertex;\\n\\n fn index(&self, index: &str) -> &Self::Output {\\n &self.g[index]\\n }\\n}\\n```\\n\\n#### Cartesian product\\n\\nDuring the implementation I had to utilize Floyd-Warshall algorithm for finding\\nthe shortest path between pairs of vertices and utilized the `iproduct!` macro\\nfrom the [`itertools`]. It is a very useful higher-order function that allows\\nyou to keep the nesting of the loops at a minimum level while still maintaining\\nthe same functionality.\\n\\n#### \u201cImplementing\u201d an iterator\\n\\nFor the second part, you get to split the work between 2 actors. That way you\\ncan achieve higher efficiency of the whole process that you\'re planning, but it\\nalso makes it harder to evaluate algorithmically, since you need to check the\\ndifferent ways the work can be split.\\n\\nBeing affected by _functional programming brain damage_:tm:, I have chosen to\\ndo this part by function that returns an iterator over the possible ways:\\n```rust\\nfn pairings(\\n valves: &BTreeSet,\\n) -> impl Iterator, BTreeSet)> + \'_ {\\n let mapping = valves.iter().collect_vec();\\n\\n let max_mask = 1 << (valves.len() - 1);\\n\\n (0..max_mask).map(move |mask| {\\n let mut elephant = BTreeSet::new();\\n let mut human = BTreeSet::new();\\n\\n for (i, &v) in mapping.iter().enumerate() {\\n if (mask & (1 << i)) == 0 {\\n human.insert(v.clone());\\n } else {\\n elephant.insert(v.clone());\\n }\\n }\\n\\n (human, elephant)\\n })\\n}\\n```\\n\\n## [Day 17: Pyroclastic Flow](https://adventofcode.com/2022/day/17)\\n\\n:::info tl;dr\\n\\nSimulating an autonomous Tetris where pieces get affected by a series of jets of\\nhot gas.\\n\\n:::\\n\\n### Solution\\n\\nSimilarly to the previous day I have created some iterators :smile:\\n\\n#### Collision detection\\n\\nOnce you need to check for collisions it is very helpful to be able to just\\niterate through the positions that can actually collide with the wall or other\\npiece.\\n\\nTo get the desired behaviour, you can just compose few smaller functions:\\n```rust\\nfn occupied(shape: &[Vec]) -> impl Iterator + \'_ {\\n shape.iter().enumerate().flat_map(|(y, row)| {\\n row.iter().enumerate().filter_map(move |(x, c)| {\\n if c == &\'#\' {\\n Some(Vector2D::new(x as isize, y as isize))\\n } else {\\n None\\n }\\n })\\n })\\n}\\n```\\n\\nIn the end, we get relative positions which we can adjust later when given the\\nspecific positions from iterator. You can see some interesting parts in this:\\n\\n* `.enumerate()` allows us to get both the indices (coordinates) and the line\\n or, later on, the character itself,\\n* `.flat_map()` flattens the iterator, i.e. when we return another iterator,\\n they just get chained instead of iterating over iterators (which sounds pretty\\n disturbing, doesn\'t it?),\\n* and finally `.filter_map()` which is pretty similar to the \u201cbasic\u201d `.map()`\\n with a one, key, difference that it expects the items of an iterator to be\\n mapped to an `Option` from which it ignores nothing (as in `None` :wink:)\\n and also unwraps the values from `Some(\u2026)`.\\n\\n#### Infinite iterator\\n\\nIn the solution we cycle through both Tetris-like shapes that fall down and the\\njets that move our pieces around. Initially I have implemented my own infinite\\niterator that just yields the indices. It is a very simple, yet powerful, piece\\nof code:\\n```rust\\nstruct InfiniteIndex {\\n size: usize,\\n i: usize,\\n}\\n\\nimpl InfiniteIndex {\\n fn new(size: usize) -> InfiniteIndex {\\n InfiniteIndex { size, i: size - 1 }\\n }\\n}\\n\\nimpl Iterator for InfiniteIndex {\\n type Item = usize;\\n\\n fn next(&mut self) -> Option {\\n self.i = (self.i + 1) % self.size;\\n Some(self.i)\\n }\\n}\\n```\\n\\nHowever when I\'m looking at the code now, it doesn\'t really make much sense\u2026\\nGuess what, we can use a built-in function that is implemented on iterators for\\nthat! The function is called `.cycle()`\\n\\nOn the other hand, I am not going to switch to that function, since it would\\nintroduce an another myriad of issues caused by the fact that I create iterators\\nright away in the constructor of my structure and the iterators would borrow\\nboth the jets and shapes which would introduce a lifetime dependency into the\\nstructure.\\n\\n## [Day 18: Boiling Boulders](https://adventofcode.com/2022/day/18) \\n\\n:::info tl;dr\\n\\nLet\'s compute a surface area of some obsidian approximated via coordinates of\\ncubes.\\n\\n:::\\n\\n### Solution\\n\\nThis day is kinda interesting, because it shows how easily you can complicate the\\nproblem and also how much can you screw yourself over with the optimization and\\n\u201csmart\u201d approach.\\n\\nFor the first part you need to find the surface area of an obsidian that is\\napproximated by cubes. Now, that is a very easy thing to do, just keep the track\\nof already added cubes, and check if the newly added cube touches any face of any\\nother cube. Simple, and with a `BTreeSet` relatively efficient way to do it.\\n\\nHowever the second part lets you on a secret that there may be some surface area\\nfrom the \u201cinside\u201d too and you want to know only the one from the outside of the\\nobsidian. I have seen some solutions later, but if you check your data, you might\\nnotice that the bounding box of all the cubes isn\'t that big at all. Therefore I\\nchose to pre-construct the box beforehand, fill in the cubes and then just run a\\nBFS turning all the lava on the outside into the air. Now you just need to check\\ncubes and count how many of their faces touch the air.\\n\\n## [Day 19: Not Enough Minerals](https://adventofcode.com/2022/day/19)\\n\\n:::info tl;dr\\n\\nFinding out the best strategy for building robots to collect geodes.\\n\\n:::\\n\\n### Solution\\n\\nNot much interesting stuff to mention apart from the suggestion to never believe\\nthat the default implementation given by `derive` macro is what you want, it\\ndoesn\'t have to be. :smile:\\n\\n## [Day 20: Grove Positioning System](https://adventofcode.com/2022/day/20)\\n\\n:::info tl;dr\\n\\nShuffling around the _circular linked list_ to find the coordinates.\\n\\n:::\\n\\nNow, small rant for this day is in place. They\'ve never mentioned that coordinates\\ncan repeat and therefore the values are non-unique. This is something that did\\nnot happen in the given sample, but was present in the user input. It took \xbba lot\xab\\nto realize that this is the issue.\\n\\n### Solution\\n\\nI have tried implementing a circular linked list for this\u2026 and I have failed\\nmiserably. To be fair, I still have no clue why. It was \u201cfun\u201d to play around with\\nthe `Rc>`. In the end I failed on _wrong answer_. I have also encountered\\na rather interesting issue with `.borrow_mut()` method being used on `Rc>`.\\n\\n#### `.borrow_mut()`\\n\\nConsider the following snippet of the code (taken from the documentation):\\n```rust\\nuse std::cell::{RefCell, RefMut};\\nuse std::collections::HashMap;\\nuse std::rc::Rc;\\n// use std::borrow::BorrowMut;\\n\\nfn main() {\\n let shared_map: Rc> = Rc::new(RefCell::new(HashMap::new()));\\n // Create a new block to limit the scope of the dynamic borrow\\n {\\n let mut map: RefMut<_> = shared_map.borrow_mut();\\n map.insert(\\"africa\\", 92388);\\n map.insert(\\"kyoto\\", 11837);\\n map.insert(\\"piccadilly\\", 11826);\\n map.insert(\\"marbles\\", 38);\\n }\\n\\n // Note that if we had not let the previous borrow of the cache fall out\\n // of scope then the subsequent borrow would cause a dynamic thread panic.\\n // This is the major hazard of using `RefCell`.\\n let total: i32 = shared_map.borrow().values().sum();\\n println!(\\"{total}\\");\\n}\\n```\\n\\nWe allocate a hash map on the heap and then in the inner block, we borrow it as\\na mutable reference, so that we can use it.\\n\\n:::note\\n\\nIt is a very primitive example for `Rc>` and mutable borrow.\\n\\n:::\\n\\nIf you uncomment the 4th line with `use std::borrow::BorrowMut;`, you cannot\\ncompile the code anymore, because of\\n```\\n Compiling playground v0.0.1 (/playground)\\nerror[E0308]: mismatched types\\n --\x3e src/main.rs:10:34\\n |\\n10 | let mut map: RefMut<_> = shared_map.borrow_mut();\\n | --------- ^^^^^^^^^^^^^^^^^^^^^^^ expected struct `RefMut`, found mutable reference\\n | |\\n | expected due to this\\n |\\n = note: expected struct `RefMut<\'_, _>`\\n found mutable reference `&mut Rc>>`\\n\\nerror[E0599]: no method named `insert` found for struct `RefMut<\'_, _>` in the current scope\\n --\x3e src/main.rs:11:13\\n |\\n11 | map.insert(\\"africa\\", 92388);\\n | ^^^^^^ method not found in `RefMut<\'_, _>`\\n\\nerror[E0599]: no method named `insert` found for struct `RefMut<\'_, _>` in the current scope\\n --\x3e src/main.rs:12:13\\n |\\n12 | map.insert(\\"kyoto\\", 11837);\\n | ^^^^^^ method not found in `RefMut<\'_, _>`\\n\\nerror[E0599]: no method named `insert` found for struct `RefMut<\'_, _>` in the current scope\\n --\x3e src/main.rs:13:13\\n |\\n13 | map.insert(\\"piccadilly\\", 11826);\\n | ^^^^^^ method not found in `RefMut<\'_, _>`\\n\\nerror[E0599]: no method named `insert` found for struct `RefMut<\'_, _>` in the current scope\\n --\x3e src/main.rs:14:13\\n |\\n14 | map.insert(\\"marbles\\", 38);\\n | ^^^^^^ method not found in `RefMut<\'_, _>`\\n\\nSome errors have detailed explanations: E0308, E0599.\\nFor more information about an error, try `rustc --explain E0308`.\\nerror: could not compile `playground` due to 5 previous errors\\n```\\n\\nIt might seem **a bit** ridiculous. However, I got to a point where the compiler\\nsuggested `use std::borrow::BorrowMut;` and it resulted in breaking parts of the\\ncode that worked previously. I think it may be a good idea to go over what is\\nhappening here.\\n\\n##### `.borrow_mut()` on `Rc>`\\n\\nLet\'s consider a variable `x` of type `Rc>`. What happens when you\\ncall `.borrow_mut()` on it? We can look at the `Rc` type, and\u2026 hang on! There is\\nneither `.borrow_mut()` method or `BorrowMut` trait implemented. How can we do it\\nthen?\\n\\nLet\'s go further and we can see that `RefCell` implements a `.borrow_mut()`\\nmethod. OK, but how can we call it on the `Rc`? Easily! `Rc` implements\\n`Deref` and therefore you can call methods on `Rc` objects as if they were\\n`T` objects. If we read on _`Deref` coercion_, we can see the following:\\n\\n> If `T` implements `Deref`, \u2026:\\n> * \u2026\\n> * `T` implicitly implements all the (immutable) methods of the type `U`.\\n\\nWhat is the requirement for the `.borrow_mut()` on `RefCell`? Well, it needs\\n`&self`, so the `Deref` implements the `.borrow_mut()` for the `Rc>`.\\n\\n##### `BorrowMut` trait\\n\\nI have not been able to find a lot on this trait. My guess is that it provides a\\nmethod instead of a syntactic sugar (`&mut x`) for the mutable borrow. And also\\nit provides default implementations for the types:\\n```rust\\nimpl BorrowMut for String\\n\\nimpl BorrowMut for &mut T\\nwhere\\n T: ?Sized,\\n\\nimpl BorrowMut for T\\nwhere\\n T: ?Sized,\\n\\nimpl BorrowMut<[T]> for Vec\\nwhere\\n A: Allocator,\\n\\nimpl BorrowMut for Box\\nwhere\\n A: Allocator,\\n T: ?Sized,\\n\\nimpl BorrowMut<[T]> for [T; N]\\n```\\n\\n##### Conflict\\n\\nNow the question is why did it break the code\u2026 My first take was that the type\\n`Rc>` has some _specialized_ implementation of the `.borrow_mut()` and\\nthe `use` overrides it with the default, which is true **in a sense**. However\\nthere is no _specialized_ implementation. Let\'s have a look at the trait and the\\ntype signature on the `RefCell`:\\n```rust\\n// trait\\npub trait BorrowMut: Borrow\\nwhere\\n Borrowed: ?Sized,\\n{\\n fn borrow_mut(&mut self) -> &mut Borrowed;\\n}\\n\\n// \u2039RefCell.borrow_mut()\u203a type signature\\npub fn borrow_mut(&self) -> RefMut<\'_, T>\\n```\\n\\nI think that we can definitely agree on the fact that `RefMut<\'_, T>` is not the\\n`RefCell`.\\n\\n**In my opinion**, `RefCell` implements a **separate** `.borrow_mut()` rather\\nthan implementing the interface, because it **cannot** satisfy the type requirements\\nof the trait.\\n\\n:::caution\\n\\nI wonder how are we expected to deal with this conflict, if and when, we need\\nboth the `.borrow_mut()` of the trait and `.borrow_mut()` of the `RefCell`.\\n\\n:::\\n\\n:::tip Fun fact\\n\\nI was suggested by the compiler to do `use std::borrow::BorrowMut;` and break the\\ncode.\\n\\nSo much for the _almighty_ and _helpful_ compiler\u2026\\n\\n:::\\n\\n## [Day 21: Monkey Math](https://adventofcode.com/2022/day/21)\\n\\n:::info tl;dr\\n\\nComputing an expression tree and then also finding ideal value for a node.\\n\\n:::\\n\\n### Solution\\n\\nRelatively simple, until you get to the 2nd part where you start to practice\\na lot of the copy-paste. I have managed to sneak some perverted stuff in there\\nthough :) Let\'s go through the details.\\n\\n#### `Default` trait\\n\\nFor the first time and twice I had a need to have a default value for my types,\\nenumerations in this case. Rust offers a very nice trait[^1] that is described\\nas:\\n\\n> A trait for giving a type a useful default value.\\n\\nI guess it sums it up nicely. The more interesting part about this is the fact\\nthat you can use the _macro machinery_ to save yourself some typing. If you have\\nenumeration of which the default value doesn\'t bear any parameter, you can just\\ndo[^2]:\\n\\n```rust\\n#[derive(Default)]\\nenum Color {\\n #[default]\\n White,\\n Gray,\\n Black,\\n}\\n```\\n\\n#### Abusing negation\\n\\nIf you want to use a _unary minus_ operator on your own type, you can implement\\na `Neg` trait[^3]. I was dealing with a binary tree and needed a way how to look\\nat the other side, so I have just implemented the negation for flipping between\\nleft and right :smile:\\n\\n[^1]: [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) docs\\n[^2]: Pardon my example from the graph algorithms ;)\\n[^3]: [`Neg`](https://doc.rust-lang.org/std/ops/trait.Neg.html) docs\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[`itertools`]: https://crates.io/crates/itertools\\n[this Reddit post and the comment]: https://www.reddit.com/r/adventofcode/comments/zb98pn/comment/iyq0ono"},{"id":"leetcode/sort-diagonally","metadata":{"permalink":"/blog/leetcode/sort-diagonally","editUrl":"https://gitlab.com/mfocko/blog/tree/main/blog/leetcode/sort-matrix-diagonally.md","source":"@site/blog/leetcode/sort-matrix-diagonally.md","title":"Sort the matrix diagonally","description":"Compiler assisted development.","date":"2023-03-04T23:15:00.000Z","formattedDate":"March 4, 2023","tags":[{"label":"cpp","permalink":"/blog/tags/cpp"},{"label":"leetcode","permalink":"/blog/tags/leetcode"},{"label":"iterators","permalink":"/blog/tags/iterators"}],"readingTime":16.99,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"Sort the matrix diagonally","description":"Compiler assisted development.","date":"2023-03-04T23:15","slug":"leetcode/sort-diagonally","authors":"mf","tags":["cpp","leetcode","iterators"],"hide_table_of_contents":false},"prevItem":{"title":"3rd week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/3rd-week"},"nextItem":{"title":"2nd week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/2nd-week"}},"content":"Let\'s try to solve one of the LeetCode challenges in easy and hard mode at the\\nsame time.\\n\\n\x3c!--truncate--\x3e\\n\\n* Link to the problem: https://leetcode.com/problems/sort-the-matrix-diagonally/\\n\\n## Problem description\\n\\nA **matrix diagonal** is a diagonal line of cells starting from some cell in\\neither the topmost row or leftmost column and going in the bottom-right direction\\nuntil reaching the matrix\'s end. For example, the **matrix diagonal** starting\\nfrom `mat[2][0]`, where `mat` is a `6 x 3` matrix, includes cells `mat[2][0]`,\\n`mat[3][1]`, and `mat[4][2]`.\\n\\nGiven an `m x n` matrix `mat` of integers, sort each matrix diagonal in ascending\\norder and return the resulting matrix.\\n\\n### Example\\n\\n![Image describing the problem](https://assets.leetcode.com/uploads/2020/01/21/1482_example_1_2.png)\\n\\n## Skeleton and initial adjustments\\n\\nWe are given the following skeleton for the C++ and the given challenge:\\n\\n```cpp\\nclass Solution {\\npublic:\\n vector> diagonalSort(vector>& mat) {\\n \\n }\\n};\\n```\\n\\nThe task is to sort the passed matrix diagonally and then return it. First of all,\\nI don\'t like to solve this in a web browser, so we\'ll need to adjust it accordingly\\nfor running it locally. We\'ll start by including the `vector` header and using\\nfully-qualified namespaces[^1] and also adding few tests:\\n\\n```cpp\\n#include \\n#include \\n\\nusing matrix = std::vector>;\\n\\nclass Solution {\\npublic:\\n matrix diagonalSort(matrix& mat)\\n {\\n }\\n};\\n\\nstatic void test_case_1()\\n{\\n // Input: mat = [[3,3,1,1],[2,2,1,2],[1,1,1,2]]\\n // Output: [[1,1,1,1],[1,2,2,2],[1,2,3,3]]\\n\\n Solution s;\\n assert((s.diagonalSort(std::vector { std::vector { 3, 3, 1, 1 },\\n std::vector { 2, 2, 1, 2 },\\n std::vector { 1, 1, 1, 2 } })\\n == std::vector { std::vector { 1, 1, 1, 1 },\\n std::vector { 1, 2, 2, 2 },\\n std::vector { 1, 2, 3, 3 } }));\\n}\\n\\nstatic void test_case_2()\\n{\\n // Input: mat =\\n // [[11,25,66,1,69,7],[23,55,17,45,15,52],[75,31,36,44,58,8],[22,27,33,25,68,4],[84,28,14,11,5,50]]\\n // Output:\\n // [[5,17,4,1,52,7],[11,11,25,45,8,69],[14,23,25,44,58,15],[22,27,31,36,50,66],[84,28,75,33,55,68]]\\n\\n Solution s;\\n assert((s.diagonalSort(std::vector { std::vector { 11, 25, 66, 1, 69, 7 },\\n std::vector { 23, 55, 17, 45, 15, 52 },\\n std::vector { 75, 31, 36, 44, 58, 8 },\\n std::vector { 22, 27, 33, 25, 68, 4 },\\n std::vector { 84, 28, 14, 11, 5, 50 } })\\n == std::vector { std::vector { 5, 17, 4, 1, 52, 7 },\\n std::vector { 11, 11, 25, 45, 8, 69 },\\n std::vector { 14, 23, 25, 44, 58, 15 },\\n std::vector { 22, 27, 31, 36, 50, 66 },\\n std::vector { 84, 28, 75, 33, 55, 68 } }));\\n}\\n\\nint main()\\n{\\n test_case_1();\\n test_case_2();\\n\\n return 0;\\n}\\n```\\n\\nWe need to return the matrix, but we\'re given a reference to the input matrix. We\\ncan easily abuse the C++ here and just switch the reference to value, this way\\nthe matrix will be copied when passed to the function, we can sort the copy and\\njust return it back. And we also get yelled by the compiler for the fact that the\\nmethod doesn\'t return anything yet, so to make it \u201cshut up\u201d we will just return\\nthe input for now:\\n\\n```diff\\n- matrix diagonalSort(matrix& mat)\\n+ matrix diagonalSort(matrix mat)\\n {\\n+ return mat;\\n }\\n```\\n\\nNow, we get the copy and we\'re good to go.\\n\\n## Na\xefve solution\\n\\nAs you may know, C++ offers a plethora of functions that can be used to your\\nadvantage, given that you know how to \u201cbend\u201d the data structures accordingly.\\n\\nWhat does that mean for us? Well, we have an `std::sort`, we can use it, right?\\nLet\'s have a look at it:\\n```cpp\\ntemplate< class RandomIt >\\nvoid sort( RandomIt first, RandomIt last );\\n```\\n\\nThis overload is more than we need. What does it do? It just sorts the elements\\nin the range `[first, last)` using `operator<` on them. We can\'t sort the whole\\nmatrix using this, but\u2026 we can sort just \xbbone\xab diagonal without doing much work\\non our end.\\n\\nWhat is the `RandomIt` type though? If we look more into the documentation, we\\ncan easily find the requirements for it and also learn that it\'s a _random access_\\n_iterator_ and allows swapping its values at the same time.\\n\\n:::tip Random access iterator\\n\\nWhat is the _random access iterator_ though? We can find it in a documentation\\nand see the following description:\\n\\n> A **LegacyRandomAccessIterator** is a [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator)\\n> that can be moved to point to any element in constant time.\\n\\nAfter that we can see all the requirements for it being listed. I don\'t feel like\\nreading them right now, so we will just use it and see where the compilation blows\\nup, i.e. \u201c_compiler-assisted development_\u201d[^2] if you will ;)\\n\\n:::\\n\\nNow we know that we can use `std::sort` to sort the diagonal itself, but we also\\nneed to get the diagonals somehow. I\'m rather lazy, so I\'ll just delegate it to\\nsomeone else[^3]. And that way we get\\n```cpp\\nmatrix diagonalSort(matrix mat)\\n{\\n // we iterate over the diagonals\\n for (auto d : diagonals(mat)) {\\n // and we sort each diagonal\\n std::sort(d.begin(), d.end());\\n }\\n\\n // we take the matrix by copy, so we can sort in-situ and return the copy\\n // that we sorted\\n return mat;\\n}\\n```\\n\\nThis solution looks very simple, doesn\'t it? Well, cause it is.\\nLet\'s try compiling it:\\n```\\nmatrix-sort.cpp:11:23: error: use of undeclared identifier \'diagonals\' [clang-diagnostic-error]\\n for (auto d : diagonals(mat)) {\\n ^\\nFound compiler error(s).\\nmake: *** [makefile:14: tidy] Error 1\\n```\\n\\nOK, seems about right. We haven\'t implemented the `diagonals` yet. And based on\\nwhat we\'ve written so far, we need a function or a class `diagonals` that will\\ngive us the diagonals we need.\\n\\n## Implementing the `diagonals`\\n\\nCool, so we need the function that will let us go through each and every diagonal\\nin our matrix. We use the _for-range_ loop, so whatever we get back from the\\n`diagonals` must support `.begin()` and `.end()`. Since I am a masochist, we will\\ndo such functionality for a matrix of any type, not just the `int` from the challenge.\\n\\nAs I said, we need to be able to\\n* construct the object\\n* get the beginning\\n* get the end (the \u201csentinel\u201d)\\n\\n```cpp\\ntemplate \\nclass diagonals {\\n using matrix_t = std::vector>;\\n\\n matrix_t& _matrix;\\n\\npublic:\\n diagonals(matrix_t& m)\\n : _matrix(m)\\n {\\n }\\n diagonals_iter begin()\\n {\\n /* TODO */\\n }\\n diagonals_iter end()\\n {\\n /* TODO */\\n }\\n};\\n```\\n\\nNow we have a `diagonals` that we can use to go through the diagonals. We haven\'t\\nimplemented the core of it yet. Let\'s go through what we have for now.\\n\\nWe have a templated class with templated `T` that is used as a placeholder for any\\ntype we would store in the matrix. Because I\'m lazy, I have defined the `matrix_t`\\ntype that is a \u201cshortcut\u201d for `std::vector>`, so I don\'t have to\\ntype it out all the time. Of course, we need to store the matrix, we are given,\\nas a private attribute. And then just have the constructor and the 2 methods we\\nneed for the _for-range_.\\n\\n### Iterating over diagonals\\n\\nNow that we have an object that will allow us to iterate through the diagonals,\\nwe need to implement the iterating itself. We need to go through all of them, so\\nwe have multiple options how to do so. I have decided to start from the \u201cmain\u201d\\ndiagonal that starts at `(0, 0)` index and then proceed with the diagonals starting\\nin the first row, followed by the rest of the diagonals in the first column.\\n\\nWe need to be able to tell that we\'ve iterated through all of them, and also we\\nneed to know which diagonal is next. For that purpose we will pass the indices\\nof the first cell on the diagonal. That way we can always tell how to move forward.\\n\\nWe will start by updating the `begin` and `end` to reflect our choice accordingly.\\n\\n```cpp\\ndiagonals_iter begin() { return diagonals_iter { _matrix, 0, 0 }; }\\ndiagonals_iter end() { return diagonals_iter { _matrix, 0, _matrix.size() }; }\\n```\\n\\nFor the `begin` we return the first diagonal that starts at `(0, 0)`. And because\\nwe have decided to do the diagonals in the first column at the end, the first\\ndiagonal that is not a valid one is the one at `(0, height)`. Apart from the\\nindices, we also need to pass reference to the matrix itself.\\n\\n:::note\\n\\nYou may have noticed that we also include the diagonals that have length 1,\\nspecifically the ones at `(0, height - 1)` and `(width - 1, 0)`. We are implementing\\nan iterator that **should not** care about the way it\'s being used. Therefore, we\\ndon\'t care about the fact they don\'t need to be sorted.\\n\\n:::\\n\\nCool, let\'s leave the iterator itself to someone else, right?[^4]\\n\\n### Implementing the iterator over diagonals\\n\\nWe can start with a simple skeleton based on the information that we pass from\\nthe `diagonals`. Also to utilize the `matrix_t` and also contain implementation\\ndetails hidden away, we will put this code into the `diagonals` class.\\n\\n```cpp\\nclass diagonals_iter {\\n matrix_t& m;\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)\\n : m(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n};\\n```\\n\\nIn this case we will be implementing a \u201csimple\u201d forward iterator, so we don\'t\\nneed to implement a lot. Notably it will be:\\n* inequality operator (we need to know when we reach the end and have nothing to\\n iterate over)\\n* preincrementation operator (we need to be able to move around the iterable)\\n* dereference operator (we need to be able to retrieve the objects we iterate\\n over)\\n\\n```cpp\\nclass diagonals_iter {\\n matrix_t& m;\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)\\n : m(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n\\n bool operator!=(const diagonals_iter& rhs) const\\n {\\n // iterators are not equal if they reference different matrices, or\\n // their positions differ\\n return m != rhs.m || x != rhs.x || y != rhs.y;\\n }\\n\\n diagonals_iter& operator++()\\n {\\n if (y != 0) {\\n // iterating through diagonals down the first column\\n y++;\\n return *this;\\n }\\n\\n // iterating the diagonals along the first row\\n x++;\\n if (x == m.front().size()) {\\n // switching to diagonals in the first column\\n x = 0;\\n y++;\\n }\\n\\n return *this;\\n }\\n\\n diagonal operator*() const { return diagonal { m, x, y }; }\\n};\\n```\\n\\nLet\'s go one-by-one. Inequality operator is rather simple, just compare iterator\'s\\nattributes field-by-field. If you think about it, checking inequality of two 2D\\nvectors may be a bit inefficient, therefore, we can swap around and check it as\\na last thing.\\n\\n```diff\\n- return m != rhs.m || x != rhs.x || y != rhs.y;\\n+ return x != rhs.x || y != rhs.y || m != rhs.m;\\n```\\n\\nPreincrementation is where the magic happens. If you have a better look, you can\\nsee two branches of this operation:\\n\\n1. When `y != 0` (we\'re iterating over the diagonals in the first column)\\n In this case, we just bump the row and we\'re done.\\n2. When `y == 0` (we\'re iterating over the diagonals in the first row)\\n In this case, we bump the column and check if we haven\'t gotten out of bounds,\\n i.e. the end of the first row. If we get out of the bounds, we\'re continuing\\n with the second diagonal in the first column.\\n\\nDereferencing the iterator must \u201cyield\u201d something. In our case it will be the\\ndiagonal that we want to sort. For sorting we need just the iterators that can\\nmove around said diagonal. The simplest thing, we can do, is to delegate it to\\nsomething else. In our case it will be a class called `diagonal`.\\n\\n## Implementing the `diagonal` itself\\n\\nAfter implementing the iterator over diagonals, we know that all we need to describe\\na diagonal is the matrix itself and the \u201cstart\u201d of the diagonal (row and column).\\nAnd we also know that the diagonal must provide some iterators for the `std::sort`\\nfunction. We can start with the following skeleton:\\n```cpp\\ntemplate \\nclass diagonal {\\n using matrix_t = std::vector>;\\n\\n matrix_t& matrix;\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n diagonal(matrix_t& matrix, std::size_t x, std::size_t y)\\n : matrix(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n\\n diagonal_iter begin() const { return diagonal_iter { matrix, x, y }; }\\n\\n diagonal_iter end() const\\n {\\n auto max_x = matrix[y].size();\\n auto max_y = matrix.size();\\n\\n // we need to find the distance in which we get out of bounds (either in\\n // column or row)\\n auto steps = std::min(max_x - x, max_y - y);\\n\\n return diagonal_iter { matrix, x + steps, y + steps };\\n }\\n};\\n```\\n\\nInitialization is rather simple, we just \u201ckeep\u201d the stuff we get, `begin` is the\\nsimplest, we just delegate.\\n\\nIn case of the `end`, it gets more complicated. We need to know where is the \u201cend\u201d\\nof the diagonal. Since `end` should point to the first element \u201cafter\u201d the iterable,\\nwe know that it\'s the first position of the iterator where either `y` becomes\\n`matrix.size()` or `x` becomes `matrix[y].size()`. Also we are moving along diagonal,\\nduh, therefore we can deduce the first \u201cposition\u201d afterwards by minimal amount of\\nsteps to get out of the any column or row, hence `std::min(max_x - x, max_y - y)`.\\nFinal position is then computed simply by adding the steps to the beginning of\\nthe diagonal.\\n\\nNow we just need to finish the iterator for the diagonal itself and we\'re done.\\n\\n### Implementing `diagonal_iter`\\n\\nThis part is the hardest from all we need to do. It\'s because of the requirements\\nof the `std::sort` that requires us to implement a _random access iterator_. I have\\nbriefly described it above, and \u201cin a nutshell\u201d it means that we need to implement\\nan iterator that can move in constant time along the diagonal in any amount of\\nsteps.\\n\\nLet\'s go through all of the functionality that our iterator needs to support to\\nbe used in `std::sort`. We need the usual operations like:\\n\\n* equality/inequality\\n* incrementation\\n* dereferencing\\n\\nWe will also add all the types that our iterator uses with the category of the\\niterator, i.e. what interface it supports:\\n```cpp\\nclass diagonal_iter {\\n // we need to keep reference to the matrix itself\\n matrix_t& m;\\n\\n // we need to be able to tell our current position\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n using difference_type = std::ptrdiff_t;\\n using value_type = T;\\n using pointer = T*;\\n using reference = T&;\\n using iterator_category = std::random_access_iterator_tag;\\n\\n diagonal_iter(matrix_t& matrix,\\n std::size_t x,\\n std::size_t y)\\n : m(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n\\n bool operator==(const diagonal_iter& rhs) const\\n {\\n return x == rhs.x && y == rhs.y && m == rhs.m;\\n }\\n\\n diagonal_iter& operator++()\\n {\\n // we are moving along the diagonal, so we increment both \u2039x\u203a and \u2039y\u203a at\\n // the same time\\n x++;\\n y++;\\n return *this;\\n }\\n\\n reference operator*() const { return m[y][x]; }\\n};\\n```\\n\\nThis is pretty similar to the previous iterator, but now we need to implement the\\nremaining requirements of the _random access iterator_. Let\'s see what those are:\\n\\n* decrementation - cause we need to be able to move backwards too, since _random _\\n _access iterator_ extends the interface of _bidirectional iterator_\\n* moving the iterator in either direction by steps given as an integer\\n* being able to tell the distance between two iterators\\n* define an ordering on the iterators\\n\\nLet\'s fill them in:\\n```cpp\\nclass diagonal_iter {\\n // we need to keep reference to the matrix itself\\n matrix_t& m;\\n\\n // we need to be able to tell our current position\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n using difference_type = std::ptrdiff_t;\\n using value_type = T;\\n using pointer = T*;\\n using reference = T&;\\n using iterator_category = std::random_access_iterator_tag;\\n\\n diagonal_iter(matrix_t& matrix,\\n std::size_t x,\\n std::size_t y)\\n : m(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n\\n bool operator==(const diagonal_iter& rhs) const\\n {\\n return x == rhs.x && y == rhs.y && m == rhs.m;\\n }\\n\\n diagonal_iter& operator++()\\n {\\n // we are moving along the diagonal, so we increment both \u2039x\u203a and \u2039y\u203a at\\n // the same time\\n x++;\\n y++;\\n return *this;\\n }\\n\\n reference operator*() const { return m[y][x]; }\\n\\n // exactly opposite to the incrementation\\n diagonal_iter operator--()\\n {\\n x--;\\n y--;\\n return *this;\\n }\\n\\n // moving \u2039n\u203a steps back is same as calling decrementation \u2039n\u203a-times, so we\\n // can just return a new iterator and subtract \u2039n\u203a from both coordinates in\\n // the matrix\\n diagonal_iter operator-(difference_type n) const\\n {\\n return diagonal_iter { m, x - n, y - n };\\n }\\n\\n // here we assume that we are given two iterators on the same diagonal\\n difference_type operator-(const diagonal_iter& rhs) const\\n {\\n assert(m == rhs.m);\\n return x - rhs.x;\\n }\\n\\n // counterpart of moving \u2039n\u203a steps backwards\\n diagonal_iter operator+(difference_type n) const\\n {\\n return diagonal_iter { m, x + n, y + n };\\n }\\n\\n // we compare the coordinates, and also assume that those 2 iterators are\\n // lying on the same diagonal\\n bool operator<(const diagonal_iter& rhs) const\\n {\\n assert(m == rhs.m);\\n return x < rhs.x && y < rhs.y;\\n }\\n};\\n```\\n\\nAt this point we could probably try and compile it, right? If we do so, we will\\nget yelled at by a compiler for the following reasons:\\n```\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type \'diagonal::diagonal_iter\' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\\n __last = __next;\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1817:11: note: in instantiation of function template specialization \'std::__unguarded_linear_insert::diagonal_iter, __gnu_cxx::__ops::_Val_less_iter>\' requested here\\n std::__unguarded_linear_insert(__i,\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1849:9: note: in instantiation of function template specialization \'std::__insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__insertion_sort(__first, __first + int(_S_threshold), __comp);\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization \'std::__final_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__final_insertion_sort(__first, __last, __comp);\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization \'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\\n ^\\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization \'std::sort::diagonal_iter>\' requested here\\n std::sort(d.begin(), d.end());\\n ^\\nmatrix-sort.cpp:17:19: note: copy assignment operator of \'diagonal_iter\' is implicitly deleted because field \'m\' is of reference type \'diagonal::matrix_t &\' (aka \'vector> &\')\\n matrix_t& m;\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1830:2: error: no matching function for call to \'__unguarded_linear_insert\' [clang-diagnostic-error]\\n std::__unguarded_linear_insert(__i,\\n ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1850:9: note: in instantiation of function template specialization \'std::__unguarded_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__unguarded_insertion_sort(__first + int(_S_threshold), __last,\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization \'std::__final_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__final_insertion_sort(__first, __last, __comp);\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization \'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\\n ^\\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization \'std::sort::diagonal_iter>\' requested here\\n std::sort(d.begin(), d.end());\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1782:5: note: candidate template ignored: substitution failure [with _RandomAccessIterator = diagonal::diagonal_iter, _Compare = __gnu_cxx::__ops::_Val_less_iter]\\n __unguarded_linear_insert(_RandomAccessIterator __last,\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1923:11: error: object of type \'diagonal::diagonal_iter\' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\\n __last = __cut;\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1937:9: note: in instantiation of function template specialization \'std::__introsort_loop::diagonal_iter, long, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__introsort_loop(__first, __last,\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization \'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\\n ^\\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization \'std::sort::diagonal_iter>\' requested here\\n std::sort(d.begin(), d.end());\\n ^\\nmatrix-sort.cpp:17:19: note: copy assignment operator of \'diagonal_iter\' is implicitly deleted because field \'m\' is of reference type \'diagonal::matrix_t &\' (aka \'vector> &\')\\n matrix_t& m;\\n ^\\n```\\n\\nThat\'s a lot of noise, isn\'t it? Let\'s focus on the important parts:\\n```\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type \'diagonal::diagonal_iter\' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\\n\u2026\\nmatrix-sort.cpp:17:19: note: copy assignment operator of \'diagonal_iter\' is implicitly deleted because field \'m\' is of reference type \'diagonal::matrix_t &\' (aka \'vector> &\')\\n matrix_t& m;\\n ^\\n```\\n\\nAh! We have a reference in our iterator, and this prevents us from having a copy\\nassignment operator (that is used \u201csomewhere\u201d in the sorting algorithm). Well\u2026\\nLet\'s just wrap it!\\n```diff\\n# we need to keep a different type than reference\\n- matrix_t& m;\\n+ std::reference_wrapper m;\\n\\n# in comparison we need to get the reference out of the wrapper first\\n- return x == rhs.x && y == rhs.y && m == rhs.m;\\n+ return x == rhs.x && y == rhs.y && m.get() == rhs.m.get();\\n\\n# same when we return a reference to the \u201ccell\u201d in the matrix\\n- reference operator*() const { return m[y][x]; }\\n+ reference operator*() const { return m.get()[y][x]; }\\n\\n# and finally in the assertions that we set for the \u201cdistance\u201d and \u201cless than\u201d\\n- assert(m == rhs.m);\\n+ assert(m.get() == rhs.m.get());\\n```\\n\\nWe\'re done now! We have written an iterator over diagonals for a 2D `vector`. You can have a look at the final result [here](pathname:///files/blog/leetcode/sort-matrix-diagonally/matrix-sort.cpp).\\n\\n[^1]: just because I\'m used to it and don\'t care about your opinion ;)\\n[^2]: exercise at your own risk\\n[^3]: me in 5 minutes in fact, but don\'t make me scared\\n[^4]: me in the next section\u2026"},{"id":"aoc-2022/2nd-week","metadata":{"permalink":"/blog/aoc-2022/2nd-week","editUrl":"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/02-week-2.md","source":"@site/blog/aoc-2022/02-week-2.md","title":"2nd week of Advent of Code \'22 in Rust","description":"Surviving second week in Rust.","date":"2022-12-25T23:15:00.000Z","formattedDate":"December 25, 2022","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":20.875,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"2nd week of Advent of Code \'22 in Rust","description":"Surviving second week in Rust.","date":"2022-12-25T23:15","slug":"aoc-2022/2nd-week","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"Sort the matrix diagonally","permalink":"/blog/leetcode/sort-diagonally"},"nextItem":{"title":"1st week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/1st-week"}},"content":"Let\'s go through the second week of [_Advent of Code_] in Rust.\\n\\n\x3c!--truncate--\x3e\\n\\n## [Day 8: Treetop Tree House](https://adventofcode.com/2022/day/8)\\n\\n:::info tl;dr\\n\\nWe get a forest and we want to know how many trees are visible from the outside.\\nApart from that we want to find the best view.\\n\\n:::\\n\\nNothing interesting. We are moving around 2D map though. And indexing can get a\\nbit painful when doing so, let\'s refactor it a bit ;) During the preparation for\\nthe AoC, I have written `Vector2D` and now it\'s time to extend it with indexing\\nof `Vec` of `Vec`s. In my solution I was manipulating with indices in the following\\nway:\\n\\n- swapping them\\n- checking whether they are correct indices for the `Vec>`\\n- indexing `Vec>` with them\\n\\n:::caution\\n\\nI\'m getting familiar with Rust and starting to \u201cabuse\u201d it\u2026 While doing so, I\'m\\nalso uncovering some \u201cfeatures\u201d that I don\'t really like. Therefore I will mark\\nall of my rants with _thicc_ **\xab\u21af\xbb** mark and will try to \u201clock\u201d them into their\\nown \u201cbox of hell\u201d.\\n\\n:::\\n\\n#### Swapping indices\\n\\nRelatively simple implementation, just take the values, swap them and return new\\nvector.\\n\\n```rust\\nimpl Vector2D {\\n pub fn swap(&self) -> Self {\\n Self {\\n x: self.y,\\n y: self.x,\\n }\\n }\\n}\\n```\\n\\nPretty straight-forward implementation, but let\'s talk about the `T: Copy`. We\\nneed to use it, since we are returning a **new** vector, with swapped **values**.\\nIf we had values that cannot be copied, the only thing we could do, would be a\\nvector of references (and it would also introduce a lifetime, to which we\'ll get\\nlater on). This is pretty similar with the operations on sets from the first week.\\n\\n#### Indexing `Vec`\\n\\nI will start with the indexing, cause bound-checking is a bit more\u2026 complicated\\nthan I would like to.\\n\\n```rust\\npub fn index<\'a, T, U>(v: &\'a [Vec], idx: &Vector2D) -> &\'a U\\nwhere\\n usize: TryFrom,\\n >::Error: Debug,\\n T: Copy,\\n{\\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\\n &v[y][x]\\n}\\n```\\n\\nLet\'s talk about this mess\u2026 Body of the function is probably the most easy part\\nand should not be hard to understand, we just take the `x` and `y` and convert\\nthem both to `usize` type that can be used later on for indexing.\\n\\nThe type signature of the function is where the fun is at :wink: We are trying\\nto convert unknown type to `usize`, so we must bound the `T` as a type that can\\nbe converted to `usize`, that\'s how we got `usize: TryFrom` which basically\\nsays that `usize` must implement `TryFrom` trait and therefore allows us to\\nconvert the indices to actual `usize` indices. Using `.unwrap()` also forces us\\nto bound the error that can occur when converting `T` into `usize`, that\'s how\\nwe get `>::Error: Debug` which loosely means\\n\\n> error during conversion of `T` into `usize` must implement `Debug`,\\n> i.e. can be printed in some way or other\\n\\n`T: Copy` is required by `.try_into()` which takes `T` by-value.\\n\\nAnd now we are left only with the first line of the definition.\\n\\n:::note\\n\\nSkilled Rustaceans might notice that this implementation is rather flaky and can\\nbreak in multiple places at once. I\'ll get back to it\u2026\\n\\n:::\\n\\nLet\'s split it in multiple parts:\\n- `v: &\'a [Vec]` represents the 2D `Vec`, we are indexing, `Vec` implements\\n `Slice` trait and _clippy_ recommends using `&[T]` to `&Vec`, exact details\\n are unknown to me\\n- `idx: &Vector2D` represents the _indices_ which we use, we take them by\\n reference to avoid an unnecessary copy\\n- `-> &\'a U` means that we are returning a _reference_ to some value of type `U`.\\n Now the question is what does the `\'a` mean, we can also see it as a generic\\n type declared along `T` and `U`. And the answer is _relatively_ simple, `\'a`\\n represents a _lifetime_. We take the `v` by a reference and return a reference,\\n borrow checker validates all of the _borrows_ (or references), so we need to\\n specify that our returned value has _the same lifetime_ as the vector we have\\n taken by a reference, i.e. returned reference must live at least as long as the\\n `v`. This way we can \u201cbe sure\u201d that the returned reference is valid.\\n\\n##### Issues\\n\\nFirst issue that our implementation has is the fact that we cannot get a mutable\\nreference out of that function. This could be easily resolved by introducing new\\nfunction, e.g. `index_mut`. Which I have actually done while writing this part:\\n```rust\\npub fn index_mut<\'a, T, U>(v: &\'a mut [Vec], idx: &Vector2D) -> &\'a mut U\\nwhere\\n usize: TryFrom,\\n >::Error: Debug,\\n T: Copy,\\n{\\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\\n &mut v[y][x]\\n}\\n```\\n\\n:::caution **\xab\u21af\xbb** Why can\'t we use one function?\\n\\nWhen we consider a `Vec`, we don\'t need to consider containers as `T`, Rust\\nimplements indexing as traits `Index` and `IndexMut` that do the dirty work\\nbehind syntactic sugar of `container[idx]`.\\n\\nHowever, implementing of traits is not allowed for _external_ types, i.e. types\\nthat you haven\'t defined yourself. This means that you can implement indexing\\nover containers that you have implemented yourself, but you cannot use your own\\ntypes for indexing \u201cbuilt-in\u201d types.\\n\\nAnother part of this rabbit hole is trait `SliceIndex` that is of a relevance\\nbecause of\\n```rust\\nimpl Index for [T]\\nwhere\\n I: SliceIndex<[T]>\\n\\nimpl Index for Vec\\nwhere\\n I: SliceIndex<[T]>,\\n A: Allocator\\n\\nimpl Index for [T; N]\\nwhere\\n [T]: Index\\n```\\n\\nIn other words, if your type implements `SliceIndex` trait, it can be used\\nfor indexing. As of now, this trait has all of its required methods experimental\\nand is marked as `unsafe`.\\n\\n:::\\n\\nAnother problem is a requirement for indexing either `[Vec]` or `Vec>`.\\nThis requirement could be countered by removing inner type `Vec` and constraining\\nit by a trait `Index` (or `IndexMut` respectively) in a following way\\n```rust\\npub fn index<\'a, C, T>(v: &\'a [C], idx: &Vector2D) -> &\'a C::Output\\nwhere\\n usize: TryFrom,\\n >::Error: Debug,\\n T: Copy,\\n C: Index\\n{\\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\\n &v[y][x]\\n}\\n```\\n\\nGiven this, we can also give a more meaningful typename for indexing type, such\\nas `I`.\\n\\n#### Checking bounds\\n\\nNow we can get to the boundary checks, it is very similar, but a more\u2026 dirty.\\nFirst approach that came up was to convert the indices in `Vector2D` to `usize`,\\nbut when you add the indices up, e.g. when checking the neighbors, you can end\\nup with negative values which, unlike in C++, causes an error (instead of underflow\\nthat you can use to your advantage; you can easily guess how).\\n\\nSo how can we approach this then? Well\u2026 we will convert the bounds instead of\\nthe indices and that lead us to:\\n```rust\\npub fn in_range(v: &[Vec], idx: &Vector2D) -> bool\\nwhere\\n usize: TryInto,\\n >::Error: Debug,\\n T: PartialOrd + Copy,\\n{\\n idx.y >= 0.try_into().unwrap()\\n && idx.y < v.len().try_into().unwrap()\\n && idx.x >= 0.try_into().unwrap()\\n && idx.x\\n < v[TryInto::::try_into(idx.y).unwrap()]\\n .len()\\n .try_into()\\n .unwrap()\\n}\\n```\\n\\nYou can tell that it\'s definitely a shitty code. Let\'s improve it now! We will\\nget back to the original idea, but do it better. We know that we cannot convert\\nnegative values into `usize`, **but** we also know that conversion like that\\nreturns a `Result` which we can use to our advantage.\\n```rust\\npub fn in_range(v: &[Vec], idx: &Vector2D) -> bool\\nwhere\\n T: Copy,\\n usize: TryFrom,\\n{\\n usize::try_from(idx.y)\\n .and_then(|y| usize::try_from(idx.x).map(|x| y < v.len() && x < v[y].len()))\\n .unwrap_or(false)\\n}\\n```\\n\\n`Result` is a type similar to `Either` in Haskell and it allows us to chain\\nmultiple operations on correct results or propagate the original error without\\ndoing anything. Let\'s dissect it one-by-one.\\n\\n`try_from` is a method implemented in `TryFrom` trait, that allows you to convert\\ntypes and either successfully convert them or fail (with a reasonable error). This\\nmethod returns `Result`.\\n\\nWe call `and_then` on that _result_, let\'s have a look at the type signature of\\n`and_then`, IMO it explains more than enough:\\n```rust\\npub fn and_then(self, op: F) -> Result\\nwhere\\n F: FnOnce(T) -> Result\\n```\\n\\nOK\u2026 So it takes the result and a function and returns another result with\\ndifferent value and different error. However we can see that the function, which\\nrepresents an operation on a result, takes just the value, i.e. it doesn\'t care\\nabout any previous error. To make it short:\\n\\n> `and_then` allows us to run an operation, which can fail, on the correct result\\n\\nWe parsed a `y` index and now we try to convert the `x` index with `try_from`\\nagain, but on that result we use `map` rather than `and_then`, why would that be?\\n\\n```rust\\npub fn map(self, op: F) -> Result\\nwhere\\n F: FnOnce(T) -> U\\n```\\n\\nHuh\u2026 `map` performs an operation that **cannot** fail. And finally we use\\n`unwrap_or` which takes the value from result, or in case of an error returns the\\ndefault that we define.\\n\\nHow does this work then? If `y` is negative, the conversion fails and the error\\npropagates all the way to `unwrap_or`, if `y` can be a correct `usize` value, then\\nwe do the same with `x`. If `x` is negative, we propagate the error as with `y`,\\nand if it\'s not, then we check whether it exceeds the higher bounds or not.\\n\\n### Solution\\n\\nRelatively simple, you just need follow the rules and not get too smart, otherwise\\nit will get back at you.\\n\\n## [Day 9: Rope Bridge](https://adventofcode.com/2022/day/9)\\n\\n:::info tl;dr\\n\\nWe get a rope with knots and we want to track how many different positions are\\nvisited with the rope\'s tail.\\n\\n:::\\n\\nBy this day, I have come to a conclusion that current skeleton for each day\\ngenerates a lot of boilerplate. And even though it can be easily copied, it\'s\\njust a waste of space and unnecessary code. Let\'s \u201csimplify\u201d this (on one end\\nwhile creating monster on the other end). I\'ve gone through what we need in the\\npreparations for the AoC. Let\'s sum up our requirements:\\n- parsing\\n- part 1 & 2\\n- running on sample / input\\n- tests\\n\\nParsing and implementation of both parts is code that changes each day and we\\ncannot do anything about it. However running and testing can be simplified!\\n\\nLet\'s introduce and export a new module `solution` that will take care of all of\\nthis. We will start by introducing a trait for each day.\\n```rust\\npub trait Solution {\\n fn parse_input>(pathname: P) -> Input;\\n\\n fn part_1(input: &Input) -> Output;\\n fn part_2(input: &Input) -> Output;\\n}\\n```\\n\\nThis does a lot of work for us already, we have defined a trait and for each day\\nwe will create a structure representing a specific day. That structure will also\\nimplement the `Solution` trait.\\n\\nNow we need to get rid of the boilerplate, we can\'t get rid of the `main` function,\\nbut we can at least move out the functionality.\\n```rust\\nfn run(type_of_input: &str) -> Result<()>\\nwhere\\n Self: Sized,\\n{\\n tracing_subscriber::fmt()\\n .with_env_filter(EnvFilter::from_default_env())\\n .with_target(false)\\n .with_file(true)\\n .with_line_number(true)\\n .without_time()\\n .compact()\\n .init();\\n color_eyre::install()?;\\n\\n let input = Self::parse_input(format!(\\"{}s/{}.txt\\", type_of_input, Self::day()));\\n\\n info!(\\"Part 1: {}\\", Self::part_1(&input));\\n info!(\\"Part 2: {}\\", Self::part_2(&input));\\n\\n Ok(())\\n}\\n\\nfn main() -> Result<()>\\nwhere\\n Self: Sized,\\n{\\n Self::run(\\"input\\")\\n}\\n```\\n\\nThis is all part of the `Solution` trait, which can implement methods while being\\ndependent on what is provided by the implementing types. In this case, we just\\nneed to bound the `Output` type to implement `Display` that is necessary for the\\n`info!` and format string there.\\n\\nNow we can get to first of the nasty things we are going to do\u2026 And it is the\\n`day()` method that you can see being used when constructing path to the input\\nfile. That method will generate a name of the file, e.g. `day01` and we know that\\nwe can _somehow_ deduce it from the structure name, given we name it reasonably.\\n\\n```rust\\nfn day() -> String {\\n let mut day = String::from(type_name::().split(\\"::\\").next().unwrap());\\n day.make_ascii_lowercase();\\n\\n day.to_string()\\n}\\n```\\n\\n:::caution `type_name`\\n\\nThis feature is still experimental and considered to be internal, it is not\\nadvised to use it any production code.\\n\\n:::\\n\\nAnd now we can get to the nastiest stuff :weary: We will **generate** the tests!\\n\\nWe want to be able to generate tests for sample input in a following way:\\n```rust\\ntest_sample!(day_01, Day01, 42, 69);\\n```\\n\\nThere\'s not much we can do, so we will write a macro to generate the tests for us.\\n\\n```rust\\n#[macro_export]\\nmacro_rules! test_sample {\\n ($mod_name:ident, $day_struct:tt, $part_1:expr, $part_2:expr) => {\\n #[cfg(test)]\\n mod $mod_name {\\n use super::*;\\n\\n #[test]\\n fn test_part_1() {\\n let sample =\\n $day_struct::parse_input(&format!(\\"samples/{}.txt\\", $day_struct::day()));\\n assert_eq!($day_struct::part_1(&sample), $part_1);\\n }\\n\\n #[test]\\n fn test_part_2() {\\n let sample =\\n $day_struct::parse_input(&format!(\\"samples/{}.txt\\", $day_struct::day()));\\n assert_eq!($day_struct::part_2(&sample), $part_2);\\n }\\n }\\n };\\n}\\n```\\n\\nWe have used it in a similar way as macros in C/C++, one of the things that we\\ncan use to our advantage is defining \u201ctype\u201d of the parameters for the macro. All\\nparameters have their name prefixed with `$` sign and you can define various \u201cforms\u201d\\nof your macro. Let\'s go through it!\\n\\nWe have following parameters:\\n- `$mod_name` which represents the name for the module with tests, it is typed\\n with `ident` which means that we want a valid identifier to be passed in.\\n- `$day_struct` represents the structure that will be used for tests, it is typed\\n with `tt` which represents a _token tree_, in our case it is a type.\\n- `$part_X` represents the expected output for the `X`th part and is of type `expr`\\n which literally means an _expression_.\\n\\nApart from that we need to use `#[macro_export]` to mark the macro as exported\\nfor usage outside of the module. Now our skeleton looks like:\\n```rust\\nuse aoc_2022::*;\\n\\ntype Input = String;\\ntype Output = String;\\n\\nstruct DayXX;\\nimpl Solution for DayXX {\\n fn parse_input>(pathname: P) -> Input {\\n file_to_string(pathname)\\n }\\n\\n fn part_1(input: &Input) -> Output {\\n todo!()\\n }\\n\\n fn part_2(input: &Input) -> Output {\\n todo!()\\n }\\n}\\n\\nfn main() -> Result<()> {\\n // DayXX::run(\\"sample\\")\\n DayXX::main()\\n}\\n\\n// test_sample!(day_XX, DayXX, , );\\n```\\n\\n### Solution\\n\\nNot much to talk about, it is relatively easy to simulate.\\n\\n## [Day 10: Cathode-Ray Tube](https://adventofcode.com/2022/day/10)\\n\\n:::info tl;dr\\n\\nEmulating basic arithmetic operations on a CPU and drawing on CRT based on the\\nCPU\'s accumulator.\\n\\n:::\\n\\nIn this day I have discovered an issue with my design of the `Solution` trait.\\nAnd the issue is caused by different types of `Output` for the part 1 and part 2.\\n\\nProblem is relatively simple and consists of simulating a CPU, I have approached\\nit in a following way:\\n```rust\\nfn evaluate_instructions(instructions: &[Instruction], mut out: Output) -> Output {\\n instructions\\n .iter()\\n .fold(State::new(), |state, instruction| {\\n state.execute(instruction, &mut out)\\n });\\n\\n out\\n}\\n```\\n\\nWe just take the instructions, we have some state of the CPU and we execute the\\ninstructions one-by-one. Perfect usage of the `fold` (or `reduce` as you may know\\nit from other languages).\\n\\nYou can also see that we have an `Output` type, so the question is how can we fix\\nthat problem. And the answer is very simple and _functional_. Rust allows you to\\nhave an `enumeration` that can _bear_ some other values apart from the type itself.\\n\\n:::tip\\n\\nWe could\'ve seen something like this with the `Result` type that can be\\ndefined as\\n```rust\\nenum Result {\\n Ok(T),\\n Err(E)\\n}\\n```\\n\\n###### What does that mean though?\\n\\nWhen we have an `Ok` value, it has the result itself, and when we get an `Err`\\nvalue, it has the error. This also allows us to handle _results_ in a rather\\npretty way:\\n```rust\\nmatch do_something(x) {\\n Ok(y) => {\\n println!(\\"SUCCESS: {}\\", y);\\n },\\n Err(y) => {\\n eprintln!(\\"ERROR: {}\\", y);\\n }\\n}\\n```\\n\\n:::\\n\\nMy solution has a following outline:\\n```rust\\nfn execute(&self, i: &Instruction, output: &mut Output) -> State {\\n // execute the instruction\\n\\n // collect results if necessary\\n match output {\\n Output::Part1(x) => self.execute_part_1(y, x),\\n Output::Part2(x) => self.execute_part_2(y, x),\\n }\\n\\n // return the obtained state\\n new_state\\n}\\n```\\n\\nYou might think that it\'s a perfectly reasonable thing to do. Yes, **but** notice\\nthat the `match` statement doesn\'t _collect_ the changes in any way and also we\\npass `output` by `&mut`, so it is shared across each _iteration_ of the `fold`.\\n\\nThe dirty and ingenious thing is that `x`s are passed by `&mut` too and therefore\\nthey are directly modified by the helper functions. To sum it up and let it sit\\n\\n> We are **collecting** the result **into** an **enumeration** that is **shared**\\n> across **all** iterations of `fold`.\\n\\n### Solution\\n\\nSimilar to _Day 9_, but there are some technical details that can get you.\\n\\n## [Day 11: Monkey in the Middle](https://adventofcode.com/2022/day/11)\\n\\n:::info tl;dr\\n\\nSimulation of monkeys throwing stuff around and measuring your stress levels\\nwhile your stuff is being passed around.\\n\\n:::\\n\\nI think I decided to use regular expressions here for the first time, cause\\nparsing the input was a pain.\\n\\nAlso I didn\'t expect to implement Euclidean algorithm in Rust\u2026\\n\\n### Solution\\n\\nAgain, we\'re just running a simulation. Though I must admit it was very easy to\\nmake a small technical mistakes that could affect the final results very late.\\n\\n## [Day 12: Hill Climbing Algorithm](https://adventofcode.com/2022/day/12)\\n\\n:::info tl;dr\\n\\nFinding shortest path up the hill and also shortest path down to the ground while\\nalso rolling down the hill\u2026\\n\\n:::\\n\\nAs I have said in the _tl;dr_, we are looking for the shortest path, but the start\\nand goal differ for the part 1 and 2. So I have decided to refactor my solution\\nto a BFS algorithm that takes necessary parameters via functions:\\n```rust\\nfn bfs(\\n graph: &[Vec], start: &Position, has_edge: F, is_target: G\\n) -> Option\\nwhere\\n F: Fn(&[Vec], &Position, &Position) -> bool,\\n G: Fn(&[Vec], &Position) -> bool\\n```\\n\\nWe pass the initial vertex from the caller and everything else is left to the BFS\\nalgorithm, based on the `has_edge` and `is_target` functions.\\n\\nThis was easy! And that is not very usual in Rust once you want to pass around\\nfunctions. :eyes:\\n\\n### Solution\\n\\nLooking for the shortest path\u2026 Must be Dijkstra, right? **Nope!** Half of the\\nReddit got jebaited though. In all fairness, nothing stops you from implementing\\nthe Dijkstra\'s algorithm for finding the shortest path, **but** if you know that\\nall connected vertices are in a unit (actually $d = 1$) distance from each other,\\nthen you know that running Dijkstra is equivalent to running BFS, only with worse\\ntime complexity, because of the priority heap instead of the queue.\\n\\n## [Day 13: Distress Signal](https://adventofcode.com/2022/day/13)\\n\\n:::info tl;dr\\n\\nProcessing packets with structured data from the distress signal.\\n\\n:::\\n\\nYou can implement a lot of traits if you want to. It is _imperative_ to implement\\nordering on the packets. I had a typo, so I also proceeded to implement a `Display`\\ntrait for debugging purposes:\\n```rust\\nimpl Display for Packet {\\n fn fmt(&self, f: &mut std::fmt::Formatter<\'_>) -> std::fmt::Result {\\n match self {\\n Packet::Integer(x) => write!(f, \\"{x}\\"),\\n Packet::List(lst) => write!(f, \\"[{}]\\", lst.iter().map(|p| format!(\\"{p}\\")).join(\\",\\")),\\n }\\n }\\n}\\n```\\n\\n### Solution\\n\\nA lot of technical details\u2026 Parsing is nasty too\u2026\\n\\n## [Day 14: Regolith Reservoir](https://adventofcode.com/2022/day/14)\\n\\n:::info tl;dr\\n\\nLet\'s simulate falling sand grain-by-grain.\\n\\n:::\\n\\nAgain, both parts are relatively similar with minimal changes, so it is a good\\nidea to refactor it a bit. Similar approach to the [BFS above]. Also this is the\\nfirst day where I ran into efficiency issues and had to redo my solution to speed\\nit up just a bit.\\n\\n### Solution\\n\\nTedious.\\n\\n## Post Mortem\\n\\n### Indexing\\n\\nI was asked about the indexing after publishing the blog. And truly it is rather\\ncomplicated topic, especially after releasing `SliceIndex` trait. I couldn\'t\\nleave it be, so I tried to implement the `Index` and `IndexMut` trait.\\n\\n:::note\\n\\nI have also mentioned that the `SliceIndex` trait is `unsafe`, but truth be told,\\nonly _unsafe_ part are the 2 methods that are named `*unchecked*`. Anyways, I will\\nbe implementing the `Index*` traits for now, rather than the `SliceIndex`.\\n\\n:::\\n\\nIt\'s relatively straightforward\u2026\\n\\n```rust\\nimpl Index> for [C]\\nwhere\\n I: Copy + TryInto,\\n >::Error: Debug,\\n C: Index,\\n{\\n type Output = C::Output;\\n\\n fn index(&self, index: Vector2D) -> &Self::Output {\\n let (x, y): (usize, usize) =\\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\\n &self[y][x]\\n }\\n}\\n\\nimpl IndexMut> for [C]\\nwhere\\n I: Copy + TryInto,\\n >::Error: Debug,\\n C: IndexMut,\\n{\\n fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output {\\n let (x, y): (usize, usize) =\\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\\n &mut self[y][x]\\n }\\n}\\n```\\n\\nWe can see a lot of similarities to the implementation of `index` and `index_mut`\\nfunctions. In the end, they are 1:1, just wrapped in the trait that provides a\\nsyntax sugar for `container[idx]`.\\n\\n:::note\\n\\nI have also switched from using the `TryFrom` to `TryInto` trait, since it better\\nmatches what we are using, the `.try_into` rather than `usize::try_from`.\\n\\nAlso implementing `TryFrom` automatically provides you with a `TryInto` trait,\\nsince it is relatively easy to implement. Just compare the following:\\n\\n```rust\\npub trait TryFrom: Sized {\\n type Error;\\n\\n fn try_from(value: T) -> Result;\\n}\\n\\npub trait TryInto: Sized {\\n type Error;\\n\\n fn try_into(self) -> Result;\\n}\\n```\\n\\n:::\\n\\nOK, so we have our trait implemented, we should be able to use `container[index]`,\\nright? Yes\u2026 but actually no :frowning:\\n\\n```\\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\\n --\x3e src/bin/day08.rs:26:18\\n |\\n26 | if trees[pos] > tallest {\\n | ^^^ slice indices are of type `usize` or ranges of `usize`\\n |\\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\\n\\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\\n --\x3e src/bin/day08.rs:30:28\\n |\\n30 | max(tallest, trees[pos])\\n | ^^^ slice indices are of type `usize` or ranges of `usize`\\n |\\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\\n\\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\\n --\x3e src/bin/day08.rs:52:28\\n |\\n52 | let max_height = trees[position];\\n | ^^^^^^^^ slice indices are of type `usize` or ranges of `usize`\\n |\\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\\n```\\n\\nWhy? We have it implemented for the slices (`[C]`), why doesn\'t it work? Well,\\nthe fun part consists of the fact that in other place, where we were using it,\\nwe were passing the `&[Vec]`, but this is coming from a helper functions that\\ntake `&Vec>` instead. And\u2026 we don\'t implement `Index` and `IndexMut` for\\nthose. Just for the slices. :exploding_head: *What are we going to do about it?*\\n\\nWe can either start copy-pasting or be smarter about it\u2026 I choose to be smarter,\\nso let\'s implement a macro! The only difference across the implementations are\\nthe types of the outer containers. Implementation doesn\'t differ **at all**!\\n\\nImplementing the macro can be done in a following way:\\n```rust\\nmacro_rules! generate_indices {\\n ($container:ty) => {\\n impl Index> for $container\\n where\\n I: Copy + TryInto,\\n >::Error: Debug,\\n C: Index,\\n {\\n type Output = C::Output;\\n\\n fn index(&self, index: Vector2D) -> &Self::Output {\\n let (x, y): (usize, usize) =\\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\\n &self[y][x]\\n }\\n }\\n\\n impl IndexMut> for $container\\n where\\n I: Copy + TryInto,\\n >::Error: Debug,\\n C: IndexMut,\\n {\\n fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output {\\n let (x, y): (usize, usize) =\\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\\n &mut self[y][x]\\n }\\n }\\n };\\n}\\n```\\n\\nAnd now we can simply do\\n```rust\\ngenerate_indices!(VecDeque);\\ngenerate_indices!([C]);\\ngenerate_indices!(Vec);\\n// generate_indices!([C; N], const N: usize);\\n```\\n\\nThe last type (I took the inspiration from the implementations of the `Index` and\\n`IndexMut` traits) is a bit problematic, because of the `const N: usize` part,\\nwhich I haven\'t managed to be able to parse. And that\'s how I got rid of the error.\\n\\n:::note\\n\\nIf I were to use 2D-indexing over `[C; N]` slices, I\'d probably just go with the\\ncopy-paste, cause the cost of this \u201cmonstrosity\u201d outweighs the benefits of no DRY.\\n\\n:::\\n\\n#### Cause of the problem\\n\\nThis issue is relatively funny. If you don\'t use any type aliases, just the raw\\ntypes, you\'ll get suggested certain changes by the _clippy_. For example if you\\nconsider the following piece of code\\n```rust\\nfn get_sum(nums: &Vec) -> i32 {\\n nums.iter().sum()\\n}\\n\\nfn main() {\\n let nums = vec![1, 2, 3];\\n println!(\\"Sum: {}\\", get_sum(&nums));\\n}\\n```\\n\\nand you run _clippy_ on it, you will get\\n```\\nChecking playground v0.0.1 (/playground)\\nwarning: writing `&Vec` instead of `&[_]` involves a new object where a slice will do\\n --\x3e src/main.rs:1:18\\n |\\n1 | fn get_sum(nums: &Vec) -> i32 {\\n | ^^^^^^^^^ help: change this to: `&[i32]`\\n |\\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg\\n = note: `#[warn(clippy::ptr_arg)]` on by default\\n\\nwarning: `playground` (bin \\"playground\\") generated 1 warning\\n Finished dev [unoptimized + debuginfo] target(s) in 0.61s\\n```\\n\\nHowever, if you introduce a type alias, such as\\n```rust\\ntype Numbers = Vec;\\n```\\n\\nThen _clippy_ won\'t say anything, cause there is literally nothing to suggest.\\nHowever the outcome is not the same\u2026\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[BFS above]: #day-12-hill-climbing-algorithm"},{"id":"aoc-2022/1st-week","metadata":{"permalink":"/blog/aoc-2022/1st-week","editUrl":"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/01-week-1.md","source":"@site/blog/aoc-2022/01-week-1.md","title":"1st week of Advent of Code \'22 in Rust","description":"Surviving first week in Rust.","date":"2022-12-15T01:15:00.000Z","formattedDate":"December 15, 2022","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":12.4,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"1st week of Advent of Code \'22 in Rust","description":"Surviving first week in Rust.","date":"2022-12-15T01:15","slug":"aoc-2022/1st-week","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"2nd week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/2nd-week"},"nextItem":{"title":"Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/intro"}},"content":"Let\'s go through the first week of [_Advent of Code_] in Rust.\\n\\n\x3c!--truncate--\x3e\\n\\n:::note\\n\\nIf you wish to have a look at the solutions, you can follow them on my [GitLab].\\nMore specifically in the [`/src/bin/`].\\n\\n:::\\n\\nI will try to summarize my experience with using Rust for the AoC. Trying it out\\nages ago, I believe it will be _pain and suffering_, but we will see. For each\\nday I will also try to give a tl;dr of the problem, so that you can better imagine\\nthe relation to my woes or :+1: moments.\\n\\n## [Day 1: Calorie Counting](https://adventofcode.com/2022/day/1)\\n\\n:::info tl;dr\\n\\nAs the name suggests, we get the calories of the food contained in the elves\\nbackpacks and we want to choose the elf that has the most food ;)\\n\\n:::\\n\\n> Wakey wakey!\\n\\nProgramming in Rust at 6am definitely hits. I\'ve also forgotten to mention how I\\nhandle samples. With each puzzle you usually get a sample input and expected\\noutput. You can use them to verify that your solution works, or usually doesn\'t.\\n\\nAt first I\'ve decided to put asserts into my `main`, something like\\n```rust\\nassert_eq!(part_1(&sample), 24000);\\ninfo!(\\"Part 1: {}\\", part_1(&input));\\n\\nassert_eq!(part_2(&sample), 45000);\\ninfo!(\\"Part 2: {}\\", part_2(&input));\\n```\\n\\nHowever, once you get further, the sample input may take some time to run itself.\\nSo in the end, I have decided to turn them into unit tests:\\n```rust\\n#[cfg(test)]\\nmod tests {\\n use super::*;\\n\\n #[test]\\n fn test_part_1() {\\n let sample = parse_input(\\"samples/day01.txt\\");\\n assert_eq!(part_1(&sample), 24000);\\n }\\n\\n #[test]\\n fn test_part_2() {\\n let sample = parse_input(\\"samples/day01.txt\\");\\n assert_eq!(part_2(&sample), 45000);\\n }\\n}\\n```\\n\\nAnd later on I have noticed, it\'s hard to tell the difference between the days,\\nso I further renamed the `mod` from generic `tests` to reflect the days.\\n\\nAlso after finishing the first day puzzle, I have installed an [`sccache`] to\\ncache the builds, so that the build time is lower, cause it was kinda unbearable.\\n\\n### Solution\\n\\nWell, it\'s a pretty simple problem. You just take the input, sum the calories and\\nfind the biggest one. However, if we try to generalize to more than the biggest\\none, the fun appears. We have few options:\\n\\n- keep all the calories, sort them, take what we need\\n- keep all the calories and use max heap\\n- use min heap and maintain at most N calories that we need\\n\\n## [Day 2: Rock Paper Scissors](https://adventofcode.com/2022/day/2)\\n\\n:::info tl;dr\\n\\nYou want to know what score did you achieve while playing _Rock Paper Scissors_.\\nAnd then you want to be strategic about it.\\n\\n:::\\n\\nApart from the technical details of the puzzle, it went relatively smooth.\\n\\n### Solution\\n\\nI took relatively na\xefve approach and then tried to simplify it.\\n\\n## [Day 3: Rucksack Reorganization](https://adventofcode.com/2022/day/3)\\n\\n:::info tl;dr\\n\\nLet\'s go reorganize elves\' backpacks! Each backpacks has 2 compartments and you\\nwant to find the common item among those compartments. Each of them has priority,\\nyou care only about the sum.\\n\\n:::\\n\\nThis is the day where I started to fight the compiler and neither of us decided\\nto give up. Let\'s dive into it \\\\o/\\n\\n:::tip Fun fact\\n\\nFighting the compiler took me 30 minutes.\\n\\n:::\\n\\nWe need to find a common item among 2 collections, that\'s an easy task, right?\\nWe can construct 2 sets and find an intersection:\\n```rust\\nlet top: HashSet = [1, 2, 3].iter().collect();\\nlet bottom: HashSet = [3, 4, 5].iter().collect();\\n```\\n\\nNow, the first issue that we encounter is caused by the fact that we are using\\na slice (the `[\u2026]`), iterator of that returns **references** to the numbers.\\nAnd we get immediately yelled at by the compiler, because the numbers are discarded\\nafter running the `.collect`. To fix this, we can use `.into_iter`:\\n```rust\\nlet top: HashSet = [1, 2, 3].into_iter().collect();\\nlet bottom: HashSet = [3, 4, 5].into_iter().collect();\\n```\\n\\nThis way the numbers will get copied instead of referenced. OK, let\'s find the\\nintersection of those 2 collections:\\n```rust\\nprintln!(\\"Common elements: {:?}\\", top.intersection(&bottom));\\n```\\n```\\nCommon elements: [3]\\n```\\n\\n:::caution\\n\\nNotice that we need to do `&bottom`. It explicitly specifies that `.intersection`\\n**borrows** the `bottom`, i.e. takes an immutable reference to it.\\n\\n:::\\n\\nThat\'s what we want, right? Looks like it! \\\\o/\\n\\nNext part wants us to find the common element among all of the backpacks. OK, so\\nthat should be fairly easy, we have an intersection and we want to find intersection\\nover all of them.\\n\\nLet\'s have a look at the type of the `.intersection`\\n```rust\\npub fn intersection<\'a>(\\n\xa0\xa0\xa0\xa0&\'a self,\\n\xa0\xa0\xa0\xa0other: &\'a HashSet\\n) -> Intersection<\'a, T, S>\\n```\\n\\nOK\u2026 Huh\u2026 But we have an example there!\\n```rust\\nlet intersection: HashSet<_> = a.intersection(&b).collect();\\n```\\n\\nCool, that\'s all we need.\\n```rust\\nlet top: HashSet = [1, 2, 3, 4].into_iter().collect();\\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\\n\\nlet intersection: HashSet<_> = top.intersection(&bottom).collect();\\nprintln!(\\"Intersection: {:?}\\", intersection);\\n```\\n```\\nIntersection: {3, 4}\\n```\\n\\nCool, so let\'s do the intersection with the `top_2`:\\n```rust\\nlet top: HashSet = [1, 2, 3, 4].into_iter().collect();\\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\\n\\nlet intersection: HashSet<_> = top.intersection(&bottom).collect();\\nlet intersection: HashSet<_> = intersection.intersection(&top_2).collect();\\nprintln!(\\"Intersection: {:?}\\", intersection);\\n```\\n\\nAnd we get yelled at by the compiler:\\n```\\nerror[E0308]: mismatched types\\n --\x3e src/main.rs:10:58\\n |\\n10 | let intersection: HashSet<_> = intersection.intersection(&top_2).collect();\\n | ------------ ^^^^^^ expected `&i32`, found `i32`\\n | |\\n | arguments to this function are incorrect\\n |\\n = note: expected reference `&HashSet<&i32>`\\n found reference `&HashSet`\\n```\\n\\n/o\\\\ What the hell is going on here? Well, the funny thing is, that this operation\\ndoesn\'t return the elements themselves, but the references to them and when we pass\\nthe third set, it has just the values themselves, without any references.\\n\\n:::tip\\n\\nIt may seem as a very weird decision, but in fact it makes some sense\u2026 It allows\\nyou to do intersection of items that may not be possible to copy. Overall this is\\na \u201ctax\u201d for having a borrow checker ~~drilling your ass~~ having your back and\\nmaking sure you\'re not doing something naughty that may cause an **undefined**\\n**behavior**.\\n\\n:::\\n\\nTo resolve this we need to get an iterator that **clones** the elements:\\n```rust\\nlet top: HashSet = [1, 2, 3, 4].into_iter().collect();\\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\\n\\nlet intersection: HashSet<_> = top.intersection(&bottom).cloned().collect();\\nlet intersection: HashSet<_> = intersection.intersection(&top_2).cloned().collect();\\nlet intersection: HashSet<_> = intersection.intersection(&bottom_2).cloned().collect();\\nprintln!(\\"Intersection: {:?}\\", intersection);\\n```\\n```\\nIntersection: {4}\\n```\\n\\n### Solution\\n\\nThe approach is pretty simple, if you omit the _1on1 with the compiler_. You just\\nhave some fun with the set operations :)\\n\\n## [Day 4: Camp Cleanup](https://adventofcode.com/2022/day/4)\\n\\n:::info tl;dr\\n\\nElves are cleaning up the camp and they got overlapping sections to clean up.\\nFind how many overlap and can take the day off.\\n\\n:::\\n\\n[`RangeInclusive`] is your friend not an enemy :)\\n\\n### Solution\\n\\nRelatively easy, you just need to parse the input and know what you want. Rust\'s\\n`RangeInclusive` type helped a lot, cause it took care of all abstractions.\\n\\n## [Day 5: Supply Stacks](https://adventofcode.com/2022/day/5)\\n\\n:::info tl;dr\\n\\nLet\'s play with stacks of crates.\\n\\n:::\\n\\nVery easy problem with very annoying input. You can judge yourself:\\n```\\n [D] \\n[N] [C] \\n[Z] [M] [P]\\n 1 2 3 \\n\\nmove 1 from 2 to 1\\nmove 3 from 1 to 3\\nmove 2 from 2 to 1\\nmove 1 from 1 to 2\\n```\\n\\nGood luck transforming that into something reasonable :)\\n\\n\\n:::tip Fun fact\\n\\nTook me 40 minutes to parse this reasonably, including fighting the compiler.\\n\\n:::\\n\\n### Solution\\n\\nFor the initial solution I went with a manual solution (as in _I have done all_\\n_the work_. Later on I have decided to explore the `std` and interface of the\\n`std::vec::Vec` and found [`split_off`] which takes an index and splits (duh)\\nthe vector:\\n```rust\\nlet mut vec = vec![1, 2, 3];\\nlet vec2 = vec.split_off(1);\\nassert_eq!(vec, [1]);\\nassert_eq!(vec2, [2, 3]);\\n```\\n\\nThis helped me simplify my solution a lot and also get rid of some _edge cases_.\\n\\n## [Day 6: Tuning Trouble](https://adventofcode.com/2022/day/6)\\n\\n:::info tl;dr\\n\\nFinding start of the message in a very weird protocol. Start of the message is\\ndenoted by $N$ unique consecutive characters.\\n\\n:::\\n\\n### Solution\\n\\nA lot of different approaches, knowing that we are dealing with input consisting\\nsolely of ASCII letters, I bit the bullet and went with sliding window and\\nconstructing sets from that window, checking if the set is as big as the window.\\n\\nOne possible optimization could consist of keeping a bit-vector (i.e. `usize`\\nvariable) of encountered characters and updating it as we go. However this has\\na different issue and that is removal of the characters from the left side of the\\nwindow. We don\'t know if the same character is not included later on.\\n\\nOther option is to do similar thing, but keeping the frequencies of the letters,\\nand again knowing we have only ASCII letters we can optimize by having a vector\\nof 26 elements that keeps count for each lowercase letter.\\n\\n## [Day 7: No Space Left On Device](https://adventofcode.com/2022/day/7)\\n\\n:::info tl;dr\\n\\nLet\'s simulate [`du`] to get some stats about our file system and then pinpoint\\ndirectories that take a lot of space and should be deleted.\\n\\n:::\\n\\n> I was waiting for this moment, and yet it got me!\\n> *imagine me swearing for hours*\\n\\n### Solution\\n\\nWe need to \u201c_build_\u201d a file system from the input that is given in a following form:\\n```\\n$ cd /\\n$ ls\\ndir a\\n14848514 b.txt\\n8504156 c.dat\\ndir d\\n$ cd a\\n$ ls\\ndir e\\n29116 f\\n2557 g\\n62596 h.lst\\n$ cd e\\n$ ls\\n584 i\\n$ cd ..\\n$ cd ..\\n$ cd d\\n$ ls\\n4060174 j\\n8033020 d.log\\n5626152 d.ext\\n7214296 k\\n```\\n\\nThere are few ways in which you can achieve this and also you can assume some\\npreconditions, but why would we do that, right? :)\\n\\nYou can \u201cslap\u201d this in either [`HashMap`] or [`BTreeMap`] and call it a day.\\nAnd that would be boring\u2026\\n\\n:::tip\\n\\n`BTreeMap` is quite fitting for this, don\'t you think?\\n\\n:::\\n\\nI always wanted to try allocation on heap in Rust, so I chose to implement a tree.\\nI fought with the `Box` for some time and was losing\u2026\\n\\nThen I looked up some implementations of trees or linked lists and decided to try\\n`Rc>`. And I got my _ass whopped_ by the compiler once again. /o\\\\\\n\\n:::tip\\n\\n`Box` represents a dynamically allocated memory on heap. It is a single pointer,\\nyou can imagine this as `std::unique_ptr` in C++.\\n\\n`Rc` represents a dynamically allocated memory on heap. On top of that it is\\n_reference counted_ (that\'s what the `Rc` stands for). You can imagine this as\\n`std::shared_ptr` in C++.\\n\\nNow the fun stuff. Neither of them lets you **mutate** the contents of the memory.\\n\\n`Cell` allows you to mutate the memory. Can be used reasonably with types that\\ncan be copied, because the memory safety is guaranteed by copying the contents\\nwhen there is more than one **mutable** reference to the memory.\\n\\n`RefCell` is similar to the `Cell`, but the borrowing rules (how many mutable\\nreferences are present) are checked dynamically.\\n\\nSo in the end, if you want something like `std::shared_ptr` in Rust, you want\\nto have `Rc>`.\\n\\n:::\\n\\nSo, how are we going to represent the file system then? We will use an enumeration,\\nhehe, which is an algebraic data type that can store some stuff in itself :weary:\\n```rust\\ntype FileHandle = Rc>;\\n\\n#[derive(Debug)]\\nenum AocFile {\\n File(usize),\\n Directory(BTreeMap),\\n}\\n```\\n\\nLet\'s go over it! `FileHandle` represents dynamically allocated `AocFile`, not\\nmuch to discuss. What does the `#[derive(Debug)]` do though? It lets us to print\\nout the value of that enumeration, it\'s derived, so it\'s not as good as if we had\\nimplemented it ourselves, but it\'s good enough for debugging, hence the name.\\n\\nNow to the fun part! `AocFile` value can be represented in two ways:\\n- `File(usize)`, e.g. `AocFile::File(123)` and we can pattern match it, if we\\n need to\\n- `Directory(BTreeMap)` will represent the directory and will\\n contain map matching the name of the files (or directories) within to their\\n respective file handles\\n\\nI will omit the details about constructing this file system, cause there are a lot\\nof technicalities introduced by the nature of the input. However if you are\\ninterested, you can have a look at my solution.\\n\\nWe need to find small enough directories and also find the smallest directory that\\nwill free enough space. Now the question is, how could we do that. And there are\\nmultiple ways I will describe.\\n\\nI have chosen to implement [_tree catamorphism_] :weary:. It is basically a fold\\nover a tree data structure. We descent down into the leaves and propagate computed\\nresults all the way to the root. You can also notice that this approach is very\\nsimilar to _dynamic programming_, we find overlapping sections of the computation\\nand try to minimize the additional work (in this case: we need to know sizes of\\nour descendants, but we have already been there).\\n\\nAnother approach that has been suggested to me few days later is running DFS on\\nthe graph. And, funnily enough, we would still need to combine what we found in\\nthe branches where we descent. So in the end, it would work very similarly to my\\nsolution.\\n\\nOne of the more exotic options would be precomputing the required information at\\nthe same time as parsing. That could be done by adding additional fields to the\\nnodes which would allow storing such information and updating it as we construct\\nthe file system.\\n\\n## Post Mortem\\n\\nThings that have been brought up in the discussion later on.\\n\\n### `Rc` vs `Rc>`\\n\\nIt has been brought up that I have a contradicting statement regarding the\\ndynamically allocated memory. Specifically:\\n\\n- You can imagine `Rc` as an `std::shared_ptr` (in C++)\\n- When you want an equivalent of `std::shared_ptr`, you want to use\\n `Rc>`\\n\\nNow, in Rust it is a bit more complicated, because the type that represents the\\n\u201cshared pointer\u201d is `Rc`. What `RefCell` does is making sure that there is\\nonly one \u201cowner\u201d of a mutable reference at a time (and dynamically, as opposed\\nto the `Cell`).\\n\\nTherefore to be precise and correct about the equivalents of `std::shared_ptr`\\nin Rust, we can say that\\n\\n- `Rc` is an equivalent of a `const std::shared_ptr`,\\n- and `Rc>` is an equivalent of a `std::shared_ptr`.\\n\\nYou can easily see that they only differ in the mutability. (And even that is not\\nas simple as it seems, because there is also `Cell`)\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[GitLab]: https://gitlab.com/mfocko/advent-of-code-2022\\n[`/src/bin/`]: https://gitlab.com/mfocko/advent-of-code-2022/-/tree/main/src/bin\\n[`sccache`]: https://github.com/mozilla/sccache\\n[`RangeInclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html\\n[`split_off`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.split_off\\n[`du`]: https://www.man7.org/linux/man-pages/man1/du.1.html\\n[`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html\\n[`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html\\n[_tree catamorphism_]: https://en.wikipedia.org/wiki/Catamorphism#Tree_fold"},{"id":"aoc-2022/intro","metadata":{"permalink":"/blog/aoc-2022/intro","editUrl":"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/00-intro.md","source":"@site/blog/aoc-2022/00-intro.md","title":"Advent of Code \'22 in Rust","description":"Preparing for Advent of Code \'22.","date":"2022-12-14T21:45:00.000Z","formattedDate":"December 14, 2022","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":8.665,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"Advent of Code \'22 in Rust","description":"Preparing for Advent of Code \'22.","date":"2022-12-14T21:45","slug":"aoc-2022/intro","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"1st week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/1st-week"}},"content":"Let\'s talk about the preparations for this year\'s [_Advent of Code_].\\n\\n\x3c!--truncate--\x3e\\n\\n## Choosing a language\\n\\nWhen choosing a language for AoC, you usually want a language that gives you a\\nquick feedback which allows you to iterate quickly to the solution of the puzzle.\\nOne of the most common choices is Python, many people also use JavaScript or Ruby.\\n\\nGiven the competitive nature of the AoC and popularity among competitive programming,\\nC++ might be also a very good choice. Only if you are familiar with it, I guess\u2026\\n\\nIf you want a challenge, you might also choose to rotate the languages each day.\\nThough I prefer to use only one language.\\n\\nFor this year I have been deciding between _Rust_, _C++_ and _Pascal_ or _Ada_.\\n\\nI have tried Rust last year and have survived with it for 3 days and then gave\\nup and switched to _Kotlin_, which was pretty good given it is \u201cJava undercover\u201d.\\nI pretty much like the ideas behind Rust, I am not sure about the whole cult and\\nimplementation of those ideas though. After some years with C/C++, I would say\\nthat Rust feels _too safe_ for my taste and tries to \u201c_punish me_\u201d even for the\\nmost trivial things.\\n\\nC++ is a very robust, but also comes with a wide variety of options providing you\\nthe ability to shoot yourself in the leg. I have tried to solve few days of previous\\nAdvent of Code events, it was _relatively easy_ to solve the problems in C++, given\\nthat I do not admit writing my own iterator for `enumerate`\u2026\\n\\nPascal or Ada were meme choices :) Ada is heavily inspired by Pascal and has a\\npretty nice standard library that offers enough to be able to quickly solve some\\nproblems in it. However the toolkit is questionable :/\\n\\n## Choosing libraries\\n\\n## Preparations for Rust\\n\\nAll of the sources, later on including solutions, can be found at my\\n[GitLab].\\n\\n### Toolkit\\n\\nSince we are using Rust, we are going to use a [Cargo] and more than likely VSCode\\nwith [`rust-analyzer`]. Because of my choice of libraries, we will also introduce\\na `.envrc` file that can be used by [`direnv`], which allows you to set specific\\nenvironment variables when you enter a directory. In our case, we will use\\n```bash\\n# to show nice backtrace when using the color-eyre\\nexport RUST_BACKTRACE=1\\n\\n# to catch logs generated by tracing\\nexport RUST_LOG=trace\\n```\\n\\nAnd for the one of the most obnoxious things ever, we will use a script to download\\nthe inputs instead of \u201c_clicking, opening and copying to a file_\u201d[^1]. There is\\nno need to be _fancy_, so we will adjust Python script by Martin[^2].\\n```py\\n#!/usr/bin/env python3\\n\\nimport datetime\\nimport yaml\\nimport requests\\nimport sys\\n\\n\\ndef load_config():\\n with open(\\"env.yaml\\", \\"r\\") as f:\\n js = yaml.load(f, Loader=yaml.Loader)\\n return js[\\"session\\"], js[\\"year\\"]\\n\\n\\ndef get_input(session, year, day):\\n return requests.get(\\n f\\"https://adventofcode.com/{year}/day/{day}/input\\",\\n cookies={\\"session\\": session},\\n headers={\\n \\"User-Agent\\": \\"{repo} by {mail}\\".format(\\n repo=\\"gitlab.com/mfocko/advent-of-code-2022\\",\\n mail=\\"me@mfocko.xyz\\",\\n )\\n },\\n ).content.decode(\\"utf-8\\")\\n\\n\\ndef main():\\n day = datetime.datetime.now().day\\n if len(sys.argv) == 2:\\n day = sys.argv[1]\\n\\n session, year = load_config()\\n problem_input = get_input(session, year, day)\\n\\n with open(f\\"./inputs/day{day:>02}.txt\\", \\"w\\") as f:\\n f.write(problem_input)\\n\\n\\nif __name__ == \\"__main__\\":\\n main()\\n```\\n\\nIf the script is called without any arguments, it will deduce the day from the\\nsystem, so we do not need to change the day every morning. It also requires a\\nconfiguration file:\\n```yaml\\n# env.yaml\\nsession: \u2039your session cookie\u203a\\nyear: 2022\\n```\\n\\n### Libraries\\n\\nLooking at the list of the libraries, I have chosen \u201ca lot\u201d of them. Let\'s walk\\nthrough each of them.\\n\\n[`tracing`] and [`tracing-subscriber`] are the crates that can be used for tracing\\nand logging of your Rust programs, there are also other crates that can help you\\nwith providing backtrace to the Sentry in case you have deployed your application\\nsomewhere and you want to watch over it. In our use case we will just utilize the\\nmacros for debugging in the terminal.\\n\\n[`thiserror`], [`anyhow`] and [`color-eyre`] are used for error reporting.\\n`thiserror` is a very good choice for libraries, cause it extends the `Error`\\nfrom the `std` and allows you to create more convenient error types. Next is\\n`anyhow` which kinda builds on top of the `thiserror` and provides you with simpler\\nerror handling in binaries[^3]. And finally we have `color-eyre` which, as I found\\nout later, is a colorful (_wink wink_) extension of `eyre` which is fork of `anyhow`\\nwhile supporting customized reports.\\n\\nIn the end I have decided to remove `thiserror` and `anyhow`, since first one is\\nsuitable for libraries and the latter was basically fully replaced by `{color-,}eyre`.\\n\\n[`regex`] and [`lazy_static`] are a very good and also, I hope, self-explanatory\\ncombination. `lazy_static` allows you to have static variables that must be initialized\\nduring runtime.\\n\\n[`itertools`] provides some nice extensions to the iterators from the `std`.\\n\\n### My own \u201clibrary\u201d\\n\\nWhen creating the crate for this year\'s Advent of Code, I have chosen a library\\ntype. Even though standard library is huge, some things might not be included and\\nalso we can follow _KISS_. I have 2 modules that my \u201clibrary\u201d exports, one for\\nparsing and one for 2D vector (that gets used quite often during Advent of Code).\\n\\nKey part is, of course, processing the input and my library exports following\\nfunctions that get used a lot:\\n```rust\\n/// Reads file to the string.\\npub fn file_to_string>(pathname: P) -> String;\\n\\n/// Reads file and returns it as a vector of characters.\\npub fn file_to_chars>(pathname: P) -> Vec;\\n\\n/// Reads file and returns a vector of parsed structures. Expects each structure\\n/// on its own line in the file. And `T` needs to implement `FromStr` trait.\\npub fn file_to_structs, T: FromStr>(pathname: P) -> Vec\\nwhere\\n ::Err: Debug;\\n\\n/// Converts iterator over strings to a vector of parsed structures. `T` needs\\n/// to implement `FromStr` trait and its error must derive `Debug` trait.\\npub fn strings_to_structs(\\n iter: impl Iterator\\n) -> Vec\\nwhere\\n ::Err: std::fmt::Debug,\\n U: Deref;\\n\\n/// Reads file and returns it as a vector of its lines.\\npub fn file_to_lines>(pathname: P) -> Vec;\\n```\\n\\nAs for the vector, I went with a rather simple implementation that allows only\\naddition of the vectors for now and accessing the elements via functions `x()`\\nand `y()`. Also the vector is generic, so we can use it with any numeric type we\\nneed.\\n\\n### Skeleton\\n\\nWe can also prepare a template to quickly bootstrap each of the days. We know\\nthat each puzzle has 2 parts, which means that we can start with 2 functions that\\nwill solve them.\\n```rust\\nfn part1(input: &Input) -> Output {\\n todo!()\\n}\\n\\nfn part2(input: &Input) -> Output {\\n todo!()\\n}\\n```\\n\\nBoth functions take reference to the input and return some output (in majority\\nof puzzles, it is the same type). `todo!()` can be used as a nice placeholder,\\nit also causes a panic when reached and we could also provide some string with\\nan explanation, e.g. `todo!(\\"part 1\\")`. We have not given functions a specific\\ntype and to avoid as much copy-paste as possible, we will introduce type aliases.\\n```rust\\ntype Input = String;\\ntype Output = i32;\\n```\\n\\n:::tip\\n\\nThis allows us to quickly adjust the types only in one place without the need to\\ndo _regex-replace_ or replace them manually.\\n\\n:::\\n\\nFor each day we get a personalized input that is provided as a text file. Almost\\nall the time, we would like to get some structured type out of that input, and\\ntherefore it makes sense to introduce a new function that will provide the parsing\\nof the input.\\n```rust\\nfn parse_input(path: &str) -> Input {\\n todo!()\\n}\\n```\\n\\nThis \u201cparser\u201d will take a path to the file, just in case we would like to run the\\nsample instead of input.\\n\\nOK, so now we can write a `main` function that will take all of the pieces and\\nrun them.\\n```rust\\nfn main() {\\n let input = parse_input(\\"inputs/dayXX.txt\\");\\n\\n println!(\\"Part 1: {}\\", part_1(&input));\\n println!(\\"Part 2: {}\\", part_2(&input));\\n}\\n```\\n\\nThis would definitely do :) But we have installed a few libraries and we want to\\nuse them. In this part we are going to utilize _[`tracing`]_ (for tracing, duh\u2026)\\nand _[`color-eyre`]_ (for better error reporting, e.g. from parsing).\\n```rust\\nfn main() -> Result<()> {\\n tracing_subscriber::fmt()\\n .with_env_filter(EnvFilter::from_default_env())\\n .with_target(false)\\n .with_file(true)\\n .with_line_number(true)\\n .without_time()\\n .compact()\\n .init();\\n color_eyre::install()?;\\n\\n let input = parse_input(\\"inputs/dayXX.txt\\");\\n\\n info!(\\"Part 1: {}\\", part_1(&input));\\n info!(\\"Part 2: {}\\", part_2(&input));\\n\\n Ok(())\\n}\\n```\\n\\nThe first statement will set up tracing and configure it to print out the logs to\\nterminal, based on the environment variable. We also change the formatting a bit,\\nsince we do not need all the _fancy_ features of the logger. Pure initialization\\nwould get us logs like this:\\n```\\n2022-12-11T19:53:19.975343Z INFO day01: Part 1: 0\\n```\\n\\nHowever after running that command, we will get the following:\\n```\\n INFO src/bin/day01.rs:35: Part 1: 0\\n```\\n\\nAnd the `color_eyre::install()?` is quite straightforward. We just initialize the\\nerror reporting by _color eyre_.\\n\\n:::caution\\n\\nNotice that we had to add `Ok(())` to the end of the function and adjust the\\nreturn type of the `main` to `Result<()>`. It is caused by the _color eyre_ that\\ncan be installed only once and therefore it can fail, that is how we got the `?`\\nat the end of the `::install` which _unwraps_ the **\xbbresult\xab** of the installation.\\n\\n:::\\n\\nOverall we will get to a template like this:\\n```rust\\nuse aoc_2022::*;\\n\\nuse color_eyre::eyre::Result;\\nuse tracing::info;\\nuse tracing_subscriber::EnvFilter;\\n\\ntype Input = String;\\ntype Output = i32;\\n\\nfn parse_input(path: &str) -> Input {\\n todo!()\\n}\\n\\nfn part1(input: &Input) -> Output {\\n todo!()\\n}\\n\\nfn part2(input: &Input) -> Output {\\n todo!()\\n}\\n\\nfn main() -> Result<()> {\\n tracing_subscriber::fmt()\\n .with_env_filter(EnvFilter::from_default_env())\\n .with_target(false)\\n .with_file(true)\\n .with_line_number(true)\\n .without_time()\\n .compact()\\n .init();\\n color_eyre::install()?;\\n\\n let input = parse_input(\\"inputs/dayXX.txt\\");\\n\\n info!(\\"Part 1: {}\\", part_1(&input));\\n info!(\\"Part 2: {}\\", part_2(&input));\\n\\n Ok(())\\n}\\n```\\n\\n[^1]: Copy-pasting might be a relaxing thing to do, but you can also discover\\nnasty stuff about your PC. See [this Reddit post and the comment].\\n[^2]: [GitHub profile](https://github.com/martinjonas)\\n[^3]: Even though you can use it even for libraries, but handling errors from\\nlibraries using `anyhow` is nasty\u2026 You will be the stinky one ;)\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[GitLab]: https://gitlab.com/mfocko/advent-of-code-2022\\n[Cargo]: https://doc.rust-lang.org/cargo/\\n[`rust-analyzer`]: https://rust-analyzer.github.io/\\n[`direnv`]: https://direnv.net/\\n[`tracing`]: https://crates.io/crates/tracing\\n[`tracing-subscriber`]: https://crates.io/crates/tracing-subscriber\\n[`thiserror`]: https://crates.io/crates/thiserror\\n[`anyhow`]: https://crates.io/crates/anyhow\\n[`color-eyre`]: https://crates.io/crates/color-eyre\\n[`regex`]: https://crates.io/crates/regex\\n[`lazy_static`]: https://crates.io/crates/lazy_static\\n[`itertools`]: https://crates.io/crates/itertools\\n[this Reddit post and the comment]: https://www.reddit.com/r/adventofcode/comments/zb98pn/comment/iyq0ono"}]}')}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[866],{4612:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"/2023/08/02/copr","metadata":{"permalink":"/blog/2023/08/02/copr","editUrl":"https://github.com/mfocko/blog/tree/main/blog/2023-08-02-copr.md","source":"@site/blog/2023-08-02-copr.md","title":"How can Copr help with broken dependencies","description":"Copr comes to save you when maintainer doesn\'t care.","date":"2023-08-02T00:00:00.000Z","formattedDate":"August 2, 2023","tags":[{"label":"\ud83c\udfed","permalink":"/blog/tags/\ud83c\udfed"},{"label":"red-hat","permalink":"/blog/tags/red-hat"},{"label":"copr","permalink":"/blog/tags/copr"},{"label":"admin","permalink":"/blog/tags/admin"},{"label":"vps","permalink":"/blog/tags/vps"}],"readingTime":3.44,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. your opinionated admin","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"How can Copr help with broken dependencies","description":"Copr comes to save you when maintainer doesn\'t care.","date":"2023-08-02T00:00:00.000Z","authors":[{"key":"mf","title":"a.k.a. your opinionated admin"}],"tags":["\ud83c\udfed","red-hat","copr","admin","vps"]},"nextItem":{"title":"4th week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/4th-week"}},"content":"When you decide to run Fedora on your VPS, you might get screwed over by using\\nrandom repositories\u2026\\n\\n\x3c!--truncate--\x3e\\n\\nWhen I \u201creserved\u201d my VPS[^1] back in June \'20, I slapped Fedora on it without\\nthinking. I bet 99% of people would say that I\'m crazy for doing such thing[^2],\\n**BUT** I\'ve been using Fedora on my PCs for some time already and it felt very\\nstable and natural to just use, even for VPS.\\n\\nOne of the first things I\'ve done was setting up a mail server. You may guess\\nwhat\'s the fun part about having a mail server\u2026 Yes, it\'s all the spam you\\nreceive and only then you realize how much \u201ccrap\u201d gets filtered on free mail\\nservices. To battle this problem I chose to use\\n[rspamd](https://github.com/rspamd/rspamd) that had CentOS support, but someone\\nhad a [Copr](https://copr.fedorainfracloud.org/) repository that I used to\\ninstall it.\\n\\n## How does Copr repositories work?\\n\\nIf you have ever used Ubuntu, you might be familiar with the concept since it is\\nvery close to [PPAs](https://help.ubuntu.com/community/PPA).\\n\\ntl;dr of the whole process consists of\\n1. enabling the Copr repository, and\\n2. installing the desired package.\\n\\nSo in shell you would do\\n```\\n# dnf copr enable \u2039copr-repository\u203a\\n# dnf install \u2039package-from-the-repository\u203a\\n```\\n\\nAnd\u2026 that\'s it! Nothing else needed! Simple, right? And literally same process\\nas you would do for the PPA.\\n\\n:::tip AUR\\n\\nOn the other hand, if you are familiar with the archLinux, you definitely know\\nAUR and what it can do for you. Copr repository is pretty similar, but the\\npackages are prebuilt in Copr and Copr repositories can carry the required\\ndependencies for said packages, which simplifies the distribution, and can even\\nhelp with installing singular packages (when you just need the dependency, not\\neverything).\\n\\n:::\\n\\n## My issue\\n\\nNow you might wonder how would I use it on my VPS. It\'s rather simple, once in\\n6 months a new Fedora release comes out. And you need to upgrade to newer\\nrelease\u2026 You don\'t need to do it right away and for such setup it probably isn\'t\\neven recommended.\\n\\n:::tip\\n\\nFedora releases are supported for a year, i.e. they live 6 months till the next\\nrelease and then another 6 months till another release.\\n\\nSome people prefer to run one version \u201cbehind\u201d. If you ever decide to run it on\\nyour home server or in a similar setup, it might be a pretty good idea to\\nfollow. I\'m using the \u201clatest greatest\u201d, cause why not :smile:\\n\\nOne way or another, you still need to bump the release every six months, unless\\nyou\'d bump 2 releases at once every year, which would be a decision, since, at\\nleast I, cannot see any benefits in it\u2026 You don\'t go for \u201cstability\u201d, cause once\\na year you switch to the latest release and then, before you bump, you use one\\nyear old software, so you\'re not even using the latest.\\n\\n:::\\n\\nFast-forward 2 years in the future, new Fedora release came out (October \'22)\\nand I was doing an upgrade. Dependencies of the rspamd have been updated and\\nrspamd builds in Copr have failed and no one fixed it. Cool, so now I can\\nupgrade, but can either ignore the dependencies or uninstall the rspamd\u2026\\n\\n## How can Copr help?\\n\\nI have managed to find\\n[specfile](https://github.com/rspamd/rspamd/blob/master/rpm/rspamd.spec) for the\\nrspamd package that they use for CentOS. There were some files apart from the\\nspecfile, so I had to make an SRPM locally and then\u2026 I just uploaded the SRPM\\nto the Copr to\\n[build](https://copr.fedorainfracloud.org/coprs/mfocko/rspamd/build/5046567/)\\nan RPM.\\n\\nI have switched the previous Copr repository for rspamd with my own and happily\\nproceeded with the upgrade.\\n\\n## Conclusion\\n\\nCopr is heavily used for testing builds on the upstream with\\n[Packit](https://packit.dev). However, as you can see, it is possible to use it\\n**very well** for packaging your own stuff and avoiding issues (such as the one\\nI have described above), if need be.\\n\\n[^1]: [vpsFree.cz](https://vpsfree.cz)\\n[^2]: Even though I\'ve been running archLinux on some Raspberry Pi\'s and also\\n on one of my \u201chome servers\u201d, before getting the VPS. You could say I like\\n to live on the edge\u2026"},{"id":"aoc-2022/4th-week","metadata":{"permalink":"/blog/aoc-2022/4th-week","editUrl":"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/04-week-4.md","source":"@site/blog/aoc-2022/04-week-4.md","title":"4th week of Advent of Code \'22 in Rust","description":"Surviving fourth week in Rust.","date":"2023-07-07T15:14:00.000Z","formattedDate":"July 7, 2023","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":15.175,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"4th week of Advent of Code \'22 in Rust","description":"Surviving fourth week in Rust.","date":"2023-07-07T15:14","slug":"aoc-2022/4th-week","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"How can Copr help with broken dependencies","permalink":"/blog/2023/08/02/copr"},"nextItem":{"title":"3rd week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/3rd-week"}},"content":"Let\'s go through the fourth week of [_Advent of Code_] in Rust.\\n\\n\x3c!--truncate--\x3e\\n\\n## [Day 22: Monkey Map](https://adventofcode.com/2022/day/22)\\n\\n:::info tl;dr\\n\\nSimulating a movement on a 2D map with given instructions. Map becomes a cube in\\nthe 2nd part\u2026\\n\\n:::\\n\\n:::caution Rant\\n\\nThis was the most obnoxious problem of this year\u2026 and a lot of Rust issues have\\nbeen hit.\\n\\n:::\\n\\n### Solution\\n\\nIt seems like a very simple problem to solve, but with very obnoxious changes in\\nthe 2nd part and also it\'s relatively hard to decompose \xbbproperly\xab.\\n\\n#### Column iterator\\n\\nIn the first part of the problem it was needed to know the boundaries of each\\nrow and column, since I stored them in `Vec>` and padded with spaces\\nto ensure I have a rectangular 2D \u201carray\u201d. However when you wanted to go through\\neach row and column to determine the boundaries, it was very easy to do for the\\nrows (cause each row is a `Vec` element), but not for the columns, since they\\nspan multiple rows.\\n\\nFor this use case I have implemented my own _column iterator_:\\n```rust\\npub struct ColumnIterator<\'a, T> {\\n map: &\'a [Vec],\\n column: usize,\\n\\n i: usize,\\n}\\n\\nimpl<\'a, T> ColumnIterator<\'a, T> {\\n pub fn new(map: &\'a [Vec], column: usize) -> ColumnIterator<\'a, T> {\\n Self { map, column, i: 0 }\\n }\\n}\\n\\nimpl<\'a, T> Iterator for ColumnIterator<\'a, T> {\\n type Item = &\'a T;\\n\\n fn next(&mut self) -> Option {\\n if self.i >= self.map.len() {\\n return None;\\n }\\n\\n self.i += 1;\\n Some(&self.map[self.i - 1][self.column])\\n }\\n}\\n```\\n\\nGiven this piece of an iterator, it is very easy to factor out the common\\nfunctionality between the rows and columns into:\\n```rust\\nlet mut find_boundaries = |constructor: fn(usize) -> Orientation,\\n iterator: &mut dyn Iterator,\\n upper_bound,\\n i| {\\n let mut first_non_empty = iterator.enumerate().skip_while(|&(_, &c)| c == \' \');\\n let start = first_non_empty.next().unwrap().0 as isize;\\n\\n let mut last_non_empty = first_non_empty.skip_while(|&(_, &c)| c != \' \');\\n let end = last_non_empty.next().unwrap_or((upper_bound, &\'_\')).0 as isize;\\n\\n boundaries.insert(constructor(i), start..end);\\n};\\n```\\n\\nAnd then use it as such:\\n```rust\\n// construct all horizontal boundaries\\n(0..map.len()).for_each(|row| {\\n find_boundaries(\\n Orientation::horizontal,\\n &mut map[row].iter(),\\n map[row].len(),\\n row,\\n );\\n});\\n\\n// construct all vertical boundaries\\n(0..map[0].len()).for_each(|col| {\\n find_boundaries(\\n Orientation::vertical,\\n &mut ColumnIterator::new(&map, col),\\n map.len(),\\n col,\\n );\\n});\\n```\\n\\n#### Walking around the map\\n\\nOnce the 2nd part got introduced, you start to think about a way how not to\\ncopy-paste a lot of stuff (I haven\'t avoided it anyways\u2026). In this problem, I\'ve\\nchosen to introduce a trait (i.e. _interface_) for 2D and 3D walker.\\n```rust\\ntrait Wrap: Clone {\\n type State;\\n\\n // simulation\\n fn is_blocked(&self) -> bool;\\n fn step(&mut self, steps: isize);\\n fn turn_left(&mut self);\\n fn turn_right(&mut self);\\n\\n // movement\\n fn next(&self) -> (Self::State, Direction);\\n\\n // final answer\\n fn answer(&self) -> Output;\\n}\\n```\\n\\nEach walker maintains its own state and also provides the functions that are\\nused during the simulation. The \u201cpromised\u201d methods are separated into:\\n* _simulation_-related: that are used during the simulation from the `.fold()`\\n* _movement_-related: just a one method that holds most of the logic differences\\n between 2D and 3D\\n* _final answer_: which extracts the _proof of solution_ from the\\n implementation-specific walker\\n\\nBoth 2D and 3D versions borrow the original input and therefore you must\\nannotate the lifetime of it:\\n```rust\\nstruct Wrap2D<\'a> {\\n input: &\'a Input,\\n position: Position,\\n direction: Direction,\\n}\\nimpl<\'a> Wrap2D<\'a> {\\n fn new(input: &\'a Input) -> Wrap2D<\'a> {\\n// \u2026\\n```\\n\\n#### Problems\\n\\nI have used a lot of closures for this problem and once I introduced a parameter\\nthat was of unknown type (apart from the fact it implements a specific trait), I\\ngot suggested a \u201cfix\u201d for the compilation error that resulted in something that\\nwas not possible to parse, cause it, more than likely, violated the grammar.\\n\\nIn a similar fashion, I have been suggested changes that led to a code that\\ndidn\'t make sense by just looking at it (there was no need to try the changes),\\nfor example one suggested change in the closure parameter caused disapperance of\\nthe parameter name. :smile:\\n\\n#### Clippy\\n\\nI have to admit that Clippy was rather helpful here, I\'ll include two examples\\nof rather smart suggestions.\\n\\nWhen writing the parsing for this problem, the first thing I have spotted on the\\n`char` was the `.is_digit()` function that takes a radix as a parameter. Clippy\\nnoticed that I use `radix = 10` and suggested switching to `.is_ascii_digit()`\\nthat does exactly the same thing:\\n```diff\\n- .take_while(|c| c.is_digit(10))\\n+ .take_while(|c| c.is_ascii_digit())\\n```\\n\\nAnother useful suggestion appeared when working with the iterators and I wanted\\nto get the $n$-th element from it. You know the `.skip()`, you know the\\n`.next()`, just \u201cslap\u201d them together and we\'re done for :grin: Well, I got\\nsuggested to use `.nth()` that does exactly the combination of the two mentioned\\nmethods on iterators:\\n```diff\\n- match it.clone().skip(skip).next().unwrap() {\\n+ match it.clone().nth(skip).unwrap() {\\n```\\n\\n## [Day 23: Unstable Diffusion](https://adventofcode.com/2022/day/23)\\n\\n:::info tl;dr\\n\\nSimulating movement of elves around with a set of specific rules.\\n\\n:::\\n\\n### Solution\\n\\nThere\'s not much to mention since it\'s just a cellular automaton simulation\\n(even though the AoC rules for cellular automatons usually get out of hand\\n:wink:).\\n\\nAlthough I had a need to determine boundaries of the elves\' positions and ended\\nup with a nasty DRY violation. Knowing that you you\'re looking for maximum and\\nminimum that are, of course, exactly the same except for initial values and\\ncomparators, it looks like a rather simple fix, but typing in Rust is something\\nelse, right? In the end I settled for a function that computes both boundaries\\nwithout any duplication while using a closure:\\n```rust\\nfn get_bounds(positions: &Input) -> (Vector2D, Vector2D) {\\n let f = |init, cmp: &dyn Fn(isize, isize) -> isize| {\\n positions\\n .iter()\\n .fold(Vector2D::new(init, init), |acc, elf| {\\n Vector2D::new(cmp(acc.x(), elf.x()), cmp(acc.y(), elf.y()))\\n })\\n };\\n\\n (f(isize::MAX, &min::), f(isize::MIN, &max::))\\n}\\n```\\n\\nThis function returns a pair of 2D vectors that represent opposite points of the\\nbounding rectangle of all elves.\\n\\nYou might ask why would we need a closure and the answer is that `positions`\\ncannot be captured from within the nested function, only via closure. One more\\nfun fact on top of that is the type of the comparator\\n```rust\\n&dyn Fn(isize, isize) -> isize\\n```\\nOnce we remove the `dyn` keyword, compiler yells at us and also includes a way\\nhow to get a more thorough explanation of the error by running\\n\\n $ rustc --explain E0782\\n\\nwhich shows us\\n\\n Trait objects must include the `dyn` keyword.\\n \\n Erroneous code example:\\n \\n ```\\n trait Foo {}\\n fn test(arg: Box) {} // error!\\n ```\\n \\n Trait objects are a way to call methods on types that are not known until\\n runtime but conform to some trait.\\n \\n Trait objects should be formed with `Box`, but in the code above\\n `dyn` is left off.\\n \\n This makes it harder to see that `arg` is a trait object and not a\\n simply a heap allocated type called `Foo`.\\n \\n To fix this issue, add `dyn` before the trait name.\\n \\n ```\\n trait Foo {}\\n fn test(arg: Box) {} // ok!\\n ```\\n \\n This used to be allowed before edition 2021, but is now an error.\\n\\n:::danger Rant\\n\\nNot all of the explanations are helpful though, in some cases they might be even\\nmore confusing than helpful, since they address _very simple_ use cases.\\n\\nAs you can see, even in this case there are two sides to the explanations:\\n* it explains why you need to use `dyn`, but\\n* it still mentions that trait objects need to be heap-allocated via `Box`\\n that, as you can see in my snippet, **does not** apply here :smile: IMO it\'s\\n caused by the fact that we are borrowing it and therefore we don\'t need to\\n care about the size or whereabouts of it.\\n\\n:::\\n\\n:::info C++ parallel\\n\\nIf you dive into the explanation above, you can notice that the `Box`\\npattern is very helpful for using types that are not known during compile-time.\\nYou would use a very similar approach in C++ when parsing some data structure\\nfrom input (let\'s say JSON for example).\\n\\nOn the other hand, in this case, it doesn\'t really make much sense, cause you\\ncan clearly see that the types **are known** during the compile-time, which in\\nC++ could be easily resolved by templating the helper function.\\n\\n:::\\n\\n## [Day 24: Blizzard Basin](https://adventofcode.com/2022/day/24)\\n\\n:::info tl;dr\\n\\nNavigating your way through a basin with series of blizzards that move around\\nyou as you move.\\n\\n:::\\n\\n:::caution\\n\\nIt\'s second to last day and I went \u201c_bonkers_\u201d on the Rust :smile: Proceed to\\nread _Solution_ part on your own risk.\\n\\n:::\\n\\n### Solution\\n\\nYou are given a map with blizzards all over the place and you\'re supposed to\\nfind the minimum time it requires you to walk through the basin without getting\\nin any of the blizzards.\\n\\n#### Breakdown\\n\\nRelatively simple, yet a bit annoying, approach can be taken. It\'s technically\\na shortest-path algorithm implementation with some relaxation restrictions and\\nbeing able to stay on one position for some time, so each _vertex_ of the graph\\nis determined by the position on the map and the _timestamp_. I have chosen to\\nuse `Vector3D`, since `x` and `y` attributes can be used for the position\\nand, well, let\'s use `z` for a timestamp, cause why not, right? :wink:\\n\\n#### Evaluating the blizzards\\n\\n:::caution\\n\\nI think that this is the most perverted abuse of the traits in the whole 4 weeks\\nof AoC in Rust\u2026\\n\\n:::\\n\\nThe blizzards move along their respective directions in time and loop around in\\ntheir respective row/column. Each vertex holds position **and** time, so we can\\n_just_ index the basin with the vertex itself, right? Yes, we can :smiling_imp:\\n\\n:::tip Fun fact\\n\\nWhile writing this part, I\'ve recognized unnecessary verbosity in the code and\\ncleaned it up a bit. The changed version is shown here and the original was just\\nmore verbose.\\n\\n:::\\n\\nI\'ll skip the boring parts of checking bounds and entry/exit of the basin :wink:\\nWe can easily calculate positions of the blizzards using a modular arithmetics:\\n```rust\\nimpl Index for Basin {\\n type Output = char;\\n\\n fn index(&self, index: Position) -> &Self::Output {\\n // \u2039skipped boring parts\u203a\\n\\n // We need to account for the loops of the blizzards\\n let width = self.cols - 2;\\n let height = self.rows - 2;\\n\\n let blizzard_origin = |size, d, t, i| ((i - 1 + size + d * (t % size)) % size + 1) as usize;\\n [\\n (\\n index.y() as usize,\\n blizzard_origin(width, -1, index.z(), index.x()),\\n \'>\',\\n ),\\n (\\n index.y() as usize,\\n blizzard_origin(width, 1, index.z(), index.x()),\\n \'<\',\\n ),\\n (\\n blizzard_origin(height, -1, index.z(), index.y()),\\n index.x() as usize,\\n \'v\',\\n ),\\n (\\n blizzard_origin(height, 1, index.z(), index.y()),\\n index.x() as usize,\\n \'^\',\\n ),\\n ]\\n .iter()\\n .find_map(|&(y, x, direction)| {\\n if self.map[y][x] == direction {\\n Some(&self.map[y][x])\\n } else {\\n None\\n }\\n })\\n .unwrap_or(&\'.\')\\n }\\n}\\n```\\n\\nAs you can see, there is an expression for calculating the original position and\\nit\'s used multiple times, so why not take it out to a lambda, right? :wink:\\n\\nI couldn\'t get the `rustfmt` to format the `for`-loop nicely, so I\'ve just\\ndecided to go with iterating over an elements of a slice. I have used, once\\nagain, a combination of two functions (`find_map` in this case) to do 2 things\\nat once and at the end, if we haven\'t found any blizzard, we just return the\\nempty space.\\n\\nI think it\'s a very _nice_ (and naughty) way how to use the `Index` trait, don\'t\\nyou think?\\n\\n#### Shortest-path algorithm\\n\\nFor the shortest path you can choose and adjust any of the common shortest-path\\nalgorithms, in my case, I have decided to use [_A\\\\*_] instead of Dijkstra\'s\\nalgorithm, since it better reflects the _cost_ function.\\n\\n:::info Comparison of costs\\n\\nWith the Dijkstra\'s algorithm I would proceed with the `time` attribute used as\\na priority for the queue.\\n\\nWhereas with the _A\\\\*_, I have chosen to use both time and Manhattan distance\\nthat promotes vertices closer to the exit **and** with a minimum time taken.\\n\\n:::\\n\\nCost function is, of course, a closure :wink:\\n```rust\\nlet cost = |p: Position| p.z() as usize + exit.y().abs_diff(p.y()) + exit.x().abs_diff(p.x());\\n```\\n\\nAnd also for checking the possible moves from the current vertex, I have\\nimplemented, yet another, closure that yields an iterator with the next moves:\\n```rust\\nlet next_positions = |p| {\\n [(0, 0, 1), (0, -1, 1), (0, 1, 1), (-1, 0, 1), (1, 0, 1)]\\n .iter()\\n .filter_map(move |&(x, y, t)| {\\n let next_p = p + Vector3D::new(x, y, t);\\n\\n if basin[next_p] == \'.\' {\\n Some(next_p)\\n } else {\\n None\\n }\\n })\\n};\\n```\\n\\n#### Min-heap\\n\\nIn this case I had a need to use the priority queue taking the elements with the\\nlowest cost as the prioritized ones. Rust only offers you the [`BinaryHeap`] and\\nthat is a max-heap. One of the ways how to achieve a min-heap is to put the\\nelements in wrapped in a [`Reverse`] (as is even showed in the linked [docs of\\nthe `BinaryHeap`]). However the wrapping affects the type of the heap and also\\npopping the most prioritized elements yields values wrapped in the `Reverse`.\\n\\nFor this purpose I have just taken the max-heap and wrapped it as a whole in a\\nseparate structure providing just the desired methods:\\n```rust\\nuse std::cmp::{Ord, Reverse};\\nuse std::collections::BinaryHeap;\\n\\npub struct MinHeap {\\n heap: BinaryHeap>,\\n}\\n\\nimpl MinHeap {\\n pub fn new() -> MinHeap {\\n MinHeap {\\n heap: BinaryHeap::new(),\\n }\\n }\\n\\n pub fn push(&mut self, item: T) {\\n self.heap.push(Reverse(item))\\n }\\n\\n pub fn pop(&mut self) -> Option {\\n self.heap.pop().map(|Reverse(x)| x)\\n }\\n}\\n\\nimpl Default for MinHeap {\\n fn default() -> Self {\\n Self::new()\\n }\\n}\\n```\\n\\nRest is just the algorithm implementation which is not that interesting.\\n\\n## [Day 25: Full of Hot Air](https://adventofcode.com/2022/day/25)\\n\\n:::info tl;dr\\n\\nPlaying around with a numbers in a _special_ base.\\n\\n:::\\n\\nGetting flashbacks to the _IB111 Foundations of Programming_\u2026 Very nice \u201cproblem\u201d\\nwith a rather easy solution, as the last day always seems to be.\\n\\n### Solution\\n\\nImplementing 2 functions, converting from the _SNAFU base_ and back to the _SNAFU_\\n_base_ representation. Let\'s do a bit more though! I have implemented two functions:\\n* `from_snafu`\\n* `to_snafu`\\n\\nNow it is apparent that all I do is number to string and string to number. Hmm\u2026\\nthat sounds familiar, doesn\'t it? Let\'s introduce a structure for the SNAFU numbers\\nand implement the traits that we need.\\n\\nLet\'s start with a structure:\\n```rust\\n#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\\nstruct SNAFU {\\n value: i64,\\n}\\n```\\n\\n#### Converting from `&str`\\n\\nWe will start by implementing the `FromStr` trait that will help us parse our input.\\nThis is rather simple, I can just take the `from_snafu` function, copy-paste it\\ninto the `from_str` method and the number I get will be wrapped in `Result` and\\n`SNAFU` structure.\\n\\n#### Converting to `String`\\n\\nThis is more fun. In some cases you need to implement only one trait and others\\nare automatically implemented using that one trait. In our case, if you look in\\nthe documentation, you can see that `ToString` trait is automatically implemented\\nfor any type that implements `Display` trait.\\n\\nLet\'s implement the `Display` trait then. We should be able to use the `to_snafu`\\nfunction and just take the `self.value` from the `SNAFU` structure.\\n\\nAnd for the convenience of tests, we can also implement a rather simple `From`\\ntrait for the `SNAFU`.\\n\\n#### Adjusting the code\\n\\nAfter those changes we need to adjust the code and tests.\\n\\nParsing of the input is very easy, before we have used the lines, now we parse\\neverything:\\n```diff\\n fn parse_input>(pathname: P) -> Input {\\n- file_to_lines(pathname)\\n+ file_to_structs(pathname)\\n }\\n```\\n\\nPart 1 needs to be adjusted a bit too:\\n```diff\\n fn part_1(input: &Input) -> Output {\\n- to_snafu(input.iter().map(|s| from_snafu(s)).sum())\\n+ SNAFU::from(input.iter().map(|s| s.value).sum::()).to_string()\\n }\\n```\\n\\nYou can also see that it simplifies the meaning a bit and it is more explicit than\\nthe previous versions.\\n\\nAnd for the tests:\\n```diff\\n #[test]\\n fn test_from() {\\n- for (n, s) in EXAMPLES.iter() {\\n- assert_eq!(from_snafu(s), *n);\\n+ for (&n, s) in EXAMPLES.iter() {\\n+ assert_eq!(s.parse::().unwrap().value, n);\\n }\\n }\\n \\n #[test]\\n fn test_to() {\\n- for (n, s) in EXAMPLES.iter() {\\n- assert_eq!(to_snafu(*n), s.to_string());\\n+ for (&n, s) in EXAMPLES.iter() {\\n+ assert_eq!(SNAFU::from(n).to_string(), s.to_string());\\n }\\n```\\n\\n## Summary\\n\\nLet\'s wrap the whole thing up! Keeping in mind both AoC and the Rust\u2026\\n\\n![Finished advent calendar :smile:](/img/blog/aoc-2022/04-week-4/calendar.png)\\n\\n### Advent of Code\\n\\nThis year was quite fun, even though most of the solutions and posts came in\\nlater on (*cough* in \'23 *cough*). Day 22 was the most obnoxious one\u2026 And also\\nit feels like I used priority queues and tree data structures **a lot** :eyes:\\n\\n### with Rust\\n\\nI must admit that a lot of compiler warnings and errors were very useful. Even\\nthough I still found some instances where they didn\'t help at all or cause even\\nworse issues than I had. Compilation times have been addressed with the caching.\\n\\nBuilding my first tree data structure in Rust has been a very \u201cinteresting\u201d\\njourney. Being able to write a more generic BFS algorithm that allows you to not\\nduplicate code while still mantaining the desired functionality contributes to\\na very readable code.\\n\\nI am definitely much more aware of the basic things that bloated Python is\\nmissing, yet Rust has them\u2026\\n\\nUsing explicit types and writing down placeholder functions with `todo!()`\\nmacros is very pleasant, since it allows you to easily navigate the type system\\nduring the development when you don\'t even need to be sure how are you going to\\nput the smaller pieces together.\\n\\nI have used a plethora of traits and also implemented some of them to either be\\nidiomatic, or exploit the syntactic sugar they offer. Deriving the default trait\\nimplementation is also very helpful in a lot of cases, e.g. debugging output,\\ncopying, equality comparison, etc.\\n\\nI confess to touching more \u201ccursed\u201d parts of the Rust, such as macros to\\ndeclutter the copy-paste for tests or writing my own structures that need to\\ncarry a lifetime for their own fields.\\n\\ntl;dr Relatively pleasant language until you hit brick wall :wink:\\n\\n---\\n\\nSee you next year! Maybe in Rust, maybe not :upside_down_face:\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[_A\\\\*_]: https://en.wikipedia.org/wiki/A*_search_algorithm\\n[`BinaryHeap`]: https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html\\n[`Reverse`]: https://doc.rust-lang.org/std/cmp/struct.Reverse.html\\n[docs of the `BinaryHeap`]: https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#min-heap"},{"id":"aoc-2022/3rd-week","metadata":{"permalink":"/blog/aoc-2022/3rd-week","editUrl":"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/03-week-3.md","source":"@site/blog/aoc-2022/03-week-3.md","title":"3rd week of Advent of Code \'22 in Rust","description":"Surviving third week in Rust.","date":"2023-07-06T21:00:00.000Z","formattedDate":"July 6, 2023","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":11.565,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"3rd week of Advent of Code \'22 in Rust","description":"Surviving third week in Rust.","date":"2023-07-06T21:00","slug":"aoc-2022/3rd-week","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"4th week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/4th-week"},"nextItem":{"title":"Sort the matrix diagonally","permalink":"/blog/leetcode/sort-diagonally"}},"content":"Let\'s go through the third week of [_Advent of Code_] in Rust.\\n\\n\x3c!--truncate--\x3e\\n\\n## [Day 15: Beacon Exclusion Zone](https://adventofcode.com/2022/day/15)\\n\\n:::info tl;dr\\n\\nTriangulating a distress beacon based on the information from the sensors.\\n\\n:::\\n\\n### Solution\\n\\nRelatively easy thing to implement, no major Rust issues hit.\\n\\n## [Day 16: Proboscidea Volcanium](https://adventofcode.com/2022/day/16)\\n\\n:::info tl;dr\\n\\nFinding a max flow in a graph given some time constraints.\\n\\n:::\\n\\n### Solution\\n\\nI have used some interesting things to implement this and make it easier for me.\\n\\n#### Indexing in graph\\n\\nI have come across a situation where I needed to keep more information regarding\\nthe graph\u2026 In that case you can, of course, create a structure and keep it in,\\nbut once you have multiple members in the structure it gets harder to work with\\nsince you need to address the fields in the structure. When you work with graph,\\nyou frequently need to access the vertices and in this case it felt a lot easier\\nto implement the indexing in a graph, rather than explicitly access the\\nunderlying data structure.\\n\\nHere you can see a rather short snippet from the solution that allows you to\\n\u201cindex\u201d the graph:\\n```rust\\nimpl Index<&str> for Graph {\\n type Output = Vertex;\\n\\n fn index(&self, index: &str) -> &Self::Output {\\n &self.g[index]\\n }\\n}\\n```\\n\\n#### Cartesian product\\n\\nDuring the implementation I had to utilize Floyd-Warshall algorithm for finding\\nthe shortest path between pairs of vertices and utilized the `iproduct!` macro\\nfrom the [`itertools`]. It is a very useful higher-order function that allows\\nyou to keep the nesting of the loops at a minimum level while still maintaining\\nthe same functionality.\\n\\n#### \u201cImplementing\u201d an iterator\\n\\nFor the second part, you get to split the work between 2 actors. That way you\\ncan achieve higher efficiency of the whole process that you\'re planning, but it\\nalso makes it harder to evaluate algorithmically, since you need to check the\\ndifferent ways the work can be split.\\n\\nBeing affected by _functional programming brain damage_:tm:, I have chosen to\\ndo this part by function that returns an iterator over the possible ways:\\n```rust\\nfn pairings(\\n valves: &BTreeSet,\\n) -> impl Iterator, BTreeSet)> + \'_ {\\n let mapping = valves.iter().collect_vec();\\n\\n let max_mask = 1 << (valves.len() - 1);\\n\\n (0..max_mask).map(move |mask| {\\n let mut elephant = BTreeSet::new();\\n let mut human = BTreeSet::new();\\n\\n for (i, &v) in mapping.iter().enumerate() {\\n if (mask & (1 << i)) == 0 {\\n human.insert(v.clone());\\n } else {\\n elephant.insert(v.clone());\\n }\\n }\\n\\n (human, elephant)\\n })\\n}\\n```\\n\\n## [Day 17: Pyroclastic Flow](https://adventofcode.com/2022/day/17)\\n\\n:::info tl;dr\\n\\nSimulating an autonomous Tetris where pieces get affected by a series of jets of\\nhot gas.\\n\\n:::\\n\\n### Solution\\n\\nSimilarly to the previous day I have created some iterators :smile:\\n\\n#### Collision detection\\n\\nOnce you need to check for collisions it is very helpful to be able to just\\niterate through the positions that can actually collide with the wall or other\\npiece.\\n\\nTo get the desired behaviour, you can just compose few smaller functions:\\n```rust\\nfn occupied(shape: &[Vec]) -> impl Iterator + \'_ {\\n shape.iter().enumerate().flat_map(|(y, row)| {\\n row.iter().enumerate().filter_map(move |(x, c)| {\\n if c == &\'#\' {\\n Some(Vector2D::new(x as isize, y as isize))\\n } else {\\n None\\n }\\n })\\n })\\n}\\n```\\n\\nIn the end, we get relative positions which we can adjust later when given the\\nspecific positions from iterator. You can see some interesting parts in this:\\n\\n* `.enumerate()` allows us to get both the indices (coordinates) and the line\\n or, later on, the character itself,\\n* `.flat_map()` flattens the iterator, i.e. when we return another iterator,\\n they just get chained instead of iterating over iterators (which sounds pretty\\n disturbing, doesn\'t it?),\\n* and finally `.filter_map()` which is pretty similar to the \u201cbasic\u201d `.map()`\\n with a one, key, difference that it expects the items of an iterator to be\\n mapped to an `Option` from which it ignores nothing (as in `None` :wink:)\\n and also unwraps the values from `Some(\u2026)`.\\n\\n#### Infinite iterator\\n\\nIn the solution we cycle through both Tetris-like shapes that fall down and the\\njets that move our pieces around. Initially I have implemented my own infinite\\niterator that just yields the indices. It is a very simple, yet powerful, piece\\nof code:\\n```rust\\nstruct InfiniteIndex {\\n size: usize,\\n i: usize,\\n}\\n\\nimpl InfiniteIndex {\\n fn new(size: usize) -> InfiniteIndex {\\n InfiniteIndex { size, i: size - 1 }\\n }\\n}\\n\\nimpl Iterator for InfiniteIndex {\\n type Item = usize;\\n\\n fn next(&mut self) -> Option {\\n self.i = (self.i + 1) % self.size;\\n Some(self.i)\\n }\\n}\\n```\\n\\nHowever when I\'m looking at the code now, it doesn\'t really make much sense\u2026\\nGuess what, we can use a built-in function that is implemented on iterators for\\nthat! The function is called `.cycle()`\\n\\nOn the other hand, I am not going to switch to that function, since it would\\nintroduce an another myriad of issues caused by the fact that I create iterators\\nright away in the constructor of my structure and the iterators would borrow\\nboth the jets and shapes which would introduce a lifetime dependency into the\\nstructure.\\n\\n## [Day 18: Boiling Boulders](https://adventofcode.com/2022/day/18) \\n\\n:::info tl;dr\\n\\nLet\'s compute a surface area of some obsidian approximated via coordinates of\\ncubes.\\n\\n:::\\n\\n### Solution\\n\\nThis day is kinda interesting, because it shows how easily you can complicate the\\nproblem and also how much can you screw yourself over with the optimization and\\n\u201csmart\u201d approach.\\n\\nFor the first part you need to find the surface area of an obsidian that is\\napproximated by cubes. Now, that is a very easy thing to do, just keep the track\\nof already added cubes, and check if the newly added cube touches any face of any\\nother cube. Simple, and with a `BTreeSet` relatively efficient way to do it.\\n\\nHowever the second part lets you on a secret that there may be some surface area\\nfrom the \u201cinside\u201d too and you want to know only the one from the outside of the\\nobsidian. I have seen some solutions later, but if you check your data, you might\\nnotice that the bounding box of all the cubes isn\'t that big at all. Therefore I\\nchose to pre-construct the box beforehand, fill in the cubes and then just run a\\nBFS turning all the lava on the outside into the air. Now you just need to check\\ncubes and count how many of their faces touch the air.\\n\\n## [Day 19: Not Enough Minerals](https://adventofcode.com/2022/day/19)\\n\\n:::info tl;dr\\n\\nFinding out the best strategy for building robots to collect geodes.\\n\\n:::\\n\\n### Solution\\n\\nNot much interesting stuff to mention apart from the suggestion to never believe\\nthat the default implementation given by `derive` macro is what you want, it\\ndoesn\'t have to be. :smile:\\n\\n## [Day 20: Grove Positioning System](https://adventofcode.com/2022/day/20)\\n\\n:::info tl;dr\\n\\nShuffling around the _circular linked list_ to find the coordinates.\\n\\n:::\\n\\nNow, small rant for this day is in place. They\'ve never mentioned that coordinates\\ncan repeat and therefore the values are non-unique. This is something that did\\nnot happen in the given sample, but was present in the user input. It took \xbba lot\xab\\nto realize that this is the issue.\\n\\n### Solution\\n\\nI have tried implementing a circular linked list for this\u2026 and I have failed\\nmiserably. To be fair, I still have no clue why. It was \u201cfun\u201d to play around with\\nthe `Rc>`. In the end I failed on _wrong answer_. I have also encountered\\na rather interesting issue with `.borrow_mut()` method being used on `Rc>`.\\n\\n#### `.borrow_mut()`\\n\\nConsider the following snippet of the code (taken from the documentation):\\n```rust\\nuse std::cell::{RefCell, RefMut};\\nuse std::collections::HashMap;\\nuse std::rc::Rc;\\n// use std::borrow::BorrowMut;\\n\\nfn main() {\\n let shared_map: Rc> = Rc::new(RefCell::new(HashMap::new()));\\n // Create a new block to limit the scope of the dynamic borrow\\n {\\n let mut map: RefMut<_> = shared_map.borrow_mut();\\n map.insert(\\"africa\\", 92388);\\n map.insert(\\"kyoto\\", 11837);\\n map.insert(\\"piccadilly\\", 11826);\\n map.insert(\\"marbles\\", 38);\\n }\\n\\n // Note that if we had not let the previous borrow of the cache fall out\\n // of scope then the subsequent borrow would cause a dynamic thread panic.\\n // This is the major hazard of using `RefCell`.\\n let total: i32 = shared_map.borrow().values().sum();\\n println!(\\"{total}\\");\\n}\\n```\\n\\nWe allocate a hash map on the heap and then in the inner block, we borrow it as\\na mutable reference, so that we can use it.\\n\\n:::note\\n\\nIt is a very primitive example for `Rc>` and mutable borrow.\\n\\n:::\\n\\nIf you uncomment the 4th line with `use std::borrow::BorrowMut;`, you cannot\\ncompile the code anymore, because of\\n```\\n Compiling playground v0.0.1 (/playground)\\nerror[E0308]: mismatched types\\n --\x3e src/main.rs:10:34\\n |\\n10 | let mut map: RefMut<_> = shared_map.borrow_mut();\\n | --------- ^^^^^^^^^^^^^^^^^^^^^^^ expected struct `RefMut`, found mutable reference\\n | |\\n | expected due to this\\n |\\n = note: expected struct `RefMut<\'_, _>`\\n found mutable reference `&mut Rc>>`\\n\\nerror[E0599]: no method named `insert` found for struct `RefMut<\'_, _>` in the current scope\\n --\x3e src/main.rs:11:13\\n |\\n11 | map.insert(\\"africa\\", 92388);\\n | ^^^^^^ method not found in `RefMut<\'_, _>`\\n\\nerror[E0599]: no method named `insert` found for struct `RefMut<\'_, _>` in the current scope\\n --\x3e src/main.rs:12:13\\n |\\n12 | map.insert(\\"kyoto\\", 11837);\\n | ^^^^^^ method not found in `RefMut<\'_, _>`\\n\\nerror[E0599]: no method named `insert` found for struct `RefMut<\'_, _>` in the current scope\\n --\x3e src/main.rs:13:13\\n |\\n13 | map.insert(\\"piccadilly\\", 11826);\\n | ^^^^^^ method not found in `RefMut<\'_, _>`\\n\\nerror[E0599]: no method named `insert` found for struct `RefMut<\'_, _>` in the current scope\\n --\x3e src/main.rs:14:13\\n |\\n14 | map.insert(\\"marbles\\", 38);\\n | ^^^^^^ method not found in `RefMut<\'_, _>`\\n\\nSome errors have detailed explanations: E0308, E0599.\\nFor more information about an error, try `rustc --explain E0308`.\\nerror: could not compile `playground` due to 5 previous errors\\n```\\n\\nIt might seem **a bit** ridiculous. However, I got to a point where the compiler\\nsuggested `use std::borrow::BorrowMut;` and it resulted in breaking parts of the\\ncode that worked previously. I think it may be a good idea to go over what is\\nhappening here.\\n\\n##### `.borrow_mut()` on `Rc>`\\n\\nLet\'s consider a variable `x` of type `Rc>`. What happens when you\\ncall `.borrow_mut()` on it? We can look at the `Rc` type, and\u2026 hang on! There is\\nneither `.borrow_mut()` method or `BorrowMut` trait implemented. How can we do it\\nthen?\\n\\nLet\'s go further and we can see that `RefCell` implements a `.borrow_mut()`\\nmethod. OK, but how can we call it on the `Rc`? Easily! `Rc` implements\\n`Deref` and therefore you can call methods on `Rc` objects as if they were\\n`T` objects. If we read on _`Deref` coercion_, we can see the following:\\n\\n> If `T` implements `Deref`, \u2026:\\n> * \u2026\\n> * `T` implicitly implements all the (immutable) methods of the type `U`.\\n\\nWhat is the requirement for the `.borrow_mut()` on `RefCell`? Well, it needs\\n`&self`, so the `Deref` implements the `.borrow_mut()` for the `Rc>`.\\n\\n##### `BorrowMut` trait\\n\\nI have not been able to find a lot on this trait. My guess is that it provides a\\nmethod instead of a syntactic sugar (`&mut x`) for the mutable borrow. And also\\nit provides default implementations for the types:\\n```rust\\nimpl BorrowMut for String\\n\\nimpl BorrowMut for &mut T\\nwhere\\n T: ?Sized,\\n\\nimpl BorrowMut for T\\nwhere\\n T: ?Sized,\\n\\nimpl BorrowMut<[T]> for Vec\\nwhere\\n A: Allocator,\\n\\nimpl BorrowMut for Box\\nwhere\\n A: Allocator,\\n T: ?Sized,\\n\\nimpl BorrowMut<[T]> for [T; N]\\n```\\n\\n##### Conflict\\n\\nNow the question is why did it break the code\u2026 My first take was that the type\\n`Rc>` has some _specialized_ implementation of the `.borrow_mut()` and\\nthe `use` overrides it with the default, which is true **in a sense**. However\\nthere is no _specialized_ implementation. Let\'s have a look at the trait and the\\ntype signature on the `RefCell`:\\n```rust\\n// trait\\npub trait BorrowMut: Borrow\\nwhere\\n Borrowed: ?Sized,\\n{\\n fn borrow_mut(&mut self) -> &mut Borrowed;\\n}\\n\\n// \u2039RefCell.borrow_mut()\u203a type signature\\npub fn borrow_mut(&self) -> RefMut<\'_, T>\\n```\\n\\nI think that we can definitely agree on the fact that `RefMut<\'_, T>` is not the\\n`RefCell`.\\n\\n**In my opinion**, `RefCell` implements a **separate** `.borrow_mut()` rather\\nthan implementing the interface, because it **cannot** satisfy the type requirements\\nof the trait.\\n\\n:::caution\\n\\nI wonder how are we expected to deal with this conflict, if and when, we need\\nboth the `.borrow_mut()` of the trait and `.borrow_mut()` of the `RefCell`.\\n\\n:::\\n\\n:::tip Fun fact\\n\\nI was suggested by the compiler to do `use std::borrow::BorrowMut;` and break the\\ncode.\\n\\nSo much for the _almighty_ and _helpful_ compiler\u2026\\n\\n:::\\n\\n## [Day 21: Monkey Math](https://adventofcode.com/2022/day/21)\\n\\n:::info tl;dr\\n\\nComputing an expression tree and then also finding ideal value for a node.\\n\\n:::\\n\\n### Solution\\n\\nRelatively simple, until you get to the 2nd part where you start to practice\\na lot of the copy-paste. I have managed to sneak some perverted stuff in there\\nthough :) Let\'s go through the details.\\n\\n#### `Default` trait\\n\\nFor the first time and twice I had a need to have a default value for my types,\\nenumerations in this case. Rust offers a very nice trait[^1] that is described\\nas:\\n\\n> A trait for giving a type a useful default value.\\n\\nI guess it sums it up nicely. The more interesting part about this is the fact\\nthat you can use the _macro machinery_ to save yourself some typing. If you have\\nenumeration of which the default value doesn\'t bear any parameter, you can just\\ndo[^2]:\\n\\n```rust\\n#[derive(Default)]\\nenum Color {\\n #[default]\\n White,\\n Gray,\\n Black,\\n}\\n```\\n\\n#### Abusing negation\\n\\nIf you want to use a _unary minus_ operator on your own type, you can implement\\na `Neg` trait[^3]. I was dealing with a binary tree and needed a way how to look\\nat the other side, so I have just implemented the negation for flipping between\\nleft and right :smile:\\n\\n[^1]: [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) docs\\n[^2]: Pardon my example from the graph algorithms ;)\\n[^3]: [`Neg`](https://doc.rust-lang.org/std/ops/trait.Neg.html) docs\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[`itertools`]: https://crates.io/crates/itertools\\n[this Reddit post and the comment]: https://www.reddit.com/r/adventofcode/comments/zb98pn/comment/iyq0ono"},{"id":"leetcode/sort-diagonally","metadata":{"permalink":"/blog/leetcode/sort-diagonally","editUrl":"https://github.com/mfocko/blog/tree/main/blog/leetcode/sort-matrix-diagonally.md","source":"@site/blog/leetcode/sort-matrix-diagonally.md","title":"Sort the matrix diagonally","description":"Compiler assisted development.","date":"2023-03-04T23:15:00.000Z","formattedDate":"March 4, 2023","tags":[{"label":"cpp","permalink":"/blog/tags/cpp"},{"label":"leetcode","permalink":"/blog/tags/leetcode"},{"label":"iterators","permalink":"/blog/tags/iterators"}],"readingTime":16.99,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"Sort the matrix diagonally","description":"Compiler assisted development.","date":"2023-03-04T23:15","slug":"leetcode/sort-diagonally","authors":"mf","tags":["cpp","leetcode","iterators"],"hide_table_of_contents":false},"prevItem":{"title":"3rd week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/3rd-week"},"nextItem":{"title":"2nd week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/2nd-week"}},"content":"Let\'s try to solve one of the LeetCode challenges in easy and hard mode at the\\nsame time.\\n\\n\x3c!--truncate--\x3e\\n\\n* Link to the problem: https://leetcode.com/problems/sort-the-matrix-diagonally/\\n\\n## Problem description\\n\\nA **matrix diagonal** is a diagonal line of cells starting from some cell in\\neither the topmost row or leftmost column and going in the bottom-right direction\\nuntil reaching the matrix\'s end. For example, the **matrix diagonal** starting\\nfrom `mat[2][0]`, where `mat` is a `6 x 3` matrix, includes cells `mat[2][0]`,\\n`mat[3][1]`, and `mat[4][2]`.\\n\\nGiven an `m x n` matrix `mat` of integers, sort each matrix diagonal in ascending\\norder and return the resulting matrix.\\n\\n### Example\\n\\n![Image describing the problem](https://assets.leetcode.com/uploads/2020/01/21/1482_example_1_2.png)\\n\\n## Skeleton and initial adjustments\\n\\nWe are given the following skeleton for the C++ and the given challenge:\\n\\n```cpp\\nclass Solution {\\npublic:\\n vector> diagonalSort(vector>& mat) {\\n \\n }\\n};\\n```\\n\\nThe task is to sort the passed matrix diagonally and then return it. First of all,\\nI don\'t like to solve this in a web browser, so we\'ll need to adjust it accordingly\\nfor running it locally. We\'ll start by including the `vector` header and using\\nfully-qualified namespaces[^1] and also adding few tests:\\n\\n```cpp\\n#include \\n#include \\n\\nusing matrix = std::vector>;\\n\\nclass Solution {\\npublic:\\n matrix diagonalSort(matrix& mat)\\n {\\n }\\n};\\n\\nstatic void test_case_1()\\n{\\n // Input: mat = [[3,3,1,1],[2,2,1,2],[1,1,1,2]]\\n // Output: [[1,1,1,1],[1,2,2,2],[1,2,3,3]]\\n\\n Solution s;\\n assert((s.diagonalSort(std::vector { std::vector { 3, 3, 1, 1 },\\n std::vector { 2, 2, 1, 2 },\\n std::vector { 1, 1, 1, 2 } })\\n == std::vector { std::vector { 1, 1, 1, 1 },\\n std::vector { 1, 2, 2, 2 },\\n std::vector { 1, 2, 3, 3 } }));\\n}\\n\\nstatic void test_case_2()\\n{\\n // Input: mat =\\n // [[11,25,66,1,69,7],[23,55,17,45,15,52],[75,31,36,44,58,8],[22,27,33,25,68,4],[84,28,14,11,5,50]]\\n // Output:\\n // [[5,17,4,1,52,7],[11,11,25,45,8,69],[14,23,25,44,58,15],[22,27,31,36,50,66],[84,28,75,33,55,68]]\\n\\n Solution s;\\n assert((s.diagonalSort(std::vector { std::vector { 11, 25, 66, 1, 69, 7 },\\n std::vector { 23, 55, 17, 45, 15, 52 },\\n std::vector { 75, 31, 36, 44, 58, 8 },\\n std::vector { 22, 27, 33, 25, 68, 4 },\\n std::vector { 84, 28, 14, 11, 5, 50 } })\\n == std::vector { std::vector { 5, 17, 4, 1, 52, 7 },\\n std::vector { 11, 11, 25, 45, 8, 69 },\\n std::vector { 14, 23, 25, 44, 58, 15 },\\n std::vector { 22, 27, 31, 36, 50, 66 },\\n std::vector { 84, 28, 75, 33, 55, 68 } }));\\n}\\n\\nint main()\\n{\\n test_case_1();\\n test_case_2();\\n\\n return 0;\\n}\\n```\\n\\nWe need to return the matrix, but we\'re given a reference to the input matrix. We\\ncan easily abuse the C++ here and just switch the reference to value, this way\\nthe matrix will be copied when passed to the function, we can sort the copy and\\njust return it back. And we also get yelled by the compiler for the fact that the\\nmethod doesn\'t return anything yet, so to make it \u201cshut up\u201d we will just return\\nthe input for now:\\n\\n```diff\\n- matrix diagonalSort(matrix& mat)\\n+ matrix diagonalSort(matrix mat)\\n {\\n+ return mat;\\n }\\n```\\n\\nNow, we get the copy and we\'re good to go.\\n\\n## Na\xefve solution\\n\\nAs you may know, C++ offers a plethora of functions that can be used to your\\nadvantage, given that you know how to \u201cbend\u201d the data structures accordingly.\\n\\nWhat does that mean for us? Well, we have an `std::sort`, we can use it, right?\\nLet\'s have a look at it:\\n```cpp\\ntemplate< class RandomIt >\\nvoid sort( RandomIt first, RandomIt last );\\n```\\n\\nThis overload is more than we need. What does it do? It just sorts the elements\\nin the range `[first, last)` using `operator<` on them. We can\'t sort the whole\\nmatrix using this, but\u2026 we can sort just \xbbone\xab diagonal without doing much work\\non our end.\\n\\nWhat is the `RandomIt` type though? If we look more into the documentation, we\\ncan easily find the requirements for it and also learn that it\'s a _random access_\\n_iterator_ and allows swapping its values at the same time.\\n\\n:::tip Random access iterator\\n\\nWhat is the _random access iterator_ though? We can find it in a documentation\\nand see the following description:\\n\\n> A **LegacyRandomAccessIterator** is a [LegacyBidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator)\\n> that can be moved to point to any element in constant time.\\n\\nAfter that we can see all the requirements for it being listed. I don\'t feel like\\nreading them right now, so we will just use it and see where the compilation blows\\nup, i.e. \u201c_compiler-assisted development_\u201d[^2] if you will ;)\\n\\n:::\\n\\nNow we know that we can use `std::sort` to sort the diagonal itself, but we also\\nneed to get the diagonals somehow. I\'m rather lazy, so I\'ll just delegate it to\\nsomeone else[^3]. And that way we get\\n```cpp\\nmatrix diagonalSort(matrix mat)\\n{\\n // we iterate over the diagonals\\n for (auto d : diagonals(mat)) {\\n // and we sort each diagonal\\n std::sort(d.begin(), d.end());\\n }\\n\\n // we take the matrix by copy, so we can sort in-situ and return the copy\\n // that we sorted\\n return mat;\\n}\\n```\\n\\nThis solution looks very simple, doesn\'t it? Well, cause it is.\\nLet\'s try compiling it:\\n```\\nmatrix-sort.cpp:11:23: error: use of undeclared identifier \'diagonals\' [clang-diagnostic-error]\\n for (auto d : diagonals(mat)) {\\n ^\\nFound compiler error(s).\\nmake: *** [makefile:14: tidy] Error 1\\n```\\n\\nOK, seems about right. We haven\'t implemented the `diagonals` yet. And based on\\nwhat we\'ve written so far, we need a function or a class `diagonals` that will\\ngive us the diagonals we need.\\n\\n## Implementing the `diagonals`\\n\\nCool, so we need the function that will let us go through each and every diagonal\\nin our matrix. We use the _for-range_ loop, so whatever we get back from the\\n`diagonals` must support `.begin()` and `.end()`. Since I am a masochist, we will\\ndo such functionality for a matrix of any type, not just the `int` from the challenge.\\n\\nAs I said, we need to be able to\\n* construct the object\\n* get the beginning\\n* get the end (the \u201csentinel\u201d)\\n\\n```cpp\\ntemplate \\nclass diagonals {\\n using matrix_t = std::vector>;\\n\\n matrix_t& _matrix;\\n\\npublic:\\n diagonals(matrix_t& m)\\n : _matrix(m)\\n {\\n }\\n diagonals_iter begin()\\n {\\n /* TODO */\\n }\\n diagonals_iter end()\\n {\\n /* TODO */\\n }\\n};\\n```\\n\\nNow we have a `diagonals` that we can use to go through the diagonals. We haven\'t\\nimplemented the core of it yet. Let\'s go through what we have for now.\\n\\nWe have a templated class with templated `T` that is used as a placeholder for any\\ntype we would store in the matrix. Because I\'m lazy, I have defined the `matrix_t`\\ntype that is a \u201cshortcut\u201d for `std::vector>`, so I don\'t have to\\ntype it out all the time. Of course, we need to store the matrix, we are given,\\nas a private attribute. And then just have the constructor and the 2 methods we\\nneed for the _for-range_.\\n\\n### Iterating over diagonals\\n\\nNow that we have an object that will allow us to iterate through the diagonals,\\nwe need to implement the iterating itself. We need to go through all of them, so\\nwe have multiple options how to do so. I have decided to start from the \u201cmain\u201d\\ndiagonal that starts at `(0, 0)` index and then proceed with the diagonals starting\\nin the first row, followed by the rest of the diagonals in the first column.\\n\\nWe need to be able to tell that we\'ve iterated through all of them, and also we\\nneed to know which diagonal is next. For that purpose we will pass the indices\\nof the first cell on the diagonal. That way we can always tell how to move forward.\\n\\nWe will start by updating the `begin` and `end` to reflect our choice accordingly.\\n\\n```cpp\\ndiagonals_iter begin() { return diagonals_iter { _matrix, 0, 0 }; }\\ndiagonals_iter end() { return diagonals_iter { _matrix, 0, _matrix.size() }; }\\n```\\n\\nFor the `begin` we return the first diagonal that starts at `(0, 0)`. And because\\nwe have decided to do the diagonals in the first column at the end, the first\\ndiagonal that is not a valid one is the one at `(0, height)`. Apart from the\\nindices, we also need to pass reference to the matrix itself.\\n\\n:::note\\n\\nYou may have noticed that we also include the diagonals that have length 1,\\nspecifically the ones at `(0, height - 1)` and `(width - 1, 0)`. We are implementing\\nan iterator that **should not** care about the way it\'s being used. Therefore, we\\ndon\'t care about the fact they don\'t need to be sorted.\\n\\n:::\\n\\nCool, let\'s leave the iterator itself to someone else, right?[^4]\\n\\n### Implementing the iterator over diagonals\\n\\nWe can start with a simple skeleton based on the information that we pass from\\nthe `diagonals`. Also to utilize the `matrix_t` and also contain implementation\\ndetails hidden away, we will put this code into the `diagonals` class.\\n\\n```cpp\\nclass diagonals_iter {\\n matrix_t& m;\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)\\n : m(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n};\\n```\\n\\nIn this case we will be implementing a \u201csimple\u201d forward iterator, so we don\'t\\nneed to implement a lot. Notably it will be:\\n* inequality operator (we need to know when we reach the end and have nothing to\\n iterate over)\\n* preincrementation operator (we need to be able to move around the iterable)\\n* dereference operator (we need to be able to retrieve the objects we iterate\\n over)\\n\\n```cpp\\nclass diagonals_iter {\\n matrix_t& m;\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)\\n : m(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n\\n bool operator!=(const diagonals_iter& rhs) const\\n {\\n // iterators are not equal if they reference different matrices, or\\n // their positions differ\\n return m != rhs.m || x != rhs.x || y != rhs.y;\\n }\\n\\n diagonals_iter& operator++()\\n {\\n if (y != 0) {\\n // iterating through diagonals down the first column\\n y++;\\n return *this;\\n }\\n\\n // iterating the diagonals along the first row\\n x++;\\n if (x == m.front().size()) {\\n // switching to diagonals in the first column\\n x = 0;\\n y++;\\n }\\n\\n return *this;\\n }\\n\\n diagonal operator*() const { return diagonal { m, x, y }; }\\n};\\n```\\n\\nLet\'s go one-by-one. Inequality operator is rather simple, just compare iterator\'s\\nattributes field-by-field. If you think about it, checking inequality of two 2D\\nvectors may be a bit inefficient, therefore, we can swap around and check it as\\na last thing.\\n\\n```diff\\n- return m != rhs.m || x != rhs.x || y != rhs.y;\\n+ return x != rhs.x || y != rhs.y || m != rhs.m;\\n```\\n\\nPreincrementation is where the magic happens. If you have a better look, you can\\nsee two branches of this operation:\\n\\n1. When `y != 0` (we\'re iterating over the diagonals in the first column)\\n In this case, we just bump the row and we\'re done.\\n2. When `y == 0` (we\'re iterating over the diagonals in the first row)\\n In this case, we bump the column and check if we haven\'t gotten out of bounds,\\n i.e. the end of the first row. If we get out of the bounds, we\'re continuing\\n with the second diagonal in the first column.\\n\\nDereferencing the iterator must \u201cyield\u201d something. In our case it will be the\\ndiagonal that we want to sort. For sorting we need just the iterators that can\\nmove around said diagonal. The simplest thing, we can do, is to delegate it to\\nsomething else. In our case it will be a class called `diagonal`.\\n\\n## Implementing the `diagonal` itself\\n\\nAfter implementing the iterator over diagonals, we know that all we need to describe\\na diagonal is the matrix itself and the \u201cstart\u201d of the diagonal (row and column).\\nAnd we also know that the diagonal must provide some iterators for the `std::sort`\\nfunction. We can start with the following skeleton:\\n```cpp\\ntemplate \\nclass diagonal {\\n using matrix_t = std::vector>;\\n\\n matrix_t& matrix;\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n diagonal(matrix_t& matrix, std::size_t x, std::size_t y)\\n : matrix(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n\\n diagonal_iter begin() const { return diagonal_iter { matrix, x, y }; }\\n\\n diagonal_iter end() const\\n {\\n auto max_x = matrix[y].size();\\n auto max_y = matrix.size();\\n\\n // we need to find the distance in which we get out of bounds (either in\\n // column or row)\\n auto steps = std::min(max_x - x, max_y - y);\\n\\n return diagonal_iter { matrix, x + steps, y + steps };\\n }\\n};\\n```\\n\\nInitialization is rather simple, we just \u201ckeep\u201d the stuff we get, `begin` is the\\nsimplest, we just delegate.\\n\\nIn case of the `end`, it gets more complicated. We need to know where is the \u201cend\u201d\\nof the diagonal. Since `end` should point to the first element \u201cafter\u201d the iterable,\\nwe know that it\'s the first position of the iterator where either `y` becomes\\n`matrix.size()` or `x` becomes `matrix[y].size()`. Also we are moving along diagonal,\\nduh, therefore we can deduce the first \u201cposition\u201d afterwards by minimal amount of\\nsteps to get out of the any column or row, hence `std::min(max_x - x, max_y - y)`.\\nFinal position is then computed simply by adding the steps to the beginning of\\nthe diagonal.\\n\\nNow we just need to finish the iterator for the diagonal itself and we\'re done.\\n\\n### Implementing `diagonal_iter`\\n\\nThis part is the hardest from all we need to do. It\'s because of the requirements\\nof the `std::sort` that requires us to implement a _random access iterator_. I have\\nbriefly described it above, and \u201cin a nutshell\u201d it means that we need to implement\\nan iterator that can move in constant time along the diagonal in any amount of\\nsteps.\\n\\nLet\'s go through all of the functionality that our iterator needs to support to\\nbe used in `std::sort`. We need the usual operations like:\\n\\n* equality/inequality\\n* incrementation\\n* dereferencing\\n\\nWe will also add all the types that our iterator uses with the category of the\\niterator, i.e. what interface it supports:\\n```cpp\\nclass diagonal_iter {\\n // we need to keep reference to the matrix itself\\n matrix_t& m;\\n\\n // we need to be able to tell our current position\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n using difference_type = std::ptrdiff_t;\\n using value_type = T;\\n using pointer = T*;\\n using reference = T&;\\n using iterator_category = std::random_access_iterator_tag;\\n\\n diagonal_iter(matrix_t& matrix,\\n std::size_t x,\\n std::size_t y)\\n : m(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n\\n bool operator==(const diagonal_iter& rhs) const\\n {\\n return x == rhs.x && y == rhs.y && m == rhs.m;\\n }\\n\\n diagonal_iter& operator++()\\n {\\n // we are moving along the diagonal, so we increment both \u2039x\u203a and \u2039y\u203a at\\n // the same time\\n x++;\\n y++;\\n return *this;\\n }\\n\\n reference operator*() const { return m[y][x]; }\\n};\\n```\\n\\nThis is pretty similar to the previous iterator, but now we need to implement the\\nremaining requirements of the _random access iterator_. Let\'s see what those are:\\n\\n* decrementation - cause we need to be able to move backwards too, since _random _\\n _access iterator_ extends the interface of _bidirectional iterator_\\n* moving the iterator in either direction by steps given as an integer\\n* being able to tell the distance between two iterators\\n* define an ordering on the iterators\\n\\nLet\'s fill them in:\\n```cpp\\nclass diagonal_iter {\\n // we need to keep reference to the matrix itself\\n matrix_t& m;\\n\\n // we need to be able to tell our current position\\n std::size_t x;\\n std::size_t y;\\n\\npublic:\\n using difference_type = std::ptrdiff_t;\\n using value_type = T;\\n using pointer = T*;\\n using reference = T&;\\n using iterator_category = std::random_access_iterator_tag;\\n\\n diagonal_iter(matrix_t& matrix,\\n std::size_t x,\\n std::size_t y)\\n : m(matrix)\\n , x(x)\\n , y(y)\\n {\\n }\\n\\n bool operator==(const diagonal_iter& rhs) const\\n {\\n return x == rhs.x && y == rhs.y && m == rhs.m;\\n }\\n\\n diagonal_iter& operator++()\\n {\\n // we are moving along the diagonal, so we increment both \u2039x\u203a and \u2039y\u203a at\\n // the same time\\n x++;\\n y++;\\n return *this;\\n }\\n\\n reference operator*() const { return m[y][x]; }\\n\\n // exactly opposite to the incrementation\\n diagonal_iter operator--()\\n {\\n x--;\\n y--;\\n return *this;\\n }\\n\\n // moving \u2039n\u203a steps back is same as calling decrementation \u2039n\u203a-times, so we\\n // can just return a new iterator and subtract \u2039n\u203a from both coordinates in\\n // the matrix\\n diagonal_iter operator-(difference_type n) const\\n {\\n return diagonal_iter { m, x - n, y - n };\\n }\\n\\n // here we assume that we are given two iterators on the same diagonal\\n difference_type operator-(const diagonal_iter& rhs) const\\n {\\n assert(m == rhs.m);\\n return x - rhs.x;\\n }\\n\\n // counterpart of moving \u2039n\u203a steps backwards\\n diagonal_iter operator+(difference_type n) const\\n {\\n return diagonal_iter { m, x + n, y + n };\\n }\\n\\n // we compare the coordinates, and also assume that those 2 iterators are\\n // lying on the same diagonal\\n bool operator<(const diagonal_iter& rhs) const\\n {\\n assert(m == rhs.m);\\n return x < rhs.x && y < rhs.y;\\n }\\n};\\n```\\n\\nAt this point we could probably try and compile it, right? If we do so, we will\\nget yelled at by a compiler for the following reasons:\\n```\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type \'diagonal::diagonal_iter\' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\\n __last = __next;\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1817:11: note: in instantiation of function template specialization \'std::__unguarded_linear_insert::diagonal_iter, __gnu_cxx::__ops::_Val_less_iter>\' requested here\\n std::__unguarded_linear_insert(__i,\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1849:9: note: in instantiation of function template specialization \'std::__insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__insertion_sort(__first, __first + int(_S_threshold), __comp);\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization \'std::__final_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__final_insertion_sort(__first, __last, __comp);\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization \'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\\n ^\\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization \'std::sort::diagonal_iter>\' requested here\\n std::sort(d.begin(), d.end());\\n ^\\nmatrix-sort.cpp:17:19: note: copy assignment operator of \'diagonal_iter\' is implicitly deleted because field \'m\' is of reference type \'diagonal::matrix_t &\' (aka \'vector> &\')\\n matrix_t& m;\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1830:2: error: no matching function for call to \'__unguarded_linear_insert\' [clang-diagnostic-error]\\n std::__unguarded_linear_insert(__i,\\n ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1850:9: note: in instantiation of function template specialization \'std::__unguarded_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__unguarded_insertion_sort(__first + int(_S_threshold), __last,\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization \'std::__final_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__final_insertion_sort(__first, __last, __comp);\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization \'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\\n ^\\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization \'std::sort::diagonal_iter>\' requested here\\n std::sort(d.begin(), d.end());\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1782:5: note: candidate template ignored: substitution failure [with _RandomAccessIterator = diagonal::diagonal_iter, _Compare = __gnu_cxx::__ops::_Val_less_iter]\\n __unguarded_linear_insert(_RandomAccessIterator __last,\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1923:11: error: object of type \'diagonal::diagonal_iter\' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\\n __last = __cut;\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1937:9: note: in instantiation of function template specialization \'std::__introsort_loop::diagonal_iter, long, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__introsort_loop(__first, __last,\\n ^\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization \'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>\' requested here\\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\\n ^\\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization \'std::sort::diagonal_iter>\' requested here\\n std::sort(d.begin(), d.end());\\n ^\\nmatrix-sort.cpp:17:19: note: copy assignment operator of \'diagonal_iter\' is implicitly deleted because field \'m\' is of reference type \'diagonal::matrix_t &\' (aka \'vector> &\')\\n matrix_t& m;\\n ^\\n```\\n\\nThat\'s a lot of noise, isn\'t it? Let\'s focus on the important parts:\\n```\\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type \'diagonal::diagonal_iter\' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\\n\u2026\\nmatrix-sort.cpp:17:19: note: copy assignment operator of \'diagonal_iter\' is implicitly deleted because field \'m\' is of reference type \'diagonal::matrix_t &\' (aka \'vector> &\')\\n matrix_t& m;\\n ^\\n```\\n\\nAh! We have a reference in our iterator, and this prevents us from having a copy\\nassignment operator (that is used \u201csomewhere\u201d in the sorting algorithm). Well\u2026\\nLet\'s just wrap it!\\n```diff\\n# we need to keep a different type than reference\\n- matrix_t& m;\\n+ std::reference_wrapper m;\\n\\n# in comparison we need to get the reference out of the wrapper first\\n- return x == rhs.x && y == rhs.y && m == rhs.m;\\n+ return x == rhs.x && y == rhs.y && m.get() == rhs.m.get();\\n\\n# same when we return a reference to the \u201ccell\u201d in the matrix\\n- reference operator*() const { return m[y][x]; }\\n+ reference operator*() const { return m.get()[y][x]; }\\n\\n# and finally in the assertions that we set for the \u201cdistance\u201d and \u201cless than\u201d\\n- assert(m == rhs.m);\\n+ assert(m.get() == rhs.m.get());\\n```\\n\\nWe\'re done now! We have written an iterator over diagonals for a 2D `vector`. You can have a look at the final result [here](pathname:///files/blog/leetcode/sort-matrix-diagonally/matrix-sort.cpp).\\n\\n[^1]: just because I\'m used to it and don\'t care about your opinion ;)\\n[^2]: exercise at your own risk\\n[^3]: me in 5 minutes in fact, but don\'t make me scared\\n[^4]: me in the next section\u2026"},{"id":"aoc-2022/2nd-week","metadata":{"permalink":"/blog/aoc-2022/2nd-week","editUrl":"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/02-week-2.md","source":"@site/blog/aoc-2022/02-week-2.md","title":"2nd week of Advent of Code \'22 in Rust","description":"Surviving second week in Rust.","date":"2022-12-25T23:15:00.000Z","formattedDate":"December 25, 2022","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":20.875,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"2nd week of Advent of Code \'22 in Rust","description":"Surviving second week in Rust.","date":"2022-12-25T23:15","slug":"aoc-2022/2nd-week","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"Sort the matrix diagonally","permalink":"/blog/leetcode/sort-diagonally"},"nextItem":{"title":"1st week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/1st-week"}},"content":"Let\'s go through the second week of [_Advent of Code_] in Rust.\\n\\n\x3c!--truncate--\x3e\\n\\n## [Day 8: Treetop Tree House](https://adventofcode.com/2022/day/8)\\n\\n:::info tl;dr\\n\\nWe get a forest and we want to know how many trees are visible from the outside.\\nApart from that we want to find the best view.\\n\\n:::\\n\\nNothing interesting. We are moving around 2D map though. And indexing can get a\\nbit painful when doing so, let\'s refactor it a bit ;) During the preparation for\\nthe AoC, I have written `Vector2D` and now it\'s time to extend it with indexing\\nof `Vec` of `Vec`s. In my solution I was manipulating with indices in the following\\nway:\\n\\n- swapping them\\n- checking whether they are correct indices for the `Vec>`\\n- indexing `Vec>` with them\\n\\n:::caution\\n\\nI\'m getting familiar with Rust and starting to \u201cabuse\u201d it\u2026 While doing so, I\'m\\nalso uncovering some \u201cfeatures\u201d that I don\'t really like. Therefore I will mark\\nall of my rants with _thicc_ **\xab\u21af\xbb** mark and will try to \u201clock\u201d them into their\\nown \u201cbox of hell\u201d.\\n\\n:::\\n\\n#### Swapping indices\\n\\nRelatively simple implementation, just take the values, swap them and return new\\nvector.\\n\\n```rust\\nimpl Vector2D {\\n pub fn swap(&self) -> Self {\\n Self {\\n x: self.y,\\n y: self.x,\\n }\\n }\\n}\\n```\\n\\nPretty straight-forward implementation, but let\'s talk about the `T: Copy`. We\\nneed to use it, since we are returning a **new** vector, with swapped **values**.\\nIf we had values that cannot be copied, the only thing we could do, would be a\\nvector of references (and it would also introduce a lifetime, to which we\'ll get\\nlater on). This is pretty similar with the operations on sets from the first week.\\n\\n#### Indexing `Vec`\\n\\nI will start with the indexing, cause bound-checking is a bit more\u2026 complicated\\nthan I would like to.\\n\\n```rust\\npub fn index<\'a, T, U>(v: &\'a [Vec], idx: &Vector2D) -> &\'a U\\nwhere\\n usize: TryFrom,\\n >::Error: Debug,\\n T: Copy,\\n{\\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\\n &v[y][x]\\n}\\n```\\n\\nLet\'s talk about this mess\u2026 Body of the function is probably the most easy part\\nand should not be hard to understand, we just take the `x` and `y` and convert\\nthem both to `usize` type that can be used later on for indexing.\\n\\nThe type signature of the function is where the fun is at :wink: We are trying\\nto convert unknown type to `usize`, so we must bound the `T` as a type that can\\nbe converted to `usize`, that\'s how we got `usize: TryFrom` which basically\\nsays that `usize` must implement `TryFrom` trait and therefore allows us to\\nconvert the indices to actual `usize` indices. Using `.unwrap()` also forces us\\nto bound the error that can occur when converting `T` into `usize`, that\'s how\\nwe get `>::Error: Debug` which loosely means\\n\\n> error during conversion of `T` into `usize` must implement `Debug`,\\n> i.e. can be printed in some way or other\\n\\n`T: Copy` is required by `.try_into()` which takes `T` by-value.\\n\\nAnd now we are left only with the first line of the definition.\\n\\n:::note\\n\\nSkilled Rustaceans might notice that this implementation is rather flaky and can\\nbreak in multiple places at once. I\'ll get back to it\u2026\\n\\n:::\\n\\nLet\'s split it in multiple parts:\\n- `v: &\'a [Vec]` represents the 2D `Vec`, we are indexing, `Vec` implements\\n `Slice` trait and _clippy_ recommends using `&[T]` to `&Vec`, exact details\\n are unknown to me\\n- `idx: &Vector2D` represents the _indices_ which we use, we take them by\\n reference to avoid an unnecessary copy\\n- `-> &\'a U` means that we are returning a _reference_ to some value of type `U`.\\n Now the question is what does the `\'a` mean, we can also see it as a generic\\n type declared along `T` and `U`. And the answer is _relatively_ simple, `\'a`\\n represents a _lifetime_. We take the `v` by a reference and return a reference,\\n borrow checker validates all of the _borrows_ (or references), so we need to\\n specify that our returned value has _the same lifetime_ as the vector we have\\n taken by a reference, i.e. returned reference must live at least as long as the\\n `v`. This way we can \u201cbe sure\u201d that the returned reference is valid.\\n\\n##### Issues\\n\\nFirst issue that our implementation has is the fact that we cannot get a mutable\\nreference out of that function. This could be easily resolved by introducing new\\nfunction, e.g. `index_mut`. Which I have actually done while writing this part:\\n```rust\\npub fn index_mut<\'a, T, U>(v: &\'a mut [Vec], idx: &Vector2D) -> &\'a mut U\\nwhere\\n usize: TryFrom,\\n >::Error: Debug,\\n T: Copy,\\n{\\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\\n &mut v[y][x]\\n}\\n```\\n\\n:::caution **\xab\u21af\xbb** Why can\'t we use one function?\\n\\nWhen we consider a `Vec`, we don\'t need to consider containers as `T`, Rust\\nimplements indexing as traits `Index` and `IndexMut` that do the dirty work\\nbehind syntactic sugar of `container[idx]`.\\n\\nHowever, implementing of traits is not allowed for _external_ types, i.e. types\\nthat you haven\'t defined yourself. This means that you can implement indexing\\nover containers that you have implemented yourself, but you cannot use your own\\ntypes for indexing \u201cbuilt-in\u201d types.\\n\\nAnother part of this rabbit hole is trait `SliceIndex` that is of a relevance\\nbecause of\\n```rust\\nimpl Index for [T]\\nwhere\\n I: SliceIndex<[T]>\\n\\nimpl Index for Vec\\nwhere\\n I: SliceIndex<[T]>,\\n A: Allocator\\n\\nimpl Index for [T; N]\\nwhere\\n [T]: Index\\n```\\n\\nIn other words, if your type implements `SliceIndex` trait, it can be used\\nfor indexing. As of now, this trait has all of its required methods experimental\\nand is marked as `unsafe`.\\n\\n:::\\n\\nAnother problem is a requirement for indexing either `[Vec]` or `Vec>`.\\nThis requirement could be countered by removing inner type `Vec` and constraining\\nit by a trait `Index` (or `IndexMut` respectively) in a following way\\n```rust\\npub fn index<\'a, C, T>(v: &\'a [C], idx: &Vector2D) -> &\'a C::Output\\nwhere\\n usize: TryFrom,\\n >::Error: Debug,\\n T: Copy,\\n C: Index\\n{\\n let (x, y): (usize, usize) = (idx.x.try_into().unwrap(), idx.y.try_into().unwrap());\\n &v[y][x]\\n}\\n```\\n\\nGiven this, we can also give a more meaningful typename for indexing type, such\\nas `I`.\\n\\n#### Checking bounds\\n\\nNow we can get to the boundary checks, it is very similar, but a more\u2026 dirty.\\nFirst approach that came up was to convert the indices in `Vector2D` to `usize`,\\nbut when you add the indices up, e.g. when checking the neighbors, you can end\\nup with negative values which, unlike in C++, causes an error (instead of underflow\\nthat you can use to your advantage; you can easily guess how).\\n\\nSo how can we approach this then? Well\u2026 we will convert the bounds instead of\\nthe indices and that lead us to:\\n```rust\\npub fn in_range(v: &[Vec], idx: &Vector2D) -> bool\\nwhere\\n usize: TryInto,\\n >::Error: Debug,\\n T: PartialOrd + Copy,\\n{\\n idx.y >= 0.try_into().unwrap()\\n && idx.y < v.len().try_into().unwrap()\\n && idx.x >= 0.try_into().unwrap()\\n && idx.x\\n < v[TryInto::::try_into(idx.y).unwrap()]\\n .len()\\n .try_into()\\n .unwrap()\\n}\\n```\\n\\nYou can tell that it\'s definitely a shitty code. Let\'s improve it now! We will\\nget back to the original idea, but do it better. We know that we cannot convert\\nnegative values into `usize`, **but** we also know that conversion like that\\nreturns a `Result` which we can use to our advantage.\\n```rust\\npub fn in_range(v: &[Vec], idx: &Vector2D) -> bool\\nwhere\\n T: Copy,\\n usize: TryFrom,\\n{\\n usize::try_from(idx.y)\\n .and_then(|y| usize::try_from(idx.x).map(|x| y < v.len() && x < v[y].len()))\\n .unwrap_or(false)\\n}\\n```\\n\\n`Result` is a type similar to `Either` in Haskell and it allows us to chain\\nmultiple operations on correct results or propagate the original error without\\ndoing anything. Let\'s dissect it one-by-one.\\n\\n`try_from` is a method implemented in `TryFrom` trait, that allows you to convert\\ntypes and either successfully convert them or fail (with a reasonable error). This\\nmethod returns `Result`.\\n\\nWe call `and_then` on that _result_, let\'s have a look at the type signature of\\n`and_then`, IMO it explains more than enough:\\n```rust\\npub fn and_then(self, op: F) -> Result\\nwhere\\n F: FnOnce(T) -> Result\\n```\\n\\nOK\u2026 So it takes the result and a function and returns another result with\\ndifferent value and different error. However we can see that the function, which\\nrepresents an operation on a result, takes just the value, i.e. it doesn\'t care\\nabout any previous error. To make it short:\\n\\n> `and_then` allows us to run an operation, which can fail, on the correct result\\n\\nWe parsed a `y` index and now we try to convert the `x` index with `try_from`\\nagain, but on that result we use `map` rather than `and_then`, why would that be?\\n\\n```rust\\npub fn map(self, op: F) -> Result\\nwhere\\n F: FnOnce(T) -> U\\n```\\n\\nHuh\u2026 `map` performs an operation that **cannot** fail. And finally we use\\n`unwrap_or` which takes the value from result, or in case of an error returns the\\ndefault that we define.\\n\\nHow does this work then? If `y` is negative, the conversion fails and the error\\npropagates all the way to `unwrap_or`, if `y` can be a correct `usize` value, then\\nwe do the same with `x`. If `x` is negative, we propagate the error as with `y`,\\nand if it\'s not, then we check whether it exceeds the higher bounds or not.\\n\\n### Solution\\n\\nRelatively simple, you just need follow the rules and not get too smart, otherwise\\nit will get back at you.\\n\\n## [Day 9: Rope Bridge](https://adventofcode.com/2022/day/9)\\n\\n:::info tl;dr\\n\\nWe get a rope with knots and we want to track how many different positions are\\nvisited with the rope\'s tail.\\n\\n:::\\n\\nBy this day, I have come to a conclusion that current skeleton for each day\\ngenerates a lot of boilerplate. And even though it can be easily copied, it\'s\\njust a waste of space and unnecessary code. Let\'s \u201csimplify\u201d this (on one end\\nwhile creating monster on the other end). I\'ve gone through what we need in the\\npreparations for the AoC. Let\'s sum up our requirements:\\n- parsing\\n- part 1 & 2\\n- running on sample / input\\n- tests\\n\\nParsing and implementation of both parts is code that changes each day and we\\ncannot do anything about it. However running and testing can be simplified!\\n\\nLet\'s introduce and export a new module `solution` that will take care of all of\\nthis. We will start by introducing a trait for each day.\\n```rust\\npub trait Solution {\\n fn parse_input>(pathname: P) -> Input;\\n\\n fn part_1(input: &Input) -> Output;\\n fn part_2(input: &Input) -> Output;\\n}\\n```\\n\\nThis does a lot of work for us already, we have defined a trait and for each day\\nwe will create a structure representing a specific day. That structure will also\\nimplement the `Solution` trait.\\n\\nNow we need to get rid of the boilerplate, we can\'t get rid of the `main` function,\\nbut we can at least move out the functionality.\\n```rust\\nfn run(type_of_input: &str) -> Result<()>\\nwhere\\n Self: Sized,\\n{\\n tracing_subscriber::fmt()\\n .with_env_filter(EnvFilter::from_default_env())\\n .with_target(false)\\n .with_file(true)\\n .with_line_number(true)\\n .without_time()\\n .compact()\\n .init();\\n color_eyre::install()?;\\n\\n let input = Self::parse_input(format!(\\"{}s/{}.txt\\", type_of_input, Self::day()));\\n\\n info!(\\"Part 1: {}\\", Self::part_1(&input));\\n info!(\\"Part 2: {}\\", Self::part_2(&input));\\n\\n Ok(())\\n}\\n\\nfn main() -> Result<()>\\nwhere\\n Self: Sized,\\n{\\n Self::run(\\"input\\")\\n}\\n```\\n\\nThis is all part of the `Solution` trait, which can implement methods while being\\ndependent on what is provided by the implementing types. In this case, we just\\nneed to bound the `Output` type to implement `Display` that is necessary for the\\n`info!` and format string there.\\n\\nNow we can get to first of the nasty things we are going to do\u2026 And it is the\\n`day()` method that you can see being used when constructing path to the input\\nfile. That method will generate a name of the file, e.g. `day01` and we know that\\nwe can _somehow_ deduce it from the structure name, given we name it reasonably.\\n\\n```rust\\nfn day() -> String {\\n let mut day = String::from(type_name::().split(\\"::\\").next().unwrap());\\n day.make_ascii_lowercase();\\n\\n day.to_string()\\n}\\n```\\n\\n:::caution `type_name`\\n\\nThis feature is still experimental and considered to be internal, it is not\\nadvised to use it any production code.\\n\\n:::\\n\\nAnd now we can get to the nastiest stuff :weary: We will **generate** the tests!\\n\\nWe want to be able to generate tests for sample input in a following way:\\n```rust\\ntest_sample!(day_01, Day01, 42, 69);\\n```\\n\\nThere\'s not much we can do, so we will write a macro to generate the tests for us.\\n\\n```rust\\n#[macro_export]\\nmacro_rules! test_sample {\\n ($mod_name:ident, $day_struct:tt, $part_1:expr, $part_2:expr) => {\\n #[cfg(test)]\\n mod $mod_name {\\n use super::*;\\n\\n #[test]\\n fn test_part_1() {\\n let sample =\\n $day_struct::parse_input(&format!(\\"samples/{}.txt\\", $day_struct::day()));\\n assert_eq!($day_struct::part_1(&sample), $part_1);\\n }\\n\\n #[test]\\n fn test_part_2() {\\n let sample =\\n $day_struct::parse_input(&format!(\\"samples/{}.txt\\", $day_struct::day()));\\n assert_eq!($day_struct::part_2(&sample), $part_2);\\n }\\n }\\n };\\n}\\n```\\n\\nWe have used it in a similar way as macros in C/C++, one of the things that we\\ncan use to our advantage is defining \u201ctype\u201d of the parameters for the macro. All\\nparameters have their name prefixed with `$` sign and you can define various \u201cforms\u201d\\nof your macro. Let\'s go through it!\\n\\nWe have following parameters:\\n- `$mod_name` which represents the name for the module with tests, it is typed\\n with `ident` which means that we want a valid identifier to be passed in.\\n- `$day_struct` represents the structure that will be used for tests, it is typed\\n with `tt` which represents a _token tree_, in our case it is a type.\\n- `$part_X` represents the expected output for the `X`th part and is of type `expr`\\n which literally means an _expression_.\\n\\nApart from that we need to use `#[macro_export]` to mark the macro as exported\\nfor usage outside of the module. Now our skeleton looks like:\\n```rust\\nuse aoc_2022::*;\\n\\ntype Input = String;\\ntype Output = String;\\n\\nstruct DayXX;\\nimpl Solution for DayXX {\\n fn parse_input>(pathname: P) -> Input {\\n file_to_string(pathname)\\n }\\n\\n fn part_1(input: &Input) -> Output {\\n todo!()\\n }\\n\\n fn part_2(input: &Input) -> Output {\\n todo!()\\n }\\n}\\n\\nfn main() -> Result<()> {\\n // DayXX::run(\\"sample\\")\\n DayXX::main()\\n}\\n\\n// test_sample!(day_XX, DayXX, , );\\n```\\n\\n### Solution\\n\\nNot much to talk about, it is relatively easy to simulate.\\n\\n## [Day 10: Cathode-Ray Tube](https://adventofcode.com/2022/day/10)\\n\\n:::info tl;dr\\n\\nEmulating basic arithmetic operations on a CPU and drawing on CRT based on the\\nCPU\'s accumulator.\\n\\n:::\\n\\nIn this day I have discovered an issue with my design of the `Solution` trait.\\nAnd the issue is caused by different types of `Output` for the part 1 and part 2.\\n\\nProblem is relatively simple and consists of simulating a CPU, I have approached\\nit in a following way:\\n```rust\\nfn evaluate_instructions(instructions: &[Instruction], mut out: Output) -> Output {\\n instructions\\n .iter()\\n .fold(State::new(), |state, instruction| {\\n state.execute(instruction, &mut out)\\n });\\n\\n out\\n}\\n```\\n\\nWe just take the instructions, we have some state of the CPU and we execute the\\ninstructions one-by-one. Perfect usage of the `fold` (or `reduce` as you may know\\nit from other languages).\\n\\nYou can also see that we have an `Output` type, so the question is how can we fix\\nthat problem. And the answer is very simple and _functional_. Rust allows you to\\nhave an `enumeration` that can _bear_ some other values apart from the type itself.\\n\\n:::tip\\n\\nWe could\'ve seen something like this with the `Result` type that can be\\ndefined as\\n```rust\\nenum Result {\\n Ok(T),\\n Err(E)\\n}\\n```\\n\\n###### What does that mean though?\\n\\nWhen we have an `Ok` value, it has the result itself, and when we get an `Err`\\nvalue, it has the error. This also allows us to handle _results_ in a rather\\npretty way:\\n```rust\\nmatch do_something(x) {\\n Ok(y) => {\\n println!(\\"SUCCESS: {}\\", y);\\n },\\n Err(y) => {\\n eprintln!(\\"ERROR: {}\\", y);\\n }\\n}\\n```\\n\\n:::\\n\\nMy solution has a following outline:\\n```rust\\nfn execute(&self, i: &Instruction, output: &mut Output) -> State {\\n // execute the instruction\\n\\n // collect results if necessary\\n match output {\\n Output::Part1(x) => self.execute_part_1(y, x),\\n Output::Part2(x) => self.execute_part_2(y, x),\\n }\\n\\n // return the obtained state\\n new_state\\n}\\n```\\n\\nYou might think that it\'s a perfectly reasonable thing to do. Yes, **but** notice\\nthat the `match` statement doesn\'t _collect_ the changes in any way and also we\\npass `output` by `&mut`, so it is shared across each _iteration_ of the `fold`.\\n\\nThe dirty and ingenious thing is that `x`s are passed by `&mut` too and therefore\\nthey are directly modified by the helper functions. To sum it up and let it sit\\n\\n> We are **collecting** the result **into** an **enumeration** that is **shared**\\n> across **all** iterations of `fold`.\\n\\n### Solution\\n\\nSimilar to _Day 9_, but there are some technical details that can get you.\\n\\n## [Day 11: Monkey in the Middle](https://adventofcode.com/2022/day/11)\\n\\n:::info tl;dr\\n\\nSimulation of monkeys throwing stuff around and measuring your stress levels\\nwhile your stuff is being passed around.\\n\\n:::\\n\\nI think I decided to use regular expressions here for the first time, cause\\nparsing the input was a pain.\\n\\nAlso I didn\'t expect to implement Euclidean algorithm in Rust\u2026\\n\\n### Solution\\n\\nAgain, we\'re just running a simulation. Though I must admit it was very easy to\\nmake a small technical mistakes that could affect the final results very late.\\n\\n## [Day 12: Hill Climbing Algorithm](https://adventofcode.com/2022/day/12)\\n\\n:::info tl;dr\\n\\nFinding shortest path up the hill and also shortest path down to the ground while\\nalso rolling down the hill\u2026\\n\\n:::\\n\\nAs I have said in the _tl;dr_, we are looking for the shortest path, but the start\\nand goal differ for the part 1 and 2. So I have decided to refactor my solution\\nto a BFS algorithm that takes necessary parameters via functions:\\n```rust\\nfn bfs(\\n graph: &[Vec], start: &Position, has_edge: F, is_target: G\\n) -> Option\\nwhere\\n F: Fn(&[Vec], &Position, &Position) -> bool,\\n G: Fn(&[Vec], &Position) -> bool\\n```\\n\\nWe pass the initial vertex from the caller and everything else is left to the BFS\\nalgorithm, based on the `has_edge` and `is_target` functions.\\n\\nThis was easy! And that is not very usual in Rust once you want to pass around\\nfunctions. :eyes:\\n\\n### Solution\\n\\nLooking for the shortest path\u2026 Must be Dijkstra, right? **Nope!** Half of the\\nReddit got jebaited though. In all fairness, nothing stops you from implementing\\nthe Dijkstra\'s algorithm for finding the shortest path, **but** if you know that\\nall connected vertices are in a unit (actually $d = 1$) distance from each other,\\nthen you know that running Dijkstra is equivalent to running BFS, only with worse\\ntime complexity, because of the priority heap instead of the queue.\\n\\n## [Day 13: Distress Signal](https://adventofcode.com/2022/day/13)\\n\\n:::info tl;dr\\n\\nProcessing packets with structured data from the distress signal.\\n\\n:::\\n\\nYou can implement a lot of traits if you want to. It is _imperative_ to implement\\nordering on the packets. I had a typo, so I also proceeded to implement a `Display`\\ntrait for debugging purposes:\\n```rust\\nimpl Display for Packet {\\n fn fmt(&self, f: &mut std::fmt::Formatter<\'_>) -> std::fmt::Result {\\n match self {\\n Packet::Integer(x) => write!(f, \\"{x}\\"),\\n Packet::List(lst) => write!(f, \\"[{}]\\", lst.iter().map(|p| format!(\\"{p}\\")).join(\\",\\")),\\n }\\n }\\n}\\n```\\n\\n### Solution\\n\\nA lot of technical details\u2026 Parsing is nasty too\u2026\\n\\n## [Day 14: Regolith Reservoir](https://adventofcode.com/2022/day/14)\\n\\n:::info tl;dr\\n\\nLet\'s simulate falling sand grain-by-grain.\\n\\n:::\\n\\nAgain, both parts are relatively similar with minimal changes, so it is a good\\nidea to refactor it a bit. Similar approach to the [BFS above]. Also this is the\\nfirst day where I ran into efficiency issues and had to redo my solution to speed\\nit up just a bit.\\n\\n### Solution\\n\\nTedious.\\n\\n## Post Mortem\\n\\n### Indexing\\n\\nI was asked about the indexing after publishing the blog. And truly it is rather\\ncomplicated topic, especially after releasing `SliceIndex` trait. I couldn\'t\\nleave it be, so I tried to implement the `Index` and `IndexMut` trait.\\n\\n:::note\\n\\nI have also mentioned that the `SliceIndex` trait is `unsafe`, but truth be told,\\nonly _unsafe_ part are the 2 methods that are named `*unchecked*`. Anyways, I will\\nbe implementing the `Index*` traits for now, rather than the `SliceIndex`.\\n\\n:::\\n\\nIt\'s relatively straightforward\u2026\\n\\n```rust\\nimpl Index> for [C]\\nwhere\\n I: Copy + TryInto,\\n >::Error: Debug,\\n C: Index,\\n{\\n type Output = C::Output;\\n\\n fn index(&self, index: Vector2D) -> &Self::Output {\\n let (x, y): (usize, usize) =\\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\\n &self[y][x]\\n }\\n}\\n\\nimpl IndexMut> for [C]\\nwhere\\n I: Copy + TryInto,\\n >::Error: Debug,\\n C: IndexMut,\\n{\\n fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output {\\n let (x, y): (usize, usize) =\\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\\n &mut self[y][x]\\n }\\n}\\n```\\n\\nWe can see a lot of similarities to the implementation of `index` and `index_mut`\\nfunctions. In the end, they are 1:1, just wrapped in the trait that provides a\\nsyntax sugar for `container[idx]`.\\n\\n:::note\\n\\nI have also switched from using the `TryFrom` to `TryInto` trait, since it better\\nmatches what we are using, the `.try_into` rather than `usize::try_from`.\\n\\nAlso implementing `TryFrom` automatically provides you with a `TryInto` trait,\\nsince it is relatively easy to implement. Just compare the following:\\n\\n```rust\\npub trait TryFrom: Sized {\\n type Error;\\n\\n fn try_from(value: T) -> Result;\\n}\\n\\npub trait TryInto: Sized {\\n type Error;\\n\\n fn try_into(self) -> Result;\\n}\\n```\\n\\n:::\\n\\nOK, so we have our trait implemented, we should be able to use `container[index]`,\\nright? Yes\u2026 but actually no :frowning:\\n\\n```\\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\\n --\x3e src/bin/day08.rs:26:18\\n |\\n26 | if trees[pos] > tallest {\\n | ^^^ slice indices are of type `usize` or ranges of `usize`\\n |\\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\\n\\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\\n --\x3e src/bin/day08.rs:30:28\\n |\\n30 | max(tallest, trees[pos])\\n | ^^^ slice indices are of type `usize` or ranges of `usize`\\n |\\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\\n\\nerror[E0277]: the type `[std::vec::Vec]` cannot be indexed by `aoc_2022::Vector2D`\\n --\x3e src/bin/day08.rs:52:28\\n |\\n52 | let max_height = trees[position];\\n | ^^^^^^^^ slice indices are of type `usize` or ranges of `usize`\\n |\\n = help: the trait `std::slice::SliceIndex<[std::vec::Vec]>` is not implemented for `aoc_2022::Vector2D`\\n = note: required for `std::vec::Vec>` to implement `std::ops::Index>`\\n```\\n\\nWhy? We have it implemented for the slices (`[C]`), why doesn\'t it work? Well,\\nthe fun part consists of the fact that in other place, where we were using it,\\nwe were passing the `&[Vec]`, but this is coming from a helper functions that\\ntake `&Vec>` instead. And\u2026 we don\'t implement `Index` and `IndexMut` for\\nthose. Just for the slices. :exploding_head: *What are we going to do about it?*\\n\\nWe can either start copy-pasting or be smarter about it\u2026 I choose to be smarter,\\nso let\'s implement a macro! The only difference across the implementations are\\nthe types of the outer containers. Implementation doesn\'t differ **at all**!\\n\\nImplementing the macro can be done in a following way:\\n```rust\\nmacro_rules! generate_indices {\\n ($container:ty) => {\\n impl Index> for $container\\n where\\n I: Copy + TryInto,\\n >::Error: Debug,\\n C: Index,\\n {\\n type Output = C::Output;\\n\\n fn index(&self, index: Vector2D) -> &Self::Output {\\n let (x, y): (usize, usize) =\\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\\n &self[y][x]\\n }\\n }\\n\\n impl IndexMut> for $container\\n where\\n I: Copy + TryInto,\\n >::Error: Debug,\\n C: IndexMut,\\n {\\n fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output {\\n let (x, y): (usize, usize) =\\n (index.x.try_into().unwrap(), index.y.try_into().unwrap());\\n &mut self[y][x]\\n }\\n }\\n };\\n}\\n```\\n\\nAnd now we can simply do\\n```rust\\ngenerate_indices!(VecDeque);\\ngenerate_indices!([C]);\\ngenerate_indices!(Vec);\\n// generate_indices!([C; N], const N: usize);\\n```\\n\\nThe last type (I took the inspiration from the implementations of the `Index` and\\n`IndexMut` traits) is a bit problematic, because of the `const N: usize` part,\\nwhich I haven\'t managed to be able to parse. And that\'s how I got rid of the error.\\n\\n:::note\\n\\nIf I were to use 2D-indexing over `[C; N]` slices, I\'d probably just go with the\\ncopy-paste, cause the cost of this \u201cmonstrosity\u201d outweighs the benefits of no DRY.\\n\\n:::\\n\\n#### Cause of the problem\\n\\nThis issue is relatively funny. If you don\'t use any type aliases, just the raw\\ntypes, you\'ll get suggested certain changes by the _clippy_. For example if you\\nconsider the following piece of code\\n```rust\\nfn get_sum(nums: &Vec) -> i32 {\\n nums.iter().sum()\\n}\\n\\nfn main() {\\n let nums = vec![1, 2, 3];\\n println!(\\"Sum: {}\\", get_sum(&nums));\\n}\\n```\\n\\nand you run _clippy_ on it, you will get\\n```\\nChecking playground v0.0.1 (/playground)\\nwarning: writing `&Vec` instead of `&[_]` involves a new object where a slice will do\\n --\x3e src/main.rs:1:18\\n |\\n1 | fn get_sum(nums: &Vec) -> i32 {\\n | ^^^^^^^^^ help: change this to: `&[i32]`\\n |\\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg\\n = note: `#[warn(clippy::ptr_arg)]` on by default\\n\\nwarning: `playground` (bin \\"playground\\") generated 1 warning\\n Finished dev [unoptimized + debuginfo] target(s) in 0.61s\\n```\\n\\nHowever, if you introduce a type alias, such as\\n```rust\\ntype Numbers = Vec;\\n```\\n\\nThen _clippy_ won\'t say anything, cause there is literally nothing to suggest.\\nHowever the outcome is not the same\u2026\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[BFS above]: #day-12-hill-climbing-algorithm"},{"id":"aoc-2022/1st-week","metadata":{"permalink":"/blog/aoc-2022/1st-week","editUrl":"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/01-week-1.md","source":"@site/blog/aoc-2022/01-week-1.md","title":"1st week of Advent of Code \'22 in Rust","description":"Surviving first week in Rust.","date":"2022-12-15T01:15:00.000Z","formattedDate":"December 15, 2022","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":12.4,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"1st week of Advent of Code \'22 in Rust","description":"Surviving first week in Rust.","date":"2022-12-15T01:15","slug":"aoc-2022/1st-week","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"2nd week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/2nd-week"},"nextItem":{"title":"Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/intro"}},"content":"Let\'s go through the first week of [_Advent of Code_] in Rust.\\n\\n\x3c!--truncate--\x3e\\n\\n:::note\\n\\nIf you wish to have a look at the solutions, you can follow them on my [GitLab].\\nMore specifically in the [`/src/bin/`].\\n\\n:::\\n\\nI will try to summarize my experience with using Rust for the AoC. Trying it out\\nages ago, I believe it will be _pain and suffering_, but we will see. For each\\nday I will also try to give a tl;dr of the problem, so that you can better imagine\\nthe relation to my woes or :+1: moments.\\n\\n## [Day 1: Calorie Counting](https://adventofcode.com/2022/day/1)\\n\\n:::info tl;dr\\n\\nAs the name suggests, we get the calories of the food contained in the elves\\nbackpacks and we want to choose the elf that has the most food ;)\\n\\n:::\\n\\n> Wakey wakey!\\n\\nProgramming in Rust at 6am definitely hits. I\'ve also forgotten to mention how I\\nhandle samples. With each puzzle you usually get a sample input and expected\\noutput. You can use them to verify that your solution works, or usually doesn\'t.\\n\\nAt first I\'ve decided to put asserts into my `main`, something like\\n```rust\\nassert_eq!(part_1(&sample), 24000);\\ninfo!(\\"Part 1: {}\\", part_1(&input));\\n\\nassert_eq!(part_2(&sample), 45000);\\ninfo!(\\"Part 2: {}\\", part_2(&input));\\n```\\n\\nHowever, once you get further, the sample input may take some time to run itself.\\nSo in the end, I have decided to turn them into unit tests:\\n```rust\\n#[cfg(test)]\\nmod tests {\\n use super::*;\\n\\n #[test]\\n fn test_part_1() {\\n let sample = parse_input(\\"samples/day01.txt\\");\\n assert_eq!(part_1(&sample), 24000);\\n }\\n\\n #[test]\\n fn test_part_2() {\\n let sample = parse_input(\\"samples/day01.txt\\");\\n assert_eq!(part_2(&sample), 45000);\\n }\\n}\\n```\\n\\nAnd later on I have noticed, it\'s hard to tell the difference between the days,\\nso I further renamed the `mod` from generic `tests` to reflect the days.\\n\\nAlso after finishing the first day puzzle, I have installed an [`sccache`] to\\ncache the builds, so that the build time is lower, cause it was kinda unbearable.\\n\\n### Solution\\n\\nWell, it\'s a pretty simple problem. You just take the input, sum the calories and\\nfind the biggest one. However, if we try to generalize to more than the biggest\\none, the fun appears. We have few options:\\n\\n- keep all the calories, sort them, take what we need\\n- keep all the calories and use max heap\\n- use min heap and maintain at most N calories that we need\\n\\n## [Day 2: Rock Paper Scissors](https://adventofcode.com/2022/day/2)\\n\\n:::info tl;dr\\n\\nYou want to know what score did you achieve while playing _Rock Paper Scissors_.\\nAnd then you want to be strategic about it.\\n\\n:::\\n\\nApart from the technical details of the puzzle, it went relatively smooth.\\n\\n### Solution\\n\\nI took relatively na\xefve approach and then tried to simplify it.\\n\\n## [Day 3: Rucksack Reorganization](https://adventofcode.com/2022/day/3)\\n\\n:::info tl;dr\\n\\nLet\'s go reorganize elves\' backpacks! Each backpacks has 2 compartments and you\\nwant to find the common item among those compartments. Each of them has priority,\\nyou care only about the sum.\\n\\n:::\\n\\nThis is the day where I started to fight the compiler and neither of us decided\\nto give up. Let\'s dive into it \\\\o/\\n\\n:::tip Fun fact\\n\\nFighting the compiler took me 30 minutes.\\n\\n:::\\n\\nWe need to find a common item among 2 collections, that\'s an easy task, right?\\nWe can construct 2 sets and find an intersection:\\n```rust\\nlet top: HashSet = [1, 2, 3].iter().collect();\\nlet bottom: HashSet = [3, 4, 5].iter().collect();\\n```\\n\\nNow, the first issue that we encounter is caused by the fact that we are using\\na slice (the `[\u2026]`), iterator of that returns **references** to the numbers.\\nAnd we get immediately yelled at by the compiler, because the numbers are discarded\\nafter running the `.collect`. To fix this, we can use `.into_iter`:\\n```rust\\nlet top: HashSet = [1, 2, 3].into_iter().collect();\\nlet bottom: HashSet = [3, 4, 5].into_iter().collect();\\n```\\n\\nThis way the numbers will get copied instead of referenced. OK, let\'s find the\\nintersection of those 2 collections:\\n```rust\\nprintln!(\\"Common elements: {:?}\\", top.intersection(&bottom));\\n```\\n```\\nCommon elements: [3]\\n```\\n\\n:::caution\\n\\nNotice that we need to do `&bottom`. It explicitly specifies that `.intersection`\\n**borrows** the `bottom`, i.e. takes an immutable reference to it.\\n\\n:::\\n\\nThat\'s what we want, right? Looks like it! \\\\o/\\n\\nNext part wants us to find the common element among all of the backpacks. OK, so\\nthat should be fairly easy, we have an intersection and we want to find intersection\\nover all of them.\\n\\nLet\'s have a look at the type of the `.intersection`\\n```rust\\npub fn intersection<\'a>(\\n\xa0\xa0\xa0\xa0&\'a self,\\n\xa0\xa0\xa0\xa0other: &\'a HashSet\\n) -> Intersection<\'a, T, S>\\n```\\n\\nOK\u2026 Huh\u2026 But we have an example there!\\n```rust\\nlet intersection: HashSet<_> = a.intersection(&b).collect();\\n```\\n\\nCool, that\'s all we need.\\n```rust\\nlet top: HashSet = [1, 2, 3, 4].into_iter().collect();\\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\\n\\nlet intersection: HashSet<_> = top.intersection(&bottom).collect();\\nprintln!(\\"Intersection: {:?}\\", intersection);\\n```\\n```\\nIntersection: {3, 4}\\n```\\n\\nCool, so let\'s do the intersection with the `top_2`:\\n```rust\\nlet top: HashSet = [1, 2, 3, 4].into_iter().collect();\\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\\n\\nlet intersection: HashSet<_> = top.intersection(&bottom).collect();\\nlet intersection: HashSet<_> = intersection.intersection(&top_2).collect();\\nprintln!(\\"Intersection: {:?}\\", intersection);\\n```\\n\\nAnd we get yelled at by the compiler:\\n```\\nerror[E0308]: mismatched types\\n --\x3e src/main.rs:10:58\\n |\\n10 | let intersection: HashSet<_> = intersection.intersection(&top_2).collect();\\n | ------------ ^^^^^^ expected `&i32`, found `i32`\\n | |\\n | arguments to this function are incorrect\\n |\\n = note: expected reference `&HashSet<&i32>`\\n found reference `&HashSet`\\n```\\n\\n/o\\\\ What the hell is going on here? Well, the funny thing is, that this operation\\ndoesn\'t return the elements themselves, but the references to them and when we pass\\nthe third set, it has just the values themselves, without any references.\\n\\n:::tip\\n\\nIt may seem as a very weird decision, but in fact it makes some sense\u2026 It allows\\nyou to do intersection of items that may not be possible to copy. Overall this is\\na \u201ctax\u201d for having a borrow checker ~~drilling your ass~~ having your back and\\nmaking sure you\'re not doing something naughty that may cause an **undefined**\\n**behavior**.\\n\\n:::\\n\\nTo resolve this we need to get an iterator that **clones** the elements:\\n```rust\\nlet top: HashSet = [1, 2, 3, 4].into_iter().collect();\\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\\n\\nlet intersection: HashSet<_> = top.intersection(&bottom).cloned().collect();\\nlet intersection: HashSet<_> = intersection.intersection(&top_2).cloned().collect();\\nlet intersection: HashSet<_> = intersection.intersection(&bottom_2).cloned().collect();\\nprintln!(\\"Intersection: {:?}\\", intersection);\\n```\\n```\\nIntersection: {4}\\n```\\n\\n### Solution\\n\\nThe approach is pretty simple, if you omit the _1on1 with the compiler_. You just\\nhave some fun with the set operations :)\\n\\n## [Day 4: Camp Cleanup](https://adventofcode.com/2022/day/4)\\n\\n:::info tl;dr\\n\\nElves are cleaning up the camp and they got overlapping sections to clean up.\\nFind how many overlap and can take the day off.\\n\\n:::\\n\\n[`RangeInclusive`] is your friend not an enemy :)\\n\\n### Solution\\n\\nRelatively easy, you just need to parse the input and know what you want. Rust\'s\\n`RangeInclusive` type helped a lot, cause it took care of all abstractions.\\n\\n## [Day 5: Supply Stacks](https://adventofcode.com/2022/day/5)\\n\\n:::info tl;dr\\n\\nLet\'s play with stacks of crates.\\n\\n:::\\n\\nVery easy problem with very annoying input. You can judge yourself:\\n```\\n [D] \\n[N] [C] \\n[Z] [M] [P]\\n 1 2 3 \\n\\nmove 1 from 2 to 1\\nmove 3 from 1 to 3\\nmove 2 from 2 to 1\\nmove 1 from 1 to 2\\n```\\n\\nGood luck transforming that into something reasonable :)\\n\\n\\n:::tip Fun fact\\n\\nTook me 40 minutes to parse this reasonably, including fighting the compiler.\\n\\n:::\\n\\n### Solution\\n\\nFor the initial solution I went with a manual solution (as in _I have done all_\\n_the work_. Later on I have decided to explore the `std` and interface of the\\n`std::vec::Vec` and found [`split_off`] which takes an index and splits (duh)\\nthe vector:\\n```rust\\nlet mut vec = vec![1, 2, 3];\\nlet vec2 = vec.split_off(1);\\nassert_eq!(vec, [1]);\\nassert_eq!(vec2, [2, 3]);\\n```\\n\\nThis helped me simplify my solution a lot and also get rid of some _edge cases_.\\n\\n## [Day 6: Tuning Trouble](https://adventofcode.com/2022/day/6)\\n\\n:::info tl;dr\\n\\nFinding start of the message in a very weird protocol. Start of the message is\\ndenoted by $N$ unique consecutive characters.\\n\\n:::\\n\\n### Solution\\n\\nA lot of different approaches, knowing that we are dealing with input consisting\\nsolely of ASCII letters, I bit the bullet and went with sliding window and\\nconstructing sets from that window, checking if the set is as big as the window.\\n\\nOne possible optimization could consist of keeping a bit-vector (i.e. `usize`\\nvariable) of encountered characters and updating it as we go. However this has\\na different issue and that is removal of the characters from the left side of the\\nwindow. We don\'t know if the same character is not included later on.\\n\\nOther option is to do similar thing, but keeping the frequencies of the letters,\\nand again knowing we have only ASCII letters we can optimize by having a vector\\nof 26 elements that keeps count for each lowercase letter.\\n\\n## [Day 7: No Space Left On Device](https://adventofcode.com/2022/day/7)\\n\\n:::info tl;dr\\n\\nLet\'s simulate [`du`] to get some stats about our file system and then pinpoint\\ndirectories that take a lot of space and should be deleted.\\n\\n:::\\n\\n> I was waiting for this moment, and yet it got me!\\n> *imagine me swearing for hours*\\n\\n### Solution\\n\\nWe need to \u201c_build_\u201d a file system from the input that is given in a following form:\\n```\\n$ cd /\\n$ ls\\ndir a\\n14848514 b.txt\\n8504156 c.dat\\ndir d\\n$ cd a\\n$ ls\\ndir e\\n29116 f\\n2557 g\\n62596 h.lst\\n$ cd e\\n$ ls\\n584 i\\n$ cd ..\\n$ cd ..\\n$ cd d\\n$ ls\\n4060174 j\\n8033020 d.log\\n5626152 d.ext\\n7214296 k\\n```\\n\\nThere are few ways in which you can achieve this and also you can assume some\\npreconditions, but why would we do that, right? :)\\n\\nYou can \u201cslap\u201d this in either [`HashMap`] or [`BTreeMap`] and call it a day.\\nAnd that would be boring\u2026\\n\\n:::tip\\n\\n`BTreeMap` is quite fitting for this, don\'t you think?\\n\\n:::\\n\\nI always wanted to try allocation on heap in Rust, so I chose to implement a tree.\\nI fought with the `Box` for some time and was losing\u2026\\n\\nThen I looked up some implementations of trees or linked lists and decided to try\\n`Rc>`. And I got my _ass whopped_ by the compiler once again. /o\\\\\\n\\n:::tip\\n\\n`Box` represents a dynamically allocated memory on heap. It is a single pointer,\\nyou can imagine this as `std::unique_ptr` in C++.\\n\\n`Rc` represents a dynamically allocated memory on heap. On top of that it is\\n_reference counted_ (that\'s what the `Rc` stands for). You can imagine this as\\n`std::shared_ptr` in C++.\\n\\nNow the fun stuff. Neither of them lets you **mutate** the contents of the memory.\\n\\n`Cell` allows you to mutate the memory. Can be used reasonably with types that\\ncan be copied, because the memory safety is guaranteed by copying the contents\\nwhen there is more than one **mutable** reference to the memory.\\n\\n`RefCell` is similar to the `Cell`, but the borrowing rules (how many mutable\\nreferences are present) are checked dynamically.\\n\\nSo in the end, if you want something like `std::shared_ptr` in Rust, you want\\nto have `Rc>`.\\n\\n:::\\n\\nSo, how are we going to represent the file system then? We will use an enumeration,\\nhehe, which is an algebraic data type that can store some stuff in itself :weary:\\n```rust\\ntype FileHandle = Rc>;\\n\\n#[derive(Debug)]\\nenum AocFile {\\n File(usize),\\n Directory(BTreeMap),\\n}\\n```\\n\\nLet\'s go over it! `FileHandle` represents dynamically allocated `AocFile`, not\\nmuch to discuss. What does the `#[derive(Debug)]` do though? It lets us to print\\nout the value of that enumeration, it\'s derived, so it\'s not as good as if we had\\nimplemented it ourselves, but it\'s good enough for debugging, hence the name.\\n\\nNow to the fun part! `AocFile` value can be represented in two ways:\\n- `File(usize)`, e.g. `AocFile::File(123)` and we can pattern match it, if we\\n need to\\n- `Directory(BTreeMap)` will represent the directory and will\\n contain map matching the name of the files (or directories) within to their\\n respective file handles\\n\\nI will omit the details about constructing this file system, cause there are a lot\\nof technicalities introduced by the nature of the input. However if you are\\ninterested, you can have a look at my solution.\\n\\nWe need to find small enough directories and also find the smallest directory that\\nwill free enough space. Now the question is, how could we do that. And there are\\nmultiple ways I will describe.\\n\\nI have chosen to implement [_tree catamorphism_] :weary:. It is basically a fold\\nover a tree data structure. We descent down into the leaves and propagate computed\\nresults all the way to the root. You can also notice that this approach is very\\nsimilar to _dynamic programming_, we find overlapping sections of the computation\\nand try to minimize the additional work (in this case: we need to know sizes of\\nour descendants, but we have already been there).\\n\\nAnother approach that has been suggested to me few days later is running DFS on\\nthe graph. And, funnily enough, we would still need to combine what we found in\\nthe branches where we descent. So in the end, it would work very similarly to my\\nsolution.\\n\\nOne of the more exotic options would be precomputing the required information at\\nthe same time as parsing. That could be done by adding additional fields to the\\nnodes which would allow storing such information and updating it as we construct\\nthe file system.\\n\\n## Post Mortem\\n\\nThings that have been brought up in the discussion later on.\\n\\n### `Rc` vs `Rc>`\\n\\nIt has been brought up that I have a contradicting statement regarding the\\ndynamically allocated memory. Specifically:\\n\\n- You can imagine `Rc` as an `std::shared_ptr` (in C++)\\n- When you want an equivalent of `std::shared_ptr`, you want to use\\n `Rc>`\\n\\nNow, in Rust it is a bit more complicated, because the type that represents the\\n\u201cshared pointer\u201d is `Rc`. What `RefCell` does is making sure that there is\\nonly one \u201cowner\u201d of a mutable reference at a time (and dynamically, as opposed\\nto the `Cell`).\\n\\nTherefore to be precise and correct about the equivalents of `std::shared_ptr`\\nin Rust, we can say that\\n\\n- `Rc` is an equivalent of a `const std::shared_ptr`,\\n- and `Rc>` is an equivalent of a `std::shared_ptr`.\\n\\nYou can easily see that they only differ in the mutability. (And even that is not\\nas simple as it seems, because there is also `Cell`)\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[GitLab]: https://gitlab.com/mfocko/advent-of-code-2022\\n[`/src/bin/`]: https://gitlab.com/mfocko/advent-of-code-2022/-/tree/main/src/bin\\n[`sccache`]: https://github.com/mozilla/sccache\\n[`RangeInclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html\\n[`split_off`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.split_off\\n[`du`]: https://www.man7.org/linux/man-pages/man1/du.1.html\\n[`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html\\n[`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html\\n[_tree catamorphism_]: https://en.wikipedia.org/wiki/Catamorphism#Tree_fold"},{"id":"aoc-2022/intro","metadata":{"permalink":"/blog/aoc-2022/intro","editUrl":"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/00-intro.md","source":"@site/blog/aoc-2022/00-intro.md","title":"Advent of Code \'22 in Rust","description":"Preparing for Advent of Code \'22.","date":"2022-12-14T21:45:00.000Z","formattedDate":"December 14, 2022","tags":[{"label":"advent-of-code","permalink":"/blog/tags/advent-of-code"},{"label":"advent-of-code-2022","permalink":"/blog/tags/advent-of-code-2022"},{"label":"rust","permalink":"/blog/tags/rust"}],"readingTime":8.665,"hasTruncateMarker":true,"authors":[{"name":"Matej Focko","email":"me+blog@mfocko.xyz","title":"a.k.a. @mf","url":"https://gitlab.com/mfocko","imageURL":"https://github.com/mfocko.png","key":"mf"}],"frontMatter":{"title":"Advent of Code \'22 in Rust","description":"Preparing for Advent of Code \'22.","date":"2022-12-14T21:45","slug":"aoc-2022/intro","authors":"mf","tags":["advent-of-code","advent-of-code-2022","rust"],"hide_table_of_contents":false},"prevItem":{"title":"1st week of Advent of Code \'22 in Rust","permalink":"/blog/aoc-2022/1st-week"}},"content":"Let\'s talk about the preparations for this year\'s [_Advent of Code_].\\n\\n\x3c!--truncate--\x3e\\n\\n## Choosing a language\\n\\nWhen choosing a language for AoC, you usually want a language that gives you a\\nquick feedback which allows you to iterate quickly to the solution of the puzzle.\\nOne of the most common choices is Python, many people also use JavaScript or Ruby.\\n\\nGiven the competitive nature of the AoC and popularity among competitive programming,\\nC++ might be also a very good choice. Only if you are familiar with it, I guess\u2026\\n\\nIf you want a challenge, you might also choose to rotate the languages each day.\\nThough I prefer to use only one language.\\n\\nFor this year I have been deciding between _Rust_, _C++_ and _Pascal_ or _Ada_.\\n\\nI have tried Rust last year and have survived with it for 3 days and then gave\\nup and switched to _Kotlin_, which was pretty good given it is \u201cJava undercover\u201d.\\nI pretty much like the ideas behind Rust, I am not sure about the whole cult and\\nimplementation of those ideas though. After some years with C/C++, I would say\\nthat Rust feels _too safe_ for my taste and tries to \u201c_punish me_\u201d even for the\\nmost trivial things.\\n\\nC++ is a very robust, but also comes with a wide variety of options providing you\\nthe ability to shoot yourself in the leg. I have tried to solve few days of previous\\nAdvent of Code events, it was _relatively easy_ to solve the problems in C++, given\\nthat I do not admit writing my own iterator for `enumerate`\u2026\\n\\nPascal or Ada were meme choices :) Ada is heavily inspired by Pascal and has a\\npretty nice standard library that offers enough to be able to quickly solve some\\nproblems in it. However the toolkit is questionable :/\\n\\n## Choosing libraries\\n\\n## Preparations for Rust\\n\\nAll of the sources, later on including solutions, can be found at my\\n[GitLab].\\n\\n### Toolkit\\n\\nSince we are using Rust, we are going to use a [Cargo] and more than likely VSCode\\nwith [`rust-analyzer`]. Because of my choice of libraries, we will also introduce\\na `.envrc` file that can be used by [`direnv`], which allows you to set specific\\nenvironment variables when you enter a directory. In our case, we will use\\n```bash\\n# to show nice backtrace when using the color-eyre\\nexport RUST_BACKTRACE=1\\n\\n# to catch logs generated by tracing\\nexport RUST_LOG=trace\\n```\\n\\nAnd for the one of the most obnoxious things ever, we will use a script to download\\nthe inputs instead of \u201c_clicking, opening and copying to a file_\u201d[^1]. There is\\nno need to be _fancy_, so we will adjust Python script by Martin[^2].\\n```py\\n#!/usr/bin/env python3\\n\\nimport datetime\\nimport yaml\\nimport requests\\nimport sys\\n\\n\\ndef load_config():\\n with open(\\"env.yaml\\", \\"r\\") as f:\\n js = yaml.load(f, Loader=yaml.Loader)\\n return js[\\"session\\"], js[\\"year\\"]\\n\\n\\ndef get_input(session, year, day):\\n return requests.get(\\n f\\"https://adventofcode.com/{year}/day/{day}/input\\",\\n cookies={\\"session\\": session},\\n headers={\\n \\"User-Agent\\": \\"{repo} by {mail}\\".format(\\n repo=\\"gitlab.com/mfocko/advent-of-code-2022\\",\\n mail=\\"me@mfocko.xyz\\",\\n )\\n },\\n ).content.decode(\\"utf-8\\")\\n\\n\\ndef main():\\n day = datetime.datetime.now().day\\n if len(sys.argv) == 2:\\n day = sys.argv[1]\\n\\n session, year = load_config()\\n problem_input = get_input(session, year, day)\\n\\n with open(f\\"./inputs/day{day:>02}.txt\\", \\"w\\") as f:\\n f.write(problem_input)\\n\\n\\nif __name__ == \\"__main__\\":\\n main()\\n```\\n\\nIf the script is called without any arguments, it will deduce the day from the\\nsystem, so we do not need to change the day every morning. It also requires a\\nconfiguration file:\\n```yaml\\n# env.yaml\\nsession: \u2039your session cookie\u203a\\nyear: 2022\\n```\\n\\n### Libraries\\n\\nLooking at the list of the libraries, I have chosen \u201ca lot\u201d of them. Let\'s walk\\nthrough each of them.\\n\\n[`tracing`] and [`tracing-subscriber`] are the crates that can be used for tracing\\nand logging of your Rust programs, there are also other crates that can help you\\nwith providing backtrace to the Sentry in case you have deployed your application\\nsomewhere and you want to watch over it. In our use case we will just utilize the\\nmacros for debugging in the terminal.\\n\\n[`thiserror`], [`anyhow`] and [`color-eyre`] are used for error reporting.\\n`thiserror` is a very good choice for libraries, cause it extends the `Error`\\nfrom the `std` and allows you to create more convenient error types. Next is\\n`anyhow` which kinda builds on top of the `thiserror` and provides you with simpler\\nerror handling in binaries[^3]. And finally we have `color-eyre` which, as I found\\nout later, is a colorful (_wink wink_) extension of `eyre` which is fork of `anyhow`\\nwhile supporting customized reports.\\n\\nIn the end I have decided to remove `thiserror` and `anyhow`, since first one is\\nsuitable for libraries and the latter was basically fully replaced by `{color-,}eyre`.\\n\\n[`regex`] and [`lazy_static`] are a very good and also, I hope, self-explanatory\\ncombination. `lazy_static` allows you to have static variables that must be initialized\\nduring runtime.\\n\\n[`itertools`] provides some nice extensions to the iterators from the `std`.\\n\\n### My own \u201clibrary\u201d\\n\\nWhen creating the crate for this year\'s Advent of Code, I have chosen a library\\ntype. Even though standard library is huge, some things might not be included and\\nalso we can follow _KISS_. I have 2 modules that my \u201clibrary\u201d exports, one for\\nparsing and one for 2D vector (that gets used quite often during Advent of Code).\\n\\nKey part is, of course, processing the input and my library exports following\\nfunctions that get used a lot:\\n```rust\\n/// Reads file to the string.\\npub fn file_to_string>(pathname: P) -> String;\\n\\n/// Reads file and returns it as a vector of characters.\\npub fn file_to_chars>(pathname: P) -> Vec;\\n\\n/// Reads file and returns a vector of parsed structures. Expects each structure\\n/// on its own line in the file. And `T` needs to implement `FromStr` trait.\\npub fn file_to_structs, T: FromStr>(pathname: P) -> Vec\\nwhere\\n ::Err: Debug;\\n\\n/// Converts iterator over strings to a vector of parsed structures. `T` needs\\n/// to implement `FromStr` trait and its error must derive `Debug` trait.\\npub fn strings_to_structs(\\n iter: impl Iterator\\n) -> Vec\\nwhere\\n ::Err: std::fmt::Debug,\\n U: Deref;\\n\\n/// Reads file and returns it as a vector of its lines.\\npub fn file_to_lines>(pathname: P) -> Vec;\\n```\\n\\nAs for the vector, I went with a rather simple implementation that allows only\\naddition of the vectors for now and accessing the elements via functions `x()`\\nand `y()`. Also the vector is generic, so we can use it with any numeric type we\\nneed.\\n\\n### Skeleton\\n\\nWe can also prepare a template to quickly bootstrap each of the days. We know\\nthat each puzzle has 2 parts, which means that we can start with 2 functions that\\nwill solve them.\\n```rust\\nfn part1(input: &Input) -> Output {\\n todo!()\\n}\\n\\nfn part2(input: &Input) -> Output {\\n todo!()\\n}\\n```\\n\\nBoth functions take reference to the input and return some output (in majority\\nof puzzles, it is the same type). `todo!()` can be used as a nice placeholder,\\nit also causes a panic when reached and we could also provide some string with\\nan explanation, e.g. `todo!(\\"part 1\\")`. We have not given functions a specific\\ntype and to avoid as much copy-paste as possible, we will introduce type aliases.\\n```rust\\ntype Input = String;\\ntype Output = i32;\\n```\\n\\n:::tip\\n\\nThis allows us to quickly adjust the types only in one place without the need to\\ndo _regex-replace_ or replace them manually.\\n\\n:::\\n\\nFor each day we get a personalized input that is provided as a text file. Almost\\nall the time, we would like to get some structured type out of that input, and\\ntherefore it makes sense to introduce a new function that will provide the parsing\\nof the input.\\n```rust\\nfn parse_input(path: &str) -> Input {\\n todo!()\\n}\\n```\\n\\nThis \u201cparser\u201d will take a path to the file, just in case we would like to run the\\nsample instead of input.\\n\\nOK, so now we can write a `main` function that will take all of the pieces and\\nrun them.\\n```rust\\nfn main() {\\n let input = parse_input(\\"inputs/dayXX.txt\\");\\n\\n println!(\\"Part 1: {}\\", part_1(&input));\\n println!(\\"Part 2: {}\\", part_2(&input));\\n}\\n```\\n\\nThis would definitely do :) But we have installed a few libraries and we want to\\nuse them. In this part we are going to utilize _[`tracing`]_ (for tracing, duh\u2026)\\nand _[`color-eyre`]_ (for better error reporting, e.g. from parsing).\\n```rust\\nfn main() -> Result<()> {\\n tracing_subscriber::fmt()\\n .with_env_filter(EnvFilter::from_default_env())\\n .with_target(false)\\n .with_file(true)\\n .with_line_number(true)\\n .without_time()\\n .compact()\\n .init();\\n color_eyre::install()?;\\n\\n let input = parse_input(\\"inputs/dayXX.txt\\");\\n\\n info!(\\"Part 1: {}\\", part_1(&input));\\n info!(\\"Part 2: {}\\", part_2(&input));\\n\\n Ok(())\\n}\\n```\\n\\nThe first statement will set up tracing and configure it to print out the logs to\\nterminal, based on the environment variable. We also change the formatting a bit,\\nsince we do not need all the _fancy_ features of the logger. Pure initialization\\nwould get us logs like this:\\n```\\n2022-12-11T19:53:19.975343Z INFO day01: Part 1: 0\\n```\\n\\nHowever after running that command, we will get the following:\\n```\\n INFO src/bin/day01.rs:35: Part 1: 0\\n```\\n\\nAnd the `color_eyre::install()?` is quite straightforward. We just initialize the\\nerror reporting by _color eyre_.\\n\\n:::caution\\n\\nNotice that we had to add `Ok(())` to the end of the function and adjust the\\nreturn type of the `main` to `Result<()>`. It is caused by the _color eyre_ that\\ncan be installed only once and therefore it can fail, that is how we got the `?`\\nat the end of the `::install` which _unwraps_ the **\xbbresult\xab** of the installation.\\n\\n:::\\n\\nOverall we will get to a template like this:\\n```rust\\nuse aoc_2022::*;\\n\\nuse color_eyre::eyre::Result;\\nuse tracing::info;\\nuse tracing_subscriber::EnvFilter;\\n\\ntype Input = String;\\ntype Output = i32;\\n\\nfn parse_input(path: &str) -> Input {\\n todo!()\\n}\\n\\nfn part1(input: &Input) -> Output {\\n todo!()\\n}\\n\\nfn part2(input: &Input) -> Output {\\n todo!()\\n}\\n\\nfn main() -> Result<()> {\\n tracing_subscriber::fmt()\\n .with_env_filter(EnvFilter::from_default_env())\\n .with_target(false)\\n .with_file(true)\\n .with_line_number(true)\\n .without_time()\\n .compact()\\n .init();\\n color_eyre::install()?;\\n\\n let input = parse_input(\\"inputs/dayXX.txt\\");\\n\\n info!(\\"Part 1: {}\\", part_1(&input));\\n info!(\\"Part 2: {}\\", part_2(&input));\\n\\n Ok(())\\n}\\n```\\n\\n[^1]: Copy-pasting might be a relaxing thing to do, but you can also discover\\nnasty stuff about your PC. See [this Reddit post and the comment].\\n[^2]: [GitHub profile](https://github.com/martinjonas)\\n[^3]: Even though you can use it even for libraries, but handling errors from\\nlibraries using `anyhow` is nasty\u2026 You will be the stinky one ;)\\n\\n[_Advent of Code_]: https://adventofcode.com\\n[GitLab]: https://gitlab.com/mfocko/advent-of-code-2022\\n[Cargo]: https://doc.rust-lang.org/cargo/\\n[`rust-analyzer`]: https://rust-analyzer.github.io/\\n[`direnv`]: https://direnv.net/\\n[`tracing`]: https://crates.io/crates/tracing\\n[`tracing-subscriber`]: https://crates.io/crates/tracing-subscriber\\n[`thiserror`]: https://crates.io/crates/thiserror\\n[`anyhow`]: https://crates.io/crates/anyhow\\n[`color-eyre`]: https://crates.io/crates/color-eyre\\n[`regex`]: https://crates.io/crates/regex\\n[`lazy_static`]: https://crates.io/crates/lazy_static\\n[`itertools`]: https://crates.io/crates/itertools\\n[this Reddit post and the comment]: https://www.reddit.com/r/adventofcode/comments/zb98pn/comment/iyq0ono"}]}')}}]); \ No newline at end of file diff --git a/assets/js/4e286f4e.b0df1295.js b/assets/js/4e286f4e.d6756c5b.js similarity index 99% rename from assets/js/4e286f4e.b0df1295.js rename to assets/js/4e286f4e.d6756c5b.js index dc7a032..0444473 100644 --- a/assets/js/4e286f4e.b0df1295.js +++ b/assets/js/4e286f4e.d6756c5b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1501],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=s(n),d=r,h=m["".concat(p,".").concat(d)]||m[d]||c[d]||o;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[m]="string"==typeof e?e:r,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var a=n(7462),r=(n(7294),n(3905));const o={id:"karel-1",title:"Recursion and backtracking with Robot Karel",description:"A problem with too many restrictions.\n",tags:["python","karel","recursion","backtracking"],last_update:{date:new Date("2022-11-29T00:00:00.000Z")}},i=void 0,l={unversionedId:"recursion/karel-1",id:"recursion/karel-1",title:"Recursion and backtracking with Robot Karel",description:"A problem with too many restrictions.\n",source:"@site/ib002/04-recursion/2022-11-29-karel-1.md",sourceDirName:"04-recursion",slug:"/recursion/karel-1",permalink:"/ib002/recursion/karel-1",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/04-recursion/2022-11-29-karel-1.md",tags:[{label:"python",permalink:"/ib002/tags/python"},{label:"karel",permalink:"/ib002/tags/karel"},{label:"recursion",permalink:"/ib002/tags/recursion"},{label:"backtracking",permalink:"/ib002/tags/backtracking"}],version:"current",lastUpdatedAt:166968e4,formattedLastUpdatedAt:"Nov 29, 2022",frontMatter:{id:"karel-1",title:"Recursion and backtracking with Robot Karel",description:"A problem with too many restrictions.\n",tags:["python","karel","recursion","backtracking"],last_update:{date:"2022-11-29T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Recursion",permalink:"/ib002/category/recursion"},next:{title:"Introduction to dynamic programming",permalink:"/ib002/recursion/pyramid-slide-down"}},p={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Your environment and problem description",id:"your-environment-and-problem-description",level:2},{value:"Environment",id:"environment",level:3},{value:"Interface",id:"interface",level:3},{value:"Problem",id:"problem",level:3},{value:"Simple problem to get familiar with the robot",id:"simple-problem-to-get-familiar-with-the-robot",level:2},{value:"Brainstorm the idea",id:"brainstorm-the-idea",level:2},{value:"\xbbRough\xab pseudocode",id:"rough-pseudocode",level:2},{value:"\xbbProper\xab pseudocode",id:"proper-pseudocode",level:2},{value:"Library",id:"library",level:2},{value:"Solution",id:"solution",level:2}],u={toc:s},m="wrapper";function c(e){let{components:t,...o}=e;return(0,r.kt)(m,(0,a.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"pathname:///files/ib002/recursion/karel-1.tar.gz"},"Sources"))),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"In this exercise we will be working with a Robot Karel and with a \xbbvery\xab limited\nresources. The point of this exercise is to show how powerful recursion and\nbacktracking can be even without anything else at your hand."),(0,r.kt)("h2",{id:"your-environment-and-problem-description"},"Your environment and problem description"),(0,r.kt)("h3",{id:"environment"},"Environment"),(0,r.kt)("p",null,"You are given a robot that is present in a maze and is looking for an exit. Maze\nconsists of different walls and exit is marked with a single so-called \u201cbeeper\u201d."),(0,r.kt)("p",null,"Walking into a wall results in a permanent damage of the robot."),(0,r.kt)("h3",{id:"interface"},"Interface"),(0,r.kt)("p",null,"You can control the robot using the following interface:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"actions \u200b\xad\u2014 you can use them to change the current state of the robot and its\nsurroundings",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.step()")," \u2014 moves robot one step further"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.turn_left()")," \u2014 turns robot 90-degrees counter-clockwise",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"notice that you are not given ",(0,r.kt)("inlineCode",{parentName:"li"},"turn_right")," or ",(0,r.kt)("inlineCode",{parentName:"li"},"turn_around"),", but feel free\nto implement them yourself"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.pick_beeper()")," and opposite operation ",(0,r.kt)("inlineCode",{parentName:"li"},"robot.put_beeper()")," \u2014 that\nallows you to either pick or put \u201cbeeper\u201d from or onto the current position"))),(0,r.kt)("li",{parentName:"ul"},"queries \u2014 you can use them to check the current state of the robot and its\nsurroundings",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.beepers_present()")," \u2014 to check if there are any beepers at the robot's\ncurrent location"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.left_is_clear()")," \u2014 to check if you can step to the left",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"analogically for ",(0,r.kt)("inlineCode",{parentName:"li"},"front")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"right"))))))),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Helper functions / procedures are allowed. Return values are allowed."),(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("strong",{parentName:"p"},"Variables are prohibited!"))),(0,r.kt)("h3",{id:"problem"},"Problem"),(0,r.kt)("p",null,"Your task is to decide whether there is an exit from the maze or not. You can see\nan example of a maze here:"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Image of the maze",src:n(9857).Z,width:"770",height:"839"})),(0,r.kt)("h2",{id:"simple-problem-to-get-familiar-with-the-robot"},"Simple problem to get familiar with the robot"),(0,r.kt)("p",null,"If you feel completely lost after the previous description, let me start you off\nwith a simpler problem."),(0,r.kt)("p",null,"You are standing in front of the stairs, your task is to walk up the stairs."),(0,r.kt)("p",null,"You can see an example of such map here:"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Image of the stairs",src:n(8617).Z,width:"1058",height:"1161"})),(0,r.kt)("h2",{id:"brainstorm-the-idea"},"Brainstorm the idea"),(0,r.kt)("p",null,"As a first step write down any ideas and things that you have noticed or came to\nyour mind. Ideally:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Write down a nested list of the problems, e.g."),(0,r.kt)("admonition",{parentName:"li",title:"Example ",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Problem: I want to find out whether the display on smartphone should rotate."),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"Check if display has been rotated",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Read data from some sensor",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"From what sensor"))),(0,r.kt)("li",{parentName:"ul"},"In what format are the data I have read?"),(0,r.kt)("li",{parentName:"ul"},"How do I communicate with the sensor?"),(0,r.kt)("li",{parentName:"ul"},"What is the meaning of the data that I got?"),(0,r.kt)("li",{parentName:"ul"},"How can I process it?")))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Write down list of problems that can happen, e.g."),(0,r.kt)("admonition",{parentName:"li",title:"Example continued",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Following the same problem."),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"What if the sensor doesn't work?"),(0,r.kt)("li",{parentName:"ul"},"What if the data doesn't conform to the specification?"),(0,r.kt)("li",{parentName:"ul"},"What if my formulas are wrong?")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Write down ",(0,r.kt)("strong",{parentName:"p"},"anything")," you consider important to solving the problem, e.g."),(0,r.kt)("admonition",{parentName:"li",title:"Example continued once again",type:"info"},(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"I could probably use gyroscope."),(0,r.kt)("li",{parentName:"ul"},"I should probably look up the datasheet for that module."),(0,r.kt)("li",{parentName:"ul"},"I could write some tests to verify that my computations are correct."))))),(0,r.kt)("h2",{id:"rough-pseudocode"},"\xbbRough\xab pseudocode"),(0,r.kt)("p",null,"As a next step write a ",(0,r.kt)("strong",{parentName:"p"},"mock up")," of a pseudocode solving the problem, you are\nallowed to use comments as placeholders for bigger chunks of code."),(0,r.kt)("p",null,"Those comments are also a very good hints for decomposition and short, but\ndescriptive, commnets (if they are short enough and you decide not to factor them\nout to separate functions)."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"The smaller the function is, the easier it is to test it and argue about its\ncorrectness.")),(0,r.kt)("h2",{id:"proper-pseudocode"},"\xbbProper\xab pseudocode"),(0,r.kt)("p",null,"If you are satisfied with the ",(0,r.kt)("em",{parentName:"p"},"\xbbrough\xab pseudocode"),", it's time to convert it into\na proper one. Get rid of the uncertain pieces of functionality and replace them\nwith proper pseudocode, i.e. list of the things that should happen in its place."),(0,r.kt)("h2",{id:"library"},"Library"),(0,r.kt)("p",null,"If you got here, and you ",(0,r.kt)("strong",{parentName:"p"},"actually")," wrote down the pseudocode, you can try your\nsolution after downloading the sources linked at the beginning. If you download\nthe ZIP-file, you can there:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"generate_mazes.py")," - that was used to generate the same maze with beepers in\ndifferent locations")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"karel_tk.py")," - library which can run Karel given the his world"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"documentation can be found ",(0,r.kt)("a",{parentName:"li",href:"https://www.fi.muni.cz/~xfocko/ib111/10/docs/"},"here")),(0,r.kt)("li",{parentName:"ul"},"also requires Tk Python library to be installed (it should be included in\nmajority of Python installations)"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"*.kw")," - which represent multiple worlds for Karel I have prepared")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"skeleton.py")," - skeleton for your solution, needs to be put in the same directory\nas ",(0,r.kt)("inlineCode",{parentName:"p"},"karel_tk.py")," and takes path to the world as a first argument, example usage:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ python3 skeleton.py stairs.kw\n")),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"of course, this file can be renamed ;)")))),(0,r.kt)("h2",{id:"solution"},"Solution"),(0,r.kt)("p",null,"Solution to this problem will be released as a second part, so that you can try\nit out by yourself without any influence of \u201cexample solution\u201d."),(0,r.kt)("p",null,"If you want to get any feedback, feel free to mail me your solution (including\nall the steps that lead to your final solution, if you wish to get feedback on\nthose too)."))}c.isMDXComponent=!0},9857:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/maze-a374d908bc9445061e15faeddc71641e.png"},8617:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/stairs-5ee5d03905645aeb13eeaa7774451a64.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1501],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=s(n),d=r,h=m["".concat(p,".").concat(d)]||m[d]||c[d]||o;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[m]="string"==typeof e?e:r,i[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var a=n(7462),r=(n(7294),n(3905));const o={id:"karel-1",title:"Recursion and backtracking with Robot Karel",description:"A problem with too many restrictions.\n",tags:["python","karel","recursion","backtracking"],last_update:{date:new Date("2022-11-29T00:00:00.000Z")}},i=void 0,l={unversionedId:"recursion/karel-1",id:"recursion/karel-1",title:"Recursion and backtracking with Robot Karel",description:"A problem with too many restrictions.\n",source:"@site/ib002/04-recursion/2022-11-29-karel-1.md",sourceDirName:"04-recursion",slug:"/recursion/karel-1",permalink:"/ib002/recursion/karel-1",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/04-recursion/2022-11-29-karel-1.md",tags:[{label:"python",permalink:"/ib002/tags/python"},{label:"karel",permalink:"/ib002/tags/karel"},{label:"recursion",permalink:"/ib002/tags/recursion"},{label:"backtracking",permalink:"/ib002/tags/backtracking"}],version:"current",lastUpdatedAt:166968e4,formattedLastUpdatedAt:"Nov 29, 2022",frontMatter:{id:"karel-1",title:"Recursion and backtracking with Robot Karel",description:"A problem with too many restrictions.\n",tags:["python","karel","recursion","backtracking"],last_update:{date:"2022-11-29T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Recursion",permalink:"/ib002/category/recursion"},next:{title:"Introduction to dynamic programming",permalink:"/ib002/recursion/pyramid-slide-down"}},p={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Your environment and problem description",id:"your-environment-and-problem-description",level:2},{value:"Environment",id:"environment",level:3},{value:"Interface",id:"interface",level:3},{value:"Problem",id:"problem",level:3},{value:"Simple problem to get familiar with the robot",id:"simple-problem-to-get-familiar-with-the-robot",level:2},{value:"Brainstorm the idea",id:"brainstorm-the-idea",level:2},{value:"\xbbRough\xab pseudocode",id:"rough-pseudocode",level:2},{value:"\xbbProper\xab pseudocode",id:"proper-pseudocode",level:2},{value:"Library",id:"library",level:2},{value:"Solution",id:"solution",level:2}],u={toc:s},m="wrapper";function c(e){let{components:t,...o}=e;return(0,r.kt)(m,(0,a.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"pathname:///files/ib002/recursion/karel-1.tar.gz"},"Sources"))),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"In this exercise we will be working with a Robot Karel and with a \xbbvery\xab limited\nresources. The point of this exercise is to show how powerful recursion and\nbacktracking can be even without anything else at your hand."),(0,r.kt)("h2",{id:"your-environment-and-problem-description"},"Your environment and problem description"),(0,r.kt)("h3",{id:"environment"},"Environment"),(0,r.kt)("p",null,"You are given a robot that is present in a maze and is looking for an exit. Maze\nconsists of different walls and exit is marked with a single so-called \u201cbeeper\u201d."),(0,r.kt)("p",null,"Walking into a wall results in a permanent damage of the robot."),(0,r.kt)("h3",{id:"interface"},"Interface"),(0,r.kt)("p",null,"You can control the robot using the following interface:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"actions \u200b\xad\u2014 you can use them to change the current state of the robot and its\nsurroundings",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.step()")," \u2014 moves robot one step further"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.turn_left()")," \u2014 turns robot 90-degrees counter-clockwise",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"notice that you are not given ",(0,r.kt)("inlineCode",{parentName:"li"},"turn_right")," or ",(0,r.kt)("inlineCode",{parentName:"li"},"turn_around"),", but feel free\nto implement them yourself"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.pick_beeper()")," and opposite operation ",(0,r.kt)("inlineCode",{parentName:"li"},"robot.put_beeper()")," \u2014 that\nallows you to either pick or put \u201cbeeper\u201d from or onto the current position"))),(0,r.kt)("li",{parentName:"ul"},"queries \u2014 you can use them to check the current state of the robot and its\nsurroundings",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.beepers_present()")," \u2014 to check if there are any beepers at the robot's\ncurrent location"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"robot.left_is_clear()")," \u2014 to check if you can step to the left",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"analogically for ",(0,r.kt)("inlineCode",{parentName:"li"},"front")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"right"))))))),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Helper functions / procedures are allowed. Return values are allowed."),(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("strong",{parentName:"p"},"Variables are prohibited!"))),(0,r.kt)("h3",{id:"problem"},"Problem"),(0,r.kt)("p",null,"Your task is to decide whether there is an exit from the maze or not. You can see\nan example of a maze here:"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Image of the maze",src:n(9857).Z,width:"770",height:"839"})),(0,r.kt)("h2",{id:"simple-problem-to-get-familiar-with-the-robot"},"Simple problem to get familiar with the robot"),(0,r.kt)("p",null,"If you feel completely lost after the previous description, let me start you off\nwith a simpler problem."),(0,r.kt)("p",null,"You are standing in front of the stairs, your task is to walk up the stairs."),(0,r.kt)("p",null,"You can see an example of such map here:"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Image of the stairs",src:n(8617).Z,width:"1058",height:"1161"})),(0,r.kt)("h2",{id:"brainstorm-the-idea"},"Brainstorm the idea"),(0,r.kt)("p",null,"As a first step write down any ideas and things that you have noticed or came to\nyour mind. Ideally:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Write down a nested list of the problems, e.g."),(0,r.kt)("admonition",{parentName:"li",title:"Example ",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Problem: I want to find out whether the display on smartphone should rotate."),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"Check if display has been rotated",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Read data from some sensor",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"From what sensor"))),(0,r.kt)("li",{parentName:"ul"},"In what format are the data I have read?"),(0,r.kt)("li",{parentName:"ul"},"How do I communicate with the sensor?"),(0,r.kt)("li",{parentName:"ul"},"What is the meaning of the data that I got?"),(0,r.kt)("li",{parentName:"ul"},"How can I process it?")))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Write down list of problems that can happen, e.g."),(0,r.kt)("admonition",{parentName:"li",title:"Example continued",type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Following the same problem."),(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"What if the sensor doesn't work?"),(0,r.kt)("li",{parentName:"ul"},"What if the data doesn't conform to the specification?"),(0,r.kt)("li",{parentName:"ul"},"What if my formulas are wrong?")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Write down ",(0,r.kt)("strong",{parentName:"p"},"anything")," you consider important to solving the problem, e.g."),(0,r.kt)("admonition",{parentName:"li",title:"Example continued once again",type:"info"},(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"I could probably use gyroscope."),(0,r.kt)("li",{parentName:"ul"},"I should probably look up the datasheet for that module."),(0,r.kt)("li",{parentName:"ul"},"I could write some tests to verify that my computations are correct."))))),(0,r.kt)("h2",{id:"rough-pseudocode"},"\xbbRough\xab pseudocode"),(0,r.kt)("p",null,"As a next step write a ",(0,r.kt)("strong",{parentName:"p"},"mock up")," of a pseudocode solving the problem, you are\nallowed to use comments as placeholders for bigger chunks of code."),(0,r.kt)("p",null,"Those comments are also a very good hints for decomposition and short, but\ndescriptive, commnets (if they are short enough and you decide not to factor them\nout to separate functions)."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"The smaller the function is, the easier it is to test it and argue about its\ncorrectness.")),(0,r.kt)("h2",{id:"proper-pseudocode"},"\xbbProper\xab pseudocode"),(0,r.kt)("p",null,"If you are satisfied with the ",(0,r.kt)("em",{parentName:"p"},"\xbbrough\xab pseudocode"),", it's time to convert it into\na proper one. Get rid of the uncertain pieces of functionality and replace them\nwith proper pseudocode, i.e. list of the things that should happen in its place."),(0,r.kt)("h2",{id:"library"},"Library"),(0,r.kt)("p",null,"If you got here, and you ",(0,r.kt)("strong",{parentName:"p"},"actually")," wrote down the pseudocode, you can try your\nsolution after downloading the sources linked at the beginning. If you download\nthe ZIP-file, you can there:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"generate_mazes.py")," - that was used to generate the same maze with beepers in\ndifferent locations")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"karel_tk.py")," - library which can run Karel given the his world"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"documentation can be found ",(0,r.kt)("a",{parentName:"li",href:"https://www.fi.muni.cz/~xfocko/ib111/10/docs/"},"here")),(0,r.kt)("li",{parentName:"ul"},"also requires Tk Python library to be installed (it should be included in\nmajority of Python installations)"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"*.kw")," - which represent multiple worlds for Karel I have prepared")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"skeleton.py")," - skeleton for your solution, needs to be put in the same directory\nas ",(0,r.kt)("inlineCode",{parentName:"p"},"karel_tk.py")," and takes path to the world as a first argument, example usage:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ python3 skeleton.py stairs.kw\n")),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"of course, this file can be renamed ;)")))),(0,r.kt)("h2",{id:"solution"},"Solution"),(0,r.kt)("p",null,"Solution to this problem will be released as a second part, so that you can try\nit out by yourself without any influence of \u201cexample solution\u201d."),(0,r.kt)("p",null,"If you want to get any feedback, feel free to mail me your solution (including\nall the steps that lead to your final solution, if you wish to get feedback on\nthose too)."))}c.isMDXComponent=!0},9857:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/maze-a374d908bc9445061e15faeddc71641e.png"},8617:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/stairs-5ee5d03905645aeb13eeaa7774451a64.png"}}]); \ No newline at end of file diff --git a/assets/js/4ee12fa2.4d63da2f.js b/assets/js/4ee12fa2.1cedc9fe.js similarity index 95% rename from assets/js/4ee12fa2.4d63da2f.js rename to assets/js/4ee12fa2.1cedc9fe.js index eca1ba2..cbd6896 100644 --- a/assets/js/4ee12fa2.4d63da2f.js +++ b/assets/js/4ee12fa2.1cedc9fe.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7963],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=l(r),d=o,m=s["".concat(p,".").concat(d)]||s[d]||f[d]||i;return r?n.createElement(m,a(a({ref:t},u),{},{components:r})):n.createElement(m,a({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[s]="string"==typeof e?e:o,a[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const i={id:"pb161-intro",title:"Introduction",slug:"/"},a=void 0,c={unversionedId:"pb161-intro",id:"pb161-intro",title:"Introduction",description:"",source:"@site/pb161/00-intro-pb161.md",sourceDirName:".",slug:"/",permalink:"/pb161/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb161/00-intro-pb161.md",tags:[],version:"current",lastUpdatedAt:1694110423,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"pb161-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Environment",permalink:"/pb161/environment"}},p={},l=[],u={toc:l},s="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7963],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=l(r),d=o,m=s["".concat(p,".").concat(d)]||s[d]||f[d]||i;return r?n.createElement(m,a(a({ref:t},u),{},{components:r})):n.createElement(m,a({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[s]="string"==typeof e?e:o,a[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const i={id:"pb161-intro",title:"Introduction",slug:"/"},a=void 0,c={unversionedId:"pb161-intro",id:"pb161-intro",title:"Introduction",description:"",source:"@site/pb161/00-intro-pb161.md",sourceDirName:".",slug:"/",permalink:"/pb161/",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb161/00-intro-pb161.md",tags:[],version:"current",lastUpdatedAt:1694111094,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"pb161-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Environment",permalink:"/pb161/environment"}},p={},l=[],u={toc:l},s="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/51624505.ab30cae6.js b/assets/js/51624505.5d814829.js similarity index 99% rename from assets/js/51624505.ab30cae6.js rename to assets/js/51624505.5d814829.js index f2d9206..87a1d3b 100644 --- a/assets/js/51624505.ab30cae6.js +++ b/assets/js/51624505.5d814829.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3731],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||d[m]||o;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const o={title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45",slug:"aoc-2022/intro",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,s={permalink:"/blog/aoc-2022/intro",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/00-intro.md",source:"@site/blog/aoc-2022/00-intro.md",title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45:00.000Z",formattedDate:"December 14, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:8.665,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45",slug:"aoc-2022/intro",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"1st week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/1st-week"}},l={authorsImageUrls:[void 0]},p=[{value:"Choosing a language",id:"choosing-a-language",level:2},{value:"Choosing libraries",id:"choosing-libraries",level:2},{value:"Preparations for Rust",id:"preparations-for-rust",level:2},{value:"Toolkit",id:"toolkit",level:3},{value:"Libraries",id:"libraries",level:3},{value:"My own \u201clibrary\u201d",id:"my-own-library",level:3},{value:"Skeleton",id:"skeleton",level:3}],u={toc:p},c="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Let's talk about the preparations for this year's ",(0,r.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,r.kt)("em",{parentName:"a"},"Advent of Code")),"."),(0,r.kt)("h2",{id:"choosing-a-language"},"Choosing a language"),(0,r.kt)("p",null,"When choosing a language for AoC, you usually want a language that gives you a\nquick feedback which allows you to iterate quickly to the solution of the puzzle.\nOne of the most common choices is Python, many people also use JavaScript or Ruby."),(0,r.kt)("p",null,"Given the competitive nature of the AoC and popularity among competitive programming,\nC++ might be also a very good choice. Only if you are familiar with it, I guess\u2026"),(0,r.kt)("p",null,"If you want a challenge, you might also choose to rotate the languages each day.\nThough I prefer to use only one language."),(0,r.kt)("p",null,"For this year I have been deciding between ",(0,r.kt)("em",{parentName:"p"},"Rust"),", ",(0,r.kt)("em",{parentName:"p"},"C++")," and ",(0,r.kt)("em",{parentName:"p"},"Pascal")," or ",(0,r.kt)("em",{parentName:"p"},"Ada"),"."),(0,r.kt)("p",null,"I have tried Rust last year and have survived with it for 3 days and then gave\nup and switched to ",(0,r.kt)("em",{parentName:"p"},"Kotlin"),", which was pretty good given it is \u201cJava undercover\u201d.\nI pretty much like the ideas behind Rust, I am not sure about the whole cult and\nimplementation of those ideas though. After some years with C/C++, I would say\nthat Rust feels ",(0,r.kt)("em",{parentName:"p"},"too safe")," for my taste and tries to \u201c",(0,r.kt)("em",{parentName:"p"},"punish me"),"\u201d even for the\nmost trivial things."),(0,r.kt)("p",null,"C++ is a very robust, but also comes with a wide variety of options providing you\nthe ability to shoot yourself in the leg. I have tried to solve few days of previous\nAdvent of Code events, it was ",(0,r.kt)("em",{parentName:"p"},"relatively easy")," to solve the problems in C++, given\nthat I do not admit writing my own iterator for ",(0,r.kt)("inlineCode",{parentName:"p"},"enumerate"),"\u2026"),(0,r.kt)("p",null,"Pascal or Ada were meme choices :) Ada is heavily inspired by Pascal and has a\npretty nice standard library that offers enough to be able to quickly solve some\nproblems in it. However the toolkit is questionable :/"),(0,r.kt)("h2",{id:"choosing-libraries"},"Choosing libraries"),(0,r.kt)("h2",{id:"preparations-for-rust"},"Preparations for Rust"),(0,r.kt)("p",null,"All of the sources, later on including solutions, can be found at my\n",(0,r.kt)("a",{parentName:"p",href:"https://gitlab.com/mfocko/advent-of-code-2022"},"GitLab"),"."),(0,r.kt)("h3",{id:"toolkit"},"Toolkit"),(0,r.kt)("p",null,"Since we are using Rust, we are going to use a ",(0,r.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/cargo/"},"Cargo")," and more than likely VSCode\nwith ",(0,r.kt)("a",{parentName:"p",href:"https://rust-analyzer.github.io/"},(0,r.kt)("inlineCode",{parentName:"a"},"rust-analyzer")),". Because of my choice of libraries, we will also introduce\na ",(0,r.kt)("inlineCode",{parentName:"p"},".envrc")," file that can be used by ",(0,r.kt)("a",{parentName:"p",href:"https://direnv.net/"},(0,r.kt)("inlineCode",{parentName:"a"},"direnv")),", which allows you to set specific\nenvironment variables when you enter a directory. In our case, we will use"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# to show nice backtrace when using the color-eyre\nexport RUST_BACKTRACE=1\n\n# to catch logs generated by tracing\nexport RUST_LOG=trace\n")),(0,r.kt)("p",null,"And for the one of the most obnoxious things ever, we will use a script to download\nthe inputs instead of \u201c",(0,r.kt)("em",{parentName:"p"},"clicking, opening and copying to a file"),"\u201d",(0,r.kt)("sup",{parentName:"p",id:"fnref-1-793a30"},(0,r.kt)("a",{parentName:"sup",href:"#fn-1-793a30",className:"footnote-ref"},"1")),". There is\nno need to be ",(0,r.kt)("em",{parentName:"p"},"fancy"),", so we will adjust Python script by Martin",(0,r.kt)("sup",{parentName:"p",id:"fnref-2-793a30"},(0,r.kt)("a",{parentName:"sup",href:"#fn-2-793a30",className:"footnote-ref"},"2")),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-py"},'#!/usr/bin/env python3\n\nimport datetime\nimport yaml\nimport requests\nimport sys\n\n\ndef load_config():\n with open("env.yaml", "r") as f:\n js = yaml.load(f, Loader=yaml.Loader)\n return js["session"], js["year"]\n\n\ndef get_input(session, year, day):\n return requests.get(\n f"https://adventofcode.com/{year}/day/{day}/input",\n cookies={"session": session},\n headers={\n "User-Agent": "{repo} by {mail}".format(\n repo="gitlab.com/mfocko/advent-of-code-2022",\n mail="me@mfocko.xyz",\n )\n },\n ).content.decode("utf-8")\n\n\ndef main():\n day = datetime.datetime.now().day\n if len(sys.argv) == 2:\n day = sys.argv[1]\n\n session, year = load_config()\n problem_input = get_input(session, year, day)\n\n with open(f"./inputs/day{day:>02}.txt", "w") as f:\n f.write(problem_input)\n\n\nif __name__ == "__main__":\n main()\n')),(0,r.kt)("p",null,"If the script is called without any arguments, it will deduce the day from the\nsystem, so we do not need to change the day every morning. It also requires a\nconfiguration file:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-yaml"},"# env.yaml\nsession: \u2039your session cookie\u203a\nyear: 2022\n")),(0,r.kt)("h3",{id:"libraries"},"Libraries"),(0,r.kt)("p",null,"Looking at the list of the libraries, I have chosen \u201ca lot\u201d of them. Let's walk\nthrough each of them."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/tracing"},(0,r.kt)("inlineCode",{parentName:"a"},"tracing"))," and ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/tracing-subscriber"},(0,r.kt)("inlineCode",{parentName:"a"},"tracing-subscriber"))," are the crates that can be used for tracing\nand logging of your Rust programs, there are also other crates that can help you\nwith providing backtrace to the Sentry in case you have deployed your application\nsomewhere and you want to watch over it. In our use case we will just utilize the\nmacros for debugging in the terminal."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/thiserror"},(0,r.kt)("inlineCode",{parentName:"a"},"thiserror")),", ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/anyhow"},(0,r.kt)("inlineCode",{parentName:"a"},"anyhow"))," and ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/color-eyre"},(0,r.kt)("inlineCode",{parentName:"a"},"color-eyre"))," are used for error reporting.\n",(0,r.kt)("inlineCode",{parentName:"p"},"thiserror")," is a very good choice for libraries, cause it extends the ",(0,r.kt)("inlineCode",{parentName:"p"},"Error"),"\nfrom the ",(0,r.kt)("inlineCode",{parentName:"p"},"std")," and allows you to create more convenient error types. Next is\n",(0,r.kt)("inlineCode",{parentName:"p"},"anyhow")," which kinda builds on top of the ",(0,r.kt)("inlineCode",{parentName:"p"},"thiserror")," and provides you with simpler\nerror handling in binaries",(0,r.kt)("sup",{parentName:"p",id:"fnref-3-793a30"},(0,r.kt)("a",{parentName:"sup",href:"#fn-3-793a30",className:"footnote-ref"},"3")),". And finally we have ",(0,r.kt)("inlineCode",{parentName:"p"},"color-eyre")," which, as I found\nout later, is a colorful (",(0,r.kt)("em",{parentName:"p"},"wink wink"),") extension of ",(0,r.kt)("inlineCode",{parentName:"p"},"eyre")," which is fork of ",(0,r.kt)("inlineCode",{parentName:"p"},"anyhow"),"\nwhile supporting customized reports."),(0,r.kt)("p",null,"In the end I have decided to remove ",(0,r.kt)("inlineCode",{parentName:"p"},"thiserror")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"anyhow"),", since first one is\nsuitable for libraries and the latter was basically fully replaced by ",(0,r.kt)("inlineCode",{parentName:"p"},"{color-,}eyre"),"."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/regex"},(0,r.kt)("inlineCode",{parentName:"a"},"regex"))," and ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/lazy_static"},(0,r.kt)("inlineCode",{parentName:"a"},"lazy_static"))," are a very good and also, I hope, self-explanatory\ncombination. ",(0,r.kt)("inlineCode",{parentName:"p"},"lazy_static")," allows you to have static variables that must be initialized\nduring runtime."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/itertools"},(0,r.kt)("inlineCode",{parentName:"a"},"itertools"))," provides some nice extensions to the iterators from the ",(0,r.kt)("inlineCode",{parentName:"p"},"std"),"."),(0,r.kt)("h3",{id:"my-own-library"},"My own \u201clibrary\u201d"),(0,r.kt)("p",null,"When creating the crate for this year's Advent of Code, I have chosen a library\ntype. Even though standard library is huge, some things might not be included and\nalso we can follow ",(0,r.kt)("em",{parentName:"p"},"KISS"),". I have 2 modules that my \u201clibrary\u201d exports, one for\nparsing and one for 2D vector (that gets used quite often during Advent of Code)."),(0,r.kt)("p",null,"Key part is, of course, processing the input and my library exports following\nfunctions that get used a lot:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"/// Reads file to the string.\npub fn file_to_string>(pathname: P) -> String;\n\n/// Reads file and returns it as a vector of characters.\npub fn file_to_chars>(pathname: P) -> Vec;\n\n/// Reads file and returns a vector of parsed structures. Expects each structure\n/// on its own line in the file. And `T` needs to implement `FromStr` trait.\npub fn file_to_structs, T: FromStr>(pathname: P) -> Vec\nwhere\n ::Err: Debug;\n\n/// Converts iterator over strings to a vector of parsed structures. `T` needs\n/// to implement `FromStr` trait and its error must derive `Debug` trait.\npub fn strings_to_structs(\n iter: impl Iterator\n) -> Vec\nwhere\n ::Err: std::fmt::Debug,\n U: Deref;\n\n/// Reads file and returns it as a vector of its lines.\npub fn file_to_lines>(pathname: P) -> Vec;\n")),(0,r.kt)("p",null,"As for the vector, I went with a rather simple implementation that allows only\naddition of the vectors for now and accessing the elements via functions ",(0,r.kt)("inlineCode",{parentName:"p"},"x()"),"\nand ",(0,r.kt)("inlineCode",{parentName:"p"},"y()"),". Also the vector is generic, so we can use it with any numeric type we\nneed."),(0,r.kt)("h3",{id:"skeleton"},"Skeleton"),(0,r.kt)("p",null,"We can also prepare a template to quickly bootstrap each of the days. We know\nthat each puzzle has 2 parts, which means that we can start with 2 functions that\nwill solve them."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"fn part1(input: &Input) -> Output {\n todo!()\n}\n\nfn part2(input: &Input) -> Output {\n todo!()\n}\n")),(0,r.kt)("p",null,"Both functions take reference to the input and return some output (in majority\nof puzzles, it is the same type). ",(0,r.kt)("inlineCode",{parentName:"p"},"todo!()")," can be used as a nice placeholder,\nit also causes a panic when reached and we could also provide some string with\nan explanation, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},'todo!("part 1")'),". We have not given functions a specific\ntype and to avoid as much copy-paste as possible, we will introduce type aliases."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"type Input = String;\ntype Output = i32;\n")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"This allows us to quickly adjust the types only in one place without the need to\ndo ",(0,r.kt)("em",{parentName:"p"},"regex-replace")," or replace them manually.")),(0,r.kt)("p",null,"For each day we get a personalized input that is provided as a text file. Almost\nall the time, we would like to get some structured type out of that input, and\ntherefore it makes sense to introduce a new function that will provide the parsing\nof the input."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"fn parse_input(path: &str) -> Input {\n todo!()\n}\n")),(0,r.kt)("p",null,"This \u201cparser\u201d will take a path to the file, just in case we would like to run the\nsample instead of input."),(0,r.kt)("p",null,"OK, so now we can write a ",(0,r.kt)("inlineCode",{parentName:"p"},"main")," function that will take all of the pieces and\nrun them."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'fn main() {\n let input = parse_input("inputs/dayXX.txt");\n\n println!("Part 1: {}", part_1(&input));\n println!("Part 2: {}", part_2(&input));\n}\n')),(0,r.kt)("p",null,"This would definitely do :) But we have installed a few libraries and we want to\nuse them. In this part we are going to utilize ",(0,r.kt)("em",{parentName:"p"},(0,r.kt)("a",{parentName:"em",href:"https://crates.io/crates/tracing"},(0,r.kt)("inlineCode",{parentName:"a"},"tracing")))," (for tracing, duh\u2026)\nand ",(0,r.kt)("em",{parentName:"p"},(0,r.kt)("a",{parentName:"em",href:"https://crates.io/crates/color-eyre"},(0,r.kt)("inlineCode",{parentName:"a"},"color-eyre")))," (for better error reporting, e.g. from parsing)."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'fn main() -> Result<()> {\n tracing_subscriber::fmt()\n .with_env_filter(EnvFilter::from_default_env())\n .with_target(false)\n .with_file(true)\n .with_line_number(true)\n .without_time()\n .compact()\n .init();\n color_eyre::install()?;\n\n let input = parse_input("inputs/dayXX.txt");\n\n info!("Part 1: {}", part_1(&input));\n info!("Part 2: {}", part_2(&input));\n\n Ok(())\n}\n')),(0,r.kt)("p",null,"The first statement will set up tracing and configure it to print out the logs to\nterminal, based on the environment variable. We also change the formatting a bit,\nsince we do not need all the ",(0,r.kt)("em",{parentName:"p"},"fancy")," features of the logger. Pure initialization\nwould get us logs like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"2022-12-11T19:53:19.975343Z INFO day01: Part 1: 0\n")),(0,r.kt)("p",null,"However after running that command, we will get the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"}," INFO src/bin/day01.rs:35: Part 1: 0\n")),(0,r.kt)("p",null,"And the ",(0,r.kt)("inlineCode",{parentName:"p"},"color_eyre::install()?")," is quite straightforward. We just initialize the\nerror reporting by ",(0,r.kt)("em",{parentName:"p"},"color eyre"),"."),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Notice that we had to add ",(0,r.kt)("inlineCode",{parentName:"p"},"Ok(())")," to the end of the function and adjust the\nreturn type of the ",(0,r.kt)("inlineCode",{parentName:"p"},"main")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"Result<()>"),". It is caused by the ",(0,r.kt)("em",{parentName:"p"},"color eyre")," that\ncan be installed only once and therefore it can fail, that is how we got the ",(0,r.kt)("inlineCode",{parentName:"p"},"?"),"\nat the end of the ",(0,r.kt)("inlineCode",{parentName:"p"},"::install")," which ",(0,r.kt)("em",{parentName:"p"},"unwraps")," the ",(0,r.kt)("strong",{parentName:"p"},"\xbbresult\xab")," of the installation.")),(0,r.kt)("p",null,"Overall we will get to a template like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'use aoc_2022::*;\n\nuse color_eyre::eyre::Result;\nuse tracing::info;\nuse tracing_subscriber::EnvFilter;\n\ntype Input = String;\ntype Output = i32;\n\nfn parse_input(path: &str) -> Input {\n todo!()\n}\n\nfn part1(input: &Input) -> Output {\n todo!()\n}\n\nfn part2(input: &Input) -> Output {\n todo!()\n}\n\nfn main() -> Result<()> {\n tracing_subscriber::fmt()\n .with_env_filter(EnvFilter::from_default_env())\n .with_target(false)\n .with_file(true)\n .with_line_number(true)\n .without_time()\n .compact()\n .init();\n color_eyre::install()?;\n\n let input = parse_input("inputs/dayXX.txt");\n\n info!("Part 1: {}", part_1(&input));\n info!("Part 2: {}", part_2(&input));\n\n Ok(())\n}\n')),(0,r.kt)("div",{className:"footnotes"},(0,r.kt)("hr",{parentName:"div"}),(0,r.kt)("ol",{parentName:"div"},(0,r.kt)("li",{parentName:"ol",id:"fn-1-793a30"},"Copy-pasting might be a relaxing thing to do, but you can also discover\nnasty stuff about your PC. See ",(0,r.kt)("a",{parentName:"li",href:"https://www.reddit.com/r/adventofcode/comments/zb98pn/comment/iyq0ono"},"this Reddit post and the comment"),".",(0,r.kt)("a",{parentName:"li",href:"#fnref-1-793a30",className:"footnote-backref"},"\u21a9")),(0,r.kt)("li",{parentName:"ol",id:"fn-2-793a30"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/martinjonas"},"GitHub profile"),(0,r.kt)("a",{parentName:"li",href:"#fnref-2-793a30",className:"footnote-backref"},"\u21a9")),(0,r.kt)("li",{parentName:"ol",id:"fn-3-793a30"},"Even though you can use it even for libraries, but handling errors from\nlibraries using ",(0,r.kt)("inlineCode",{parentName:"li"},"anyhow")," is nasty\u2026 You will be the stinky one ;)",(0,r.kt)("a",{parentName:"li",href:"#fnref-3-793a30",className:"footnote-backref"},"\u21a9")))))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3731],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||d[m]||o;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const o={title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45",slug:"aoc-2022/intro",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,s={permalink:"/blog/aoc-2022/intro",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/00-intro.md",source:"@site/blog/aoc-2022/00-intro.md",title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45:00.000Z",formattedDate:"December 14, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:8.665,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45",slug:"aoc-2022/intro",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"1st week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/1st-week"}},l={authorsImageUrls:[void 0]},p=[{value:"Choosing a language",id:"choosing-a-language",level:2},{value:"Choosing libraries",id:"choosing-libraries",level:2},{value:"Preparations for Rust",id:"preparations-for-rust",level:2},{value:"Toolkit",id:"toolkit",level:3},{value:"Libraries",id:"libraries",level:3},{value:"My own \u201clibrary\u201d",id:"my-own-library",level:3},{value:"Skeleton",id:"skeleton",level:3}],u={toc:p},c="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Let's talk about the preparations for this year's ",(0,r.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,r.kt)("em",{parentName:"a"},"Advent of Code")),"."),(0,r.kt)("h2",{id:"choosing-a-language"},"Choosing a language"),(0,r.kt)("p",null,"When choosing a language for AoC, you usually want a language that gives you a\nquick feedback which allows you to iterate quickly to the solution of the puzzle.\nOne of the most common choices is Python, many people also use JavaScript or Ruby."),(0,r.kt)("p",null,"Given the competitive nature of the AoC and popularity among competitive programming,\nC++ might be also a very good choice. Only if you are familiar with it, I guess\u2026"),(0,r.kt)("p",null,"If you want a challenge, you might also choose to rotate the languages each day.\nThough I prefer to use only one language."),(0,r.kt)("p",null,"For this year I have been deciding between ",(0,r.kt)("em",{parentName:"p"},"Rust"),", ",(0,r.kt)("em",{parentName:"p"},"C++")," and ",(0,r.kt)("em",{parentName:"p"},"Pascal")," or ",(0,r.kt)("em",{parentName:"p"},"Ada"),"."),(0,r.kt)("p",null,"I have tried Rust last year and have survived with it for 3 days and then gave\nup and switched to ",(0,r.kt)("em",{parentName:"p"},"Kotlin"),", which was pretty good given it is \u201cJava undercover\u201d.\nI pretty much like the ideas behind Rust, I am not sure about the whole cult and\nimplementation of those ideas though. After some years with C/C++, I would say\nthat Rust feels ",(0,r.kt)("em",{parentName:"p"},"too safe")," for my taste and tries to \u201c",(0,r.kt)("em",{parentName:"p"},"punish me"),"\u201d even for the\nmost trivial things."),(0,r.kt)("p",null,"C++ is a very robust, but also comes with a wide variety of options providing you\nthe ability to shoot yourself in the leg. I have tried to solve few days of previous\nAdvent of Code events, it was ",(0,r.kt)("em",{parentName:"p"},"relatively easy")," to solve the problems in C++, given\nthat I do not admit writing my own iterator for ",(0,r.kt)("inlineCode",{parentName:"p"},"enumerate"),"\u2026"),(0,r.kt)("p",null,"Pascal or Ada were meme choices :) Ada is heavily inspired by Pascal and has a\npretty nice standard library that offers enough to be able to quickly solve some\nproblems in it. However the toolkit is questionable :/"),(0,r.kt)("h2",{id:"choosing-libraries"},"Choosing libraries"),(0,r.kt)("h2",{id:"preparations-for-rust"},"Preparations for Rust"),(0,r.kt)("p",null,"All of the sources, later on including solutions, can be found at my\n",(0,r.kt)("a",{parentName:"p",href:"https://gitlab.com/mfocko/advent-of-code-2022"},"GitLab"),"."),(0,r.kt)("h3",{id:"toolkit"},"Toolkit"),(0,r.kt)("p",null,"Since we are using Rust, we are going to use a ",(0,r.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/cargo/"},"Cargo")," and more than likely VSCode\nwith ",(0,r.kt)("a",{parentName:"p",href:"https://rust-analyzer.github.io/"},(0,r.kt)("inlineCode",{parentName:"a"},"rust-analyzer")),". Because of my choice of libraries, we will also introduce\na ",(0,r.kt)("inlineCode",{parentName:"p"},".envrc")," file that can be used by ",(0,r.kt)("a",{parentName:"p",href:"https://direnv.net/"},(0,r.kt)("inlineCode",{parentName:"a"},"direnv")),", which allows you to set specific\nenvironment variables when you enter a directory. In our case, we will use"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"# to show nice backtrace when using the color-eyre\nexport RUST_BACKTRACE=1\n\n# to catch logs generated by tracing\nexport RUST_LOG=trace\n")),(0,r.kt)("p",null,"And for the one of the most obnoxious things ever, we will use a script to download\nthe inputs instead of \u201c",(0,r.kt)("em",{parentName:"p"},"clicking, opening and copying to a file"),"\u201d",(0,r.kt)("sup",{parentName:"p",id:"fnref-1-793a30"},(0,r.kt)("a",{parentName:"sup",href:"#fn-1-793a30",className:"footnote-ref"},"1")),". There is\nno need to be ",(0,r.kt)("em",{parentName:"p"},"fancy"),", so we will adjust Python script by Martin",(0,r.kt)("sup",{parentName:"p",id:"fnref-2-793a30"},(0,r.kt)("a",{parentName:"sup",href:"#fn-2-793a30",className:"footnote-ref"},"2")),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-py"},'#!/usr/bin/env python3\n\nimport datetime\nimport yaml\nimport requests\nimport sys\n\n\ndef load_config():\n with open("env.yaml", "r") as f:\n js = yaml.load(f, Loader=yaml.Loader)\n return js["session"], js["year"]\n\n\ndef get_input(session, year, day):\n return requests.get(\n f"https://adventofcode.com/{year}/day/{day}/input",\n cookies={"session": session},\n headers={\n "User-Agent": "{repo} by {mail}".format(\n repo="gitlab.com/mfocko/advent-of-code-2022",\n mail="me@mfocko.xyz",\n )\n },\n ).content.decode("utf-8")\n\n\ndef main():\n day = datetime.datetime.now().day\n if len(sys.argv) == 2:\n day = sys.argv[1]\n\n session, year = load_config()\n problem_input = get_input(session, year, day)\n\n with open(f"./inputs/day{day:>02}.txt", "w") as f:\n f.write(problem_input)\n\n\nif __name__ == "__main__":\n main()\n')),(0,r.kt)("p",null,"If the script is called without any arguments, it will deduce the day from the\nsystem, so we do not need to change the day every morning. It also requires a\nconfiguration file:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-yaml"},"# env.yaml\nsession: \u2039your session cookie\u203a\nyear: 2022\n")),(0,r.kt)("h3",{id:"libraries"},"Libraries"),(0,r.kt)("p",null,"Looking at the list of the libraries, I have chosen \u201ca lot\u201d of them. Let's walk\nthrough each of them."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/tracing"},(0,r.kt)("inlineCode",{parentName:"a"},"tracing"))," and ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/tracing-subscriber"},(0,r.kt)("inlineCode",{parentName:"a"},"tracing-subscriber"))," are the crates that can be used for tracing\nand logging of your Rust programs, there are also other crates that can help you\nwith providing backtrace to the Sentry in case you have deployed your application\nsomewhere and you want to watch over it. In our use case we will just utilize the\nmacros for debugging in the terminal."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/thiserror"},(0,r.kt)("inlineCode",{parentName:"a"},"thiserror")),", ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/anyhow"},(0,r.kt)("inlineCode",{parentName:"a"},"anyhow"))," and ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/color-eyre"},(0,r.kt)("inlineCode",{parentName:"a"},"color-eyre"))," are used for error reporting.\n",(0,r.kt)("inlineCode",{parentName:"p"},"thiserror")," is a very good choice for libraries, cause it extends the ",(0,r.kt)("inlineCode",{parentName:"p"},"Error"),"\nfrom the ",(0,r.kt)("inlineCode",{parentName:"p"},"std")," and allows you to create more convenient error types. Next is\n",(0,r.kt)("inlineCode",{parentName:"p"},"anyhow")," which kinda builds on top of the ",(0,r.kt)("inlineCode",{parentName:"p"},"thiserror")," and provides you with simpler\nerror handling in binaries",(0,r.kt)("sup",{parentName:"p",id:"fnref-3-793a30"},(0,r.kt)("a",{parentName:"sup",href:"#fn-3-793a30",className:"footnote-ref"},"3")),". And finally we have ",(0,r.kt)("inlineCode",{parentName:"p"},"color-eyre")," which, as I found\nout later, is a colorful (",(0,r.kt)("em",{parentName:"p"},"wink wink"),") extension of ",(0,r.kt)("inlineCode",{parentName:"p"},"eyre")," which is fork of ",(0,r.kt)("inlineCode",{parentName:"p"},"anyhow"),"\nwhile supporting customized reports."),(0,r.kt)("p",null,"In the end I have decided to remove ",(0,r.kt)("inlineCode",{parentName:"p"},"thiserror")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"anyhow"),", since first one is\nsuitable for libraries and the latter was basically fully replaced by ",(0,r.kt)("inlineCode",{parentName:"p"},"{color-,}eyre"),"."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/regex"},(0,r.kt)("inlineCode",{parentName:"a"},"regex"))," and ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/lazy_static"},(0,r.kt)("inlineCode",{parentName:"a"},"lazy_static"))," are a very good and also, I hope, self-explanatory\ncombination. ",(0,r.kt)("inlineCode",{parentName:"p"},"lazy_static")," allows you to have static variables that must be initialized\nduring runtime."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/itertools"},(0,r.kt)("inlineCode",{parentName:"a"},"itertools"))," provides some nice extensions to the iterators from the ",(0,r.kt)("inlineCode",{parentName:"p"},"std"),"."),(0,r.kt)("h3",{id:"my-own-library"},"My own \u201clibrary\u201d"),(0,r.kt)("p",null,"When creating the crate for this year's Advent of Code, I have chosen a library\ntype. Even though standard library is huge, some things might not be included and\nalso we can follow ",(0,r.kt)("em",{parentName:"p"},"KISS"),". I have 2 modules that my \u201clibrary\u201d exports, one for\nparsing and one for 2D vector (that gets used quite often during Advent of Code)."),(0,r.kt)("p",null,"Key part is, of course, processing the input and my library exports following\nfunctions that get used a lot:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"/// Reads file to the string.\npub fn file_to_string>(pathname: P) -> String;\n\n/// Reads file and returns it as a vector of characters.\npub fn file_to_chars>(pathname: P) -> Vec;\n\n/// Reads file and returns a vector of parsed structures. Expects each structure\n/// on its own line in the file. And `T` needs to implement `FromStr` trait.\npub fn file_to_structs, T: FromStr>(pathname: P) -> Vec\nwhere\n ::Err: Debug;\n\n/// Converts iterator over strings to a vector of parsed structures. `T` needs\n/// to implement `FromStr` trait and its error must derive `Debug` trait.\npub fn strings_to_structs(\n iter: impl Iterator\n) -> Vec\nwhere\n ::Err: std::fmt::Debug,\n U: Deref;\n\n/// Reads file and returns it as a vector of its lines.\npub fn file_to_lines>(pathname: P) -> Vec;\n")),(0,r.kt)("p",null,"As for the vector, I went with a rather simple implementation that allows only\naddition of the vectors for now and accessing the elements via functions ",(0,r.kt)("inlineCode",{parentName:"p"},"x()"),"\nand ",(0,r.kt)("inlineCode",{parentName:"p"},"y()"),". Also the vector is generic, so we can use it with any numeric type we\nneed."),(0,r.kt)("h3",{id:"skeleton"},"Skeleton"),(0,r.kt)("p",null,"We can also prepare a template to quickly bootstrap each of the days. We know\nthat each puzzle has 2 parts, which means that we can start with 2 functions that\nwill solve them."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"fn part1(input: &Input) -> Output {\n todo!()\n}\n\nfn part2(input: &Input) -> Output {\n todo!()\n}\n")),(0,r.kt)("p",null,"Both functions take reference to the input and return some output (in majority\nof puzzles, it is the same type). ",(0,r.kt)("inlineCode",{parentName:"p"},"todo!()")," can be used as a nice placeholder,\nit also causes a panic when reached and we could also provide some string with\nan explanation, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},'todo!("part 1")'),". We have not given functions a specific\ntype and to avoid as much copy-paste as possible, we will introduce type aliases."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"type Input = String;\ntype Output = i32;\n")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"This allows us to quickly adjust the types only in one place without the need to\ndo ",(0,r.kt)("em",{parentName:"p"},"regex-replace")," or replace them manually.")),(0,r.kt)("p",null,"For each day we get a personalized input that is provided as a text file. Almost\nall the time, we would like to get some structured type out of that input, and\ntherefore it makes sense to introduce a new function that will provide the parsing\nof the input."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"fn parse_input(path: &str) -> Input {\n todo!()\n}\n")),(0,r.kt)("p",null,"This \u201cparser\u201d will take a path to the file, just in case we would like to run the\nsample instead of input."),(0,r.kt)("p",null,"OK, so now we can write a ",(0,r.kt)("inlineCode",{parentName:"p"},"main")," function that will take all of the pieces and\nrun them."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'fn main() {\n let input = parse_input("inputs/dayXX.txt");\n\n println!("Part 1: {}", part_1(&input));\n println!("Part 2: {}", part_2(&input));\n}\n')),(0,r.kt)("p",null,"This would definitely do :) But we have installed a few libraries and we want to\nuse them. In this part we are going to utilize ",(0,r.kt)("em",{parentName:"p"},(0,r.kt)("a",{parentName:"em",href:"https://crates.io/crates/tracing"},(0,r.kt)("inlineCode",{parentName:"a"},"tracing")))," (for tracing, duh\u2026)\nand ",(0,r.kt)("em",{parentName:"p"},(0,r.kt)("a",{parentName:"em",href:"https://crates.io/crates/color-eyre"},(0,r.kt)("inlineCode",{parentName:"a"},"color-eyre")))," (for better error reporting, e.g. from parsing)."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'fn main() -> Result<()> {\n tracing_subscriber::fmt()\n .with_env_filter(EnvFilter::from_default_env())\n .with_target(false)\n .with_file(true)\n .with_line_number(true)\n .without_time()\n .compact()\n .init();\n color_eyre::install()?;\n\n let input = parse_input("inputs/dayXX.txt");\n\n info!("Part 1: {}", part_1(&input));\n info!("Part 2: {}", part_2(&input));\n\n Ok(())\n}\n')),(0,r.kt)("p",null,"The first statement will set up tracing and configure it to print out the logs to\nterminal, based on the environment variable. We also change the formatting a bit,\nsince we do not need all the ",(0,r.kt)("em",{parentName:"p"},"fancy")," features of the logger. Pure initialization\nwould get us logs like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"2022-12-11T19:53:19.975343Z INFO day01: Part 1: 0\n")),(0,r.kt)("p",null,"However after running that command, we will get the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"}," INFO src/bin/day01.rs:35: Part 1: 0\n")),(0,r.kt)("p",null,"And the ",(0,r.kt)("inlineCode",{parentName:"p"},"color_eyre::install()?")," is quite straightforward. We just initialize the\nerror reporting by ",(0,r.kt)("em",{parentName:"p"},"color eyre"),"."),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Notice that we had to add ",(0,r.kt)("inlineCode",{parentName:"p"},"Ok(())")," to the end of the function and adjust the\nreturn type of the ",(0,r.kt)("inlineCode",{parentName:"p"},"main")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"Result<()>"),". It is caused by the ",(0,r.kt)("em",{parentName:"p"},"color eyre")," that\ncan be installed only once and therefore it can fail, that is how we got the ",(0,r.kt)("inlineCode",{parentName:"p"},"?"),"\nat the end of the ",(0,r.kt)("inlineCode",{parentName:"p"},"::install")," which ",(0,r.kt)("em",{parentName:"p"},"unwraps")," the ",(0,r.kt)("strong",{parentName:"p"},"\xbbresult\xab")," of the installation.")),(0,r.kt)("p",null,"Overall we will get to a template like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'use aoc_2022::*;\n\nuse color_eyre::eyre::Result;\nuse tracing::info;\nuse tracing_subscriber::EnvFilter;\n\ntype Input = String;\ntype Output = i32;\n\nfn parse_input(path: &str) -> Input {\n todo!()\n}\n\nfn part1(input: &Input) -> Output {\n todo!()\n}\n\nfn part2(input: &Input) -> Output {\n todo!()\n}\n\nfn main() -> Result<()> {\n tracing_subscriber::fmt()\n .with_env_filter(EnvFilter::from_default_env())\n .with_target(false)\n .with_file(true)\n .with_line_number(true)\n .without_time()\n .compact()\n .init();\n color_eyre::install()?;\n\n let input = parse_input("inputs/dayXX.txt");\n\n info!("Part 1: {}", part_1(&input));\n info!("Part 2: {}", part_2(&input));\n\n Ok(())\n}\n')),(0,r.kt)("div",{className:"footnotes"},(0,r.kt)("hr",{parentName:"div"}),(0,r.kt)("ol",{parentName:"div"},(0,r.kt)("li",{parentName:"ol",id:"fn-1-793a30"},"Copy-pasting might be a relaxing thing to do, but you can also discover\nnasty stuff about your PC. See ",(0,r.kt)("a",{parentName:"li",href:"https://www.reddit.com/r/adventofcode/comments/zb98pn/comment/iyq0ono"},"this Reddit post and the comment"),".",(0,r.kt)("a",{parentName:"li",href:"#fnref-1-793a30",className:"footnote-backref"},"\u21a9")),(0,r.kt)("li",{parentName:"ol",id:"fn-2-793a30"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/martinjonas"},"GitHub profile"),(0,r.kt)("a",{parentName:"li",href:"#fnref-2-793a30",className:"footnote-backref"},"\u21a9")),(0,r.kt)("li",{parentName:"ol",id:"fn-3-793a30"},"Even though you can use it even for libraries, but handling errors from\nlibraries using ",(0,r.kt)("inlineCode",{parentName:"li"},"anyhow")," is nasty\u2026 You will be the stinky one ;)",(0,r.kt)("a",{parentName:"li",href:"#fnref-3-793a30",className:"footnote-backref"},"\u21a9")))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/713b7838.e5a05e06.js b/assets/js/713b7838.f48c11a2.js similarity index 99% rename from assets/js/713b7838.e5a05e06.js rename to assets/js/713b7838.f48c11a2.js index d3793b0..a6457cf 100644 --- a/assets/js/713b7838.e5a05e06.js +++ b/assets/js/713b7838.f48c11a2.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2167],{3905:(t,e,n)=>{n.d(e,{Zo:()=>s,kt:()=>h});var a=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function l(t){for(var e=1;e=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var p=a.createContext({}),m=function(t){var e=a.useContext(p),n=e;return t&&(n="function"==typeof t?t(e):l(l({},e),t)),n},s=function(t){var e=m(t.components);return a.createElement(p.Provider,{value:e},t.children)},d="mdxType",k={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},u=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,i=t.originalType,p=t.parentName,s=o(t,["components","mdxType","originalType","parentName"]),d=m(n),u=r,h=d["".concat(p,".").concat(u)]||d[u]||k[u]||i;return n?a.createElement(h,l(l({ref:e},s),{},{components:n})):a.createElement(h,l({ref:e},s))}));function h(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var i=n.length,l=new Array(i);l[0]=u;var o={};for(var p in e)hasOwnProperty.call(e,p)&&(o[p]=e[p]);o.originalType=t,o[d]="string"==typeof t?t:r,l[1]=o;for(var m=2;m{n.r(e),n.d(e,{assets:()=>p,contentTitle:()=>l,default:()=>k,frontMatter:()=>i,metadata:()=>o,toc:()=>m});var a=n(7462),r=(n(7294),n(3905));const i={id:"seminar-04",title:"4th seminar",description:"Robot in a maze.\n",last_update:{date:new Date("2023-03-13T00:00:00.000Z")}},l=void 0,o={unversionedId:"bonuses/seminar-04",id:"bonuses/seminar-04",title:"4th seminar",description:"Robot in a maze.\n",source:"@site/pb071/bonuses/04.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-04",permalink:"/pb071/bonuses/seminar-04",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/04.md",tags:[],version:"current",lastUpdatedAt:1678665600,formattedLastUpdatedAt:"Mar 13, 2023",frontMatter:{id:"seminar-04",title:"4th seminar",description:"Robot in a maze.\n",last_update:{date:"2023-03-13T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"3rd seminar",permalink:"/pb071/bonuses/seminar-03"},next:{title:"5th and 6th seminar",permalink:"/pb071/bonuses/seminar-05-06"}},p={},m=[{value:"Introduction",id:"introduction",level:2},{value:"Hard requirement",id:"hard-requirement",level:2},{value:"Example of run",id:"example-of-run",level:2},{value:"Bonus part",id:"bonus-part",level:2},{value:"Easter eggs",id:"easter-eggs",level:2},{value:"Submitting",id:"submitting",level:2}],s={toc:m},d="wrapper";function k(t){let{components:e,...n}=t;return(0,r.kt)(d,(0,a.Z)({},s,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Deadline for the submission of the bonus is ",(0,r.kt)("strong",{parentName:"p"},"March 23th 24:00"),".")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"In case you have any questions, feel free to reach out either by email, Discord\nor just by submitting an issue ",(0,r.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/xfocko/kb/-/issues/new"},"here"),".")),(0,r.kt)("p",null,"For this bonus you can get 3 K\u20a1 and another 0.5 K\u20a1 for the bonus part of it."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/04.tar.gz"},"Source")),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"In this task you are given a 2D map for a robot. The map contains multiple markers:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"^v<>")," - which denote the directions the robot will be facing when he steps into\nthe cell or starts on it."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"K")," - denotes the key."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"T")," - denotes the treasure.")),(0,r.kt)("p",null,"In case robot lands at the beginning on unknown field, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},".")," in the tests, he\nfaces the direction that is given through the parameter."),(0,r.kt)("p",null,"Your task is to write the ",(0,r.kt)("inlineCode",{parentName:"p"},"walk")," function that returns end result of the walk.\nWalk can end in multiple ways:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"FOUND_TREASURE")," - when you find the treasure"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"FOUND_KEY")," - when you find the key"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"OUT_OF_BOUNDS")," - when the robot falls off the map"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"INFINITE_LOOP")," - in case you will implement the bonus"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"NONE")," - which is used right now as a default return in the skeleton, has no meaning\nlater on")),(0,r.kt)("h2",{id:"hard-requirement"},"Hard requirement"),(0,r.kt)("p",null,"There is only one hard requirement that tests cannot check."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"You are not allowed to use any indexing related to map or your current position"),"\n",(0,r.kt)("strong",{parentName:"p"},"in your implementation.")),(0,r.kt)("p",null,"Reason for this requirement is for you to get used to working with pointers. And\nfor the implementation of this task it is much easier to use just the pointers."),(0,r.kt)("h2",{id:"example-of-run"},"Example of run"),(0,r.kt)("p",null,"For a better understanding of your task, I will describe a simple walk with corresponding\nfunction call."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'const char *map = (\n ">.v"\n ".K<"\n "..."\n);\n\nwalk(map, &map[6], \'^\', 3, 3);\n')),(0,r.kt)("p",null,"For this call, you should return ",(0,r.kt)("inlineCode",{parentName:"p"},"FOUND_KEY"),". Let us walk through the walk ;)"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Robot is placed at the bottom left corner, there is no direction specified, so\nhe follows the direction given by parameter (upwards, denoted as ",(0,r.kt)("inlineCode",{parentName:"p"},"N"),"(orth),\nso that we can differentiate markers on the map with the robot when using printing\nfunction)."),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.v\n.K<\nN..\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves up:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.v\nNK<\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves up (now covers ",(0,r.kt)("inlineCode",{parentName:"p"},">"),"), changes direction to right:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"E.v\n.K<\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves to right:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">Ev\n.K<\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves to right, faces south:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.S\n.K<\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves down, faces west:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.v\n.KW\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves left, founds key, returns ",(0,r.kt)("inlineCode",{parentName:"p"},"FOUND_KEY"),":"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.v\n.W<\n...\n")))),(0,r.kt)("h2",{id:"bonus-part"},"Bonus part"),(0,r.kt)("p",null,"For the bonus part you are supposed to return ",(0,r.kt)("inlineCode",{parentName:"p"},"INFINITE_LOOP")," in case the robot\nis stuck in the infinite loop. There are three tests for it. If you pass only the\neasy and medium one, you can get 0.25 K\u20a1 for doing your best and trying it out. :)"),(0,r.kt)("h2",{id:"easter-eggs"},"Easter eggs"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Statistics"),(0,r.kt)("table",{parentName:"li"},(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Language"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Files"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Lines"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Blanks"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Comments"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Code"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Complexity"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("em",{parentName:"td"},"C")),(0,r.kt)("td",{parentName:"tr",align:"right"},"4"),(0,r.kt)("td",{parentName:"tr",align:"right"},"458"),(0,r.kt)("td",{parentName:"tr",align:"right"},"34"),(0,r.kt)("td",{parentName:"tr",align:"right"},"58"),(0,r.kt)("td",{parentName:"tr",align:"right"},"366"),(0,r.kt)("td",{parentName:"tr",align:"right"},"33")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"test_maze.c")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"225"),(0,r.kt)("td",{parentName:"tr",align:"right"},"9"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0"),(0,r.kt)("td",{parentName:"tr",align:"right"},"216"),(0,r.kt)("td",{parentName:"tr",align:"right"},"4")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"sol.maze.c")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"141"),(0,r.kt)("td",{parentName:"tr",align:"right"},"15"),(0,r.kt)("td",{parentName:"tr",align:"right"},"28"),(0,r.kt)("td",{parentName:"tr",align:"right"},"98"),(0,r.kt)("td",{parentName:"tr",align:"right"},"24")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"maze.c")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"84"),(0,r.kt)("td",{parentName:"tr",align:"right"},"8"),(0,r.kt)("td",{parentName:"tr",align:"right"},"30"),(0,r.kt)("td",{parentName:"tr",align:"right"},"46"),(0,r.kt)("td",{parentName:"tr",align:"right"},"5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"main.c")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"8"),(0,r.kt)("td",{parentName:"tr",align:"right"},"2"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0"),(0,r.kt)("td",{parentName:"tr",align:"right"},"6"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("em",{parentName:"td"},"C Header")),(0,r.kt)("td",{parentName:"tr",align:"right"},"1"),(0,r.kt)("td",{parentName:"tr",align:"right"},"33"),(0,r.kt)("td",{parentName:"tr",align:"right"},"3"),(0,r.kt)("td",{parentName:"tr",align:"right"},"19"),(0,r.kt)("td",{parentName:"tr",align:"right"},"11"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"maze.h")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"33"),(0,r.kt)("td",{parentName:"tr",align:"right"},"3"),(0,r.kt)("td",{parentName:"tr",align:"right"},"19"),(0,r.kt)("td",{parentName:"tr",align:"right"},"11"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("em",{parentName:"td"},"CMake")),(0,r.kt)("td",{parentName:"tr",align:"right"},"1"),(0,r.kt)("td",{parentName:"tr",align:"right"},"25"),(0,r.kt)("td",{parentName:"tr",align:"right"},"4"),(0,r.kt)("td",{parentName:"tr",align:"right"},"6"),(0,r.kt)("td",{parentName:"tr",align:"right"},"15"),(0,r.kt)("td",{parentName:"tr",align:"right"},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"CMakeLists.txt")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"25"),(0,r.kt)("td",{parentName:"tr",align:"right"},"4"),(0,r.kt)("td",{parentName:"tr",align:"right"},"6"),(0,r.kt)("td",{parentName:"tr",align:"right"},"15"),(0,r.kt)("td",{parentName:"tr",align:"right"},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("strong",{parentName:"td"},"Total")),(0,r.kt)("td",{parentName:"tr",align:"right"},"6"),(0,r.kt)("td",{parentName:"tr",align:"right"},"516"),(0,r.kt)("td",{parentName:"tr",align:"right"},"41"),(0,r.kt)("td",{parentName:"tr",align:"right"},"83"),(0,r.kt)("td",{parentName:"tr",align:"right"},"392"),(0,r.kt)("td",{parentName:"tr",align:"right"},"35"))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Majority of the line count in solution is caused by the formatting :)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Included headers can be interpreted as hints, same goes for the unimplemented\n",(0,r.kt)("inlineCode",{parentName:"p"},"static")," functions which you can use, but ",(0,r.kt)("strong",{parentName:"p"},"are not required"),".")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Given ",(0,r.kt)("inlineCode",{parentName:"p"},"CMakeLists.txt")," will generate 2 binaries, ",(0,r.kt)("inlineCode",{parentName:"p"},"test_maze")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"maze"),"."),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"test_maze")," runs the tests you are given."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"maze")," runs the ",(0,r.kt)("inlineCode",{parentName:"li"},"main.c"),", where you can debug, print mazes and whatever else\nyou want."))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"I keep only one copy of ",(0,r.kt)("inlineCode",{parentName:"p"},"cut.h")," in my repository, so you need to download it from\n",(0,r.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/pb071/cut/-/jobs/159010/artifacts/file/1header/cut.h"},"here")," and place it into the directory where you have your source code."),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Or you can use the one you have from the latest homework, git will keep it\nonly once, so it doesn't take up more space."))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"I would recommend cloning this repository and copying the ",(0,r.kt)("inlineCode",{parentName:"p"},"maze")," directory to\nyour own repository, since there are multiple files and it may be easier for you."))),(0,r.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,r.kt)("h2",{id:"submitting"},"Submitting"),(0,r.kt)("p",null,"For submitting the bonus assignment you can follow the same procedure as for\nsubmitting the homeworks, that is:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"On branch ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," add the provided skeleton."),(0,r.kt)("li",{parentName:"ol"},"Checkout new branch ",(0,r.kt)("inlineCode",{parentName:"li"},"seminar-bonus-04"),"."),(0,r.kt)("li",{parentName:"ol"},"Add your solution to the newly created branch."),(0,r.kt)("li",{parentName:"ol"},"Create a MR to the ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," branch with me (",(0,r.kt)("inlineCode",{parentName:"li"},"@xfocko"),") as the reviewer.")))}k.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2167],{3905:(t,e,n)=>{n.d(e,{Zo:()=>s,kt:()=>h});var a=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function l(t){for(var e=1;e=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var p=a.createContext({}),m=function(t){var e=a.useContext(p),n=e;return t&&(n="function"==typeof t?t(e):l(l({},e),t)),n},s=function(t){var e=m(t.components);return a.createElement(p.Provider,{value:e},t.children)},d="mdxType",k={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},u=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,i=t.originalType,p=t.parentName,s=o(t,["components","mdxType","originalType","parentName"]),d=m(n),u=r,h=d["".concat(p,".").concat(u)]||d[u]||k[u]||i;return n?a.createElement(h,l(l({ref:e},s),{},{components:n})):a.createElement(h,l({ref:e},s))}));function h(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var i=n.length,l=new Array(i);l[0]=u;var o={};for(var p in e)hasOwnProperty.call(e,p)&&(o[p]=e[p]);o.originalType=t,o[d]="string"==typeof t?t:r,l[1]=o;for(var m=2;m{n.r(e),n.d(e,{assets:()=>p,contentTitle:()=>l,default:()=>k,frontMatter:()=>i,metadata:()=>o,toc:()=>m});var a=n(7462),r=(n(7294),n(3905));const i={id:"seminar-04",title:"4th seminar",description:"Robot in a maze.\n",last_update:{date:new Date("2023-03-13T00:00:00.000Z")}},l=void 0,o={unversionedId:"bonuses/seminar-04",id:"bonuses/seminar-04",title:"4th seminar",description:"Robot in a maze.\n",source:"@site/pb071/bonuses/04.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-04",permalink:"/pb071/bonuses/seminar-04",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/bonuses/04.md",tags:[],version:"current",lastUpdatedAt:1678665600,formattedLastUpdatedAt:"Mar 13, 2023",frontMatter:{id:"seminar-04",title:"4th seminar",description:"Robot in a maze.\n",last_update:{date:"2023-03-13T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"3rd seminar",permalink:"/pb071/bonuses/seminar-03"},next:{title:"5th and 6th seminar",permalink:"/pb071/bonuses/seminar-05-06"}},p={},m=[{value:"Introduction",id:"introduction",level:2},{value:"Hard requirement",id:"hard-requirement",level:2},{value:"Example of run",id:"example-of-run",level:2},{value:"Bonus part",id:"bonus-part",level:2},{value:"Easter eggs",id:"easter-eggs",level:2},{value:"Submitting",id:"submitting",level:2}],s={toc:m},d="wrapper";function k(t){let{components:e,...n}=t;return(0,r.kt)(d,(0,a.Z)({},s,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Deadline for the submission of the bonus is ",(0,r.kt)("strong",{parentName:"p"},"March 23th 24:00"),".")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"In case you have any questions, feel free to reach out either by email, Discord\nor just by submitting an issue ",(0,r.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/xfocko/kb/-/issues/new"},"here"),".")),(0,r.kt)("p",null,"For this bonus you can get 3 K\u20a1 and another 0.5 K\u20a1 for the bonus part of it."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/04.tar.gz"},"Source")),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"In this task you are given a 2D map for a robot. The map contains multiple markers:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"^v<>")," - which denote the directions the robot will be facing when he steps into\nthe cell or starts on it."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"K")," - denotes the key."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"T")," - denotes the treasure.")),(0,r.kt)("p",null,"In case robot lands at the beginning on unknown field, e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},".")," in the tests, he\nfaces the direction that is given through the parameter."),(0,r.kt)("p",null,"Your task is to write the ",(0,r.kt)("inlineCode",{parentName:"p"},"walk")," function that returns end result of the walk.\nWalk can end in multiple ways:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"FOUND_TREASURE")," - when you find the treasure"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"FOUND_KEY")," - when you find the key"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"OUT_OF_BOUNDS")," - when the robot falls off the map"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"INFINITE_LOOP")," - in case you will implement the bonus"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"NONE")," - which is used right now as a default return in the skeleton, has no meaning\nlater on")),(0,r.kt)("h2",{id:"hard-requirement"},"Hard requirement"),(0,r.kt)("p",null,"There is only one hard requirement that tests cannot check."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"You are not allowed to use any indexing related to map or your current position"),"\n",(0,r.kt)("strong",{parentName:"p"},"in your implementation.")),(0,r.kt)("p",null,"Reason for this requirement is for you to get used to working with pointers. And\nfor the implementation of this task it is much easier to use just the pointers."),(0,r.kt)("h2",{id:"example-of-run"},"Example of run"),(0,r.kt)("p",null,"For a better understanding of your task, I will describe a simple walk with corresponding\nfunction call."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'const char *map = (\n ">.v"\n ".K<"\n "..."\n);\n\nwalk(map, &map[6], \'^\', 3, 3);\n')),(0,r.kt)("p",null,"For this call, you should return ",(0,r.kt)("inlineCode",{parentName:"p"},"FOUND_KEY"),". Let us walk through the walk ;)"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Robot is placed at the bottom left corner, there is no direction specified, so\nhe follows the direction given by parameter (upwards, denoted as ",(0,r.kt)("inlineCode",{parentName:"p"},"N"),"(orth),\nso that we can differentiate markers on the map with the robot when using printing\nfunction)."),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.v\n.K<\nN..\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves up:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.v\nNK<\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves up (now covers ",(0,r.kt)("inlineCode",{parentName:"p"},">"),"), changes direction to right:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"E.v\n.K<\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves to right:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">Ev\n.K<\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves to right, faces south:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.S\n.K<\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves down, faces west:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.v\n.KW\n...\n"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Moves left, founds key, returns ",(0,r.kt)("inlineCode",{parentName:"p"},"FOUND_KEY"),":"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},">.v\n.W<\n...\n")))),(0,r.kt)("h2",{id:"bonus-part"},"Bonus part"),(0,r.kt)("p",null,"For the bonus part you are supposed to return ",(0,r.kt)("inlineCode",{parentName:"p"},"INFINITE_LOOP")," in case the robot\nis stuck in the infinite loop. There are three tests for it. If you pass only the\neasy and medium one, you can get 0.25 K\u20a1 for doing your best and trying it out. :)"),(0,r.kt)("h2",{id:"easter-eggs"},"Easter eggs"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Statistics"),(0,r.kt)("table",{parentName:"li"},(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Language"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Files"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Lines"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Blanks"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Comments"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Code"),(0,r.kt)("th",{parentName:"tr",align:"right"},"Complexity"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("em",{parentName:"td"},"C")),(0,r.kt)("td",{parentName:"tr",align:"right"},"4"),(0,r.kt)("td",{parentName:"tr",align:"right"},"458"),(0,r.kt)("td",{parentName:"tr",align:"right"},"34"),(0,r.kt)("td",{parentName:"tr",align:"right"},"58"),(0,r.kt)("td",{parentName:"tr",align:"right"},"366"),(0,r.kt)("td",{parentName:"tr",align:"right"},"33")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"test_maze.c")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"225"),(0,r.kt)("td",{parentName:"tr",align:"right"},"9"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0"),(0,r.kt)("td",{parentName:"tr",align:"right"},"216"),(0,r.kt)("td",{parentName:"tr",align:"right"},"4")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"sol.maze.c")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"141"),(0,r.kt)("td",{parentName:"tr",align:"right"},"15"),(0,r.kt)("td",{parentName:"tr",align:"right"},"28"),(0,r.kt)("td",{parentName:"tr",align:"right"},"98"),(0,r.kt)("td",{parentName:"tr",align:"right"},"24")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"maze.c")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"84"),(0,r.kt)("td",{parentName:"tr",align:"right"},"8"),(0,r.kt)("td",{parentName:"tr",align:"right"},"30"),(0,r.kt)("td",{parentName:"tr",align:"right"},"46"),(0,r.kt)("td",{parentName:"tr",align:"right"},"5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"main.c")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"8"),(0,r.kt)("td",{parentName:"tr",align:"right"},"2"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0"),(0,r.kt)("td",{parentName:"tr",align:"right"},"6"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("em",{parentName:"td"},"C Header")),(0,r.kt)("td",{parentName:"tr",align:"right"},"1"),(0,r.kt)("td",{parentName:"tr",align:"right"},"33"),(0,r.kt)("td",{parentName:"tr",align:"right"},"3"),(0,r.kt)("td",{parentName:"tr",align:"right"},"19"),(0,r.kt)("td",{parentName:"tr",align:"right"},"11"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"maze.h")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"33"),(0,r.kt)("td",{parentName:"tr",align:"right"},"3"),(0,r.kt)("td",{parentName:"tr",align:"right"},"19"),(0,r.kt)("td",{parentName:"tr",align:"right"},"11"),(0,r.kt)("td",{parentName:"tr",align:"right"},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("em",{parentName:"td"},"CMake")),(0,r.kt)("td",{parentName:"tr",align:"right"},"1"),(0,r.kt)("td",{parentName:"tr",align:"right"},"25"),(0,r.kt)("td",{parentName:"tr",align:"right"},"4"),(0,r.kt)("td",{parentName:"tr",align:"right"},"6"),(0,r.kt)("td",{parentName:"tr",align:"right"},"15"),(0,r.kt)("td",{parentName:"tr",align:"right"},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"CMakeLists.txt")),(0,r.kt)("td",{parentName:"tr",align:"right"}),(0,r.kt)("td",{parentName:"tr",align:"right"},"25"),(0,r.kt)("td",{parentName:"tr",align:"right"},"4"),(0,r.kt)("td",{parentName:"tr",align:"right"},"6"),(0,r.kt)("td",{parentName:"tr",align:"right"},"15"),(0,r.kt)("td",{parentName:"tr",align:"right"},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("strong",{parentName:"td"},"Total")),(0,r.kt)("td",{parentName:"tr",align:"right"},"6"),(0,r.kt)("td",{parentName:"tr",align:"right"},"516"),(0,r.kt)("td",{parentName:"tr",align:"right"},"41"),(0,r.kt)("td",{parentName:"tr",align:"right"},"83"),(0,r.kt)("td",{parentName:"tr",align:"right"},"392"),(0,r.kt)("td",{parentName:"tr",align:"right"},"35"))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Majority of the line count in solution is caused by the formatting :)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Included headers can be interpreted as hints, same goes for the unimplemented\n",(0,r.kt)("inlineCode",{parentName:"p"},"static")," functions which you can use, but ",(0,r.kt)("strong",{parentName:"p"},"are not required"),".")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Given ",(0,r.kt)("inlineCode",{parentName:"p"},"CMakeLists.txt")," will generate 2 binaries, ",(0,r.kt)("inlineCode",{parentName:"p"},"test_maze")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"maze"),"."),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"test_maze")," runs the tests you are given."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"maze")," runs the ",(0,r.kt)("inlineCode",{parentName:"li"},"main.c"),", where you can debug, print mazes and whatever else\nyou want."))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"I keep only one copy of ",(0,r.kt)("inlineCode",{parentName:"p"},"cut.h")," in my repository, so you need to download it from\n",(0,r.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/pb071/cut/-/jobs/159010/artifacts/file/1header/cut.h"},"here")," and place it into the directory where you have your source code."),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Or you can use the one you have from the latest homework, git will keep it\nonly once, so it doesn't take up more space."))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"I would recommend cloning this repository and copying the ",(0,r.kt)("inlineCode",{parentName:"p"},"maze")," directory to\nyour own repository, since there are multiple files and it may be easier for you."))),(0,r.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,r.kt)("h2",{id:"submitting"},"Submitting"),(0,r.kt)("p",null,"For submitting the bonus assignment you can follow the same procedure as for\nsubmitting the homeworks, that is:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"On branch ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," add the provided skeleton."),(0,r.kt)("li",{parentName:"ol"},"Checkout new branch ",(0,r.kt)("inlineCode",{parentName:"li"},"seminar-bonus-04"),"."),(0,r.kt)("li",{parentName:"ol"},"Add your solution to the newly created branch."),(0,r.kt)("li",{parentName:"ol"},"Create a MR to the ",(0,r.kt)("inlineCode",{parentName:"li"},"main")," branch with me (",(0,r.kt)("inlineCode",{parentName:"li"},"@xfocko"),") as the reviewer.")))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/75cccf44.5b6f1b34.js b/assets/js/75cccf44.4b938733.js similarity index 98% rename from assets/js/75cccf44.5b6f1b34.js rename to assets/js/75cccf44.4b938733.js index 0f2a841..9dc7e54 100644 --- a/assets/js/75cccf44.5b6f1b34.js +++ b/assets/js/75cccf44.4b938733.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[4256],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>u});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function l(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=o.createContext({}),s=function(e){var t=o.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=s(e.components);return o.createElement(c.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),m=s(r),f=n,u=m["".concat(c,".").concat(f)]||m[f]||d[f]||a;return r?o.createElement(u,l(l({ref:t},p),{},{components:r})):o.createElement(u,l({ref:t},p))}));function u(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,l=new Array(a);l[0]=f;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[m]="string"==typeof e?e:n,l[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>s});var o=r(7462),n=(r(7294),r(3905));const a={title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15",slug:"leetcode/sort-diagonally",authors:"mf",tags:["cpp","leetcode","iterators"],hide_table_of_contents:!1},l=void 0,i={permalink:"/blog/leetcode/sort-diagonally",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/leetcode/sort-matrix-diagonally.md",source:"@site/blog/leetcode/sort-matrix-diagonally.md",title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15:00.000Z",formattedDate:"March 4, 2023",tags:[{label:"cpp",permalink:"/blog/tags/cpp"},{label:"leetcode",permalink:"/blog/tags/leetcode"},{label:"iterators",permalink:"/blog/tags/iterators"}],readingTime:16.99,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15",slug:"leetcode/sort-diagonally",authors:"mf",tags:["cpp","leetcode","iterators"],hide_table_of_contents:!1},prevItem:{title:"3rd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/3rd-week"},nextItem:{title:"2nd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/2nd-week"}},c={authorsImageUrls:[void 0]},s=[],p={toc:s},m="wrapper";function d(e){let{components:t,...r}=e;return(0,n.kt)(m,(0,o.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Let's try to solve one of the LeetCode challenges in easy and hard mode at the\nsame time."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[4256],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>u});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function l(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=o.createContext({}),s=function(e){var t=o.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=s(e.components);return o.createElement(c.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),m=s(r),f=n,u=m["".concat(c,".").concat(f)]||m[f]||d[f]||a;return r?o.createElement(u,l(l({ref:t},p),{},{components:r})):o.createElement(u,l({ref:t},p))}));function u(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,l=new Array(a);l[0]=f;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[m]="string"==typeof e?e:n,l[1]=i;for(var s=2;s{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>s});var o=r(7462),n=(r(7294),r(3905));const a={title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15",slug:"leetcode/sort-diagonally",authors:"mf",tags:["cpp","leetcode","iterators"],hide_table_of_contents:!1},l=void 0,i={permalink:"/blog/leetcode/sort-diagonally",editUrl:"https://github.com/mfocko/blog/tree/main/blog/leetcode/sort-matrix-diagonally.md",source:"@site/blog/leetcode/sort-matrix-diagonally.md",title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15:00.000Z",formattedDate:"March 4, 2023",tags:[{label:"cpp",permalink:"/blog/tags/cpp"},{label:"leetcode",permalink:"/blog/tags/leetcode"},{label:"iterators",permalink:"/blog/tags/iterators"}],readingTime:16.99,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15",slug:"leetcode/sort-diagonally",authors:"mf",tags:["cpp","leetcode","iterators"],hide_table_of_contents:!1},prevItem:{title:"3rd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/3rd-week"},nextItem:{title:"2nd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/2nd-week"}},c={authorsImageUrls:[void 0]},s=[],p={toc:s},m="wrapper";function d(e){let{components:t,...r}=e;return(0,n.kt)(m,(0,o.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Let's try to solve one of the LeetCode challenges in easy and hard mode at the\nsame time."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/788cc978.7cfa1cd4.js b/assets/js/788cc978.6c7e62a6.js similarity index 99% rename from assets/js/788cc978.7cfa1cd4.js rename to assets/js/788cc978.6c7e62a6.js index ce2c9df..467ebe2 100644 --- a/assets/js/788cc978.7cfa1cd4.js +++ b/assets/js/788cc978.6c7e62a6.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9157],{3905:(e,a,t)=>{t.d(a,{Zo:()=>o,kt:()=>h});var n=t(7294);function m(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function s(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function r(e){for(var a=1;a=0||(m[t]=e[t]);return m}(e,a);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(m[t]=e[t])}return m}var i=n.createContext({}),l=function(e){var a=n.useContext(i),t=a;return e&&(t="function"==typeof e?e(a):r(r({},a),e)),t},o=function(e){var a=l(e.components);return n.createElement(i.Provider,{value:a},e.children)},c="mdxType",N={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},k=n.forwardRef((function(e,a){var t=e.components,m=e.mdxType,s=e.originalType,i=e.parentName,o=p(e,["components","mdxType","originalType","parentName"]),c=l(t),k=m,h=c["".concat(i,".").concat(k)]||c[k]||N[k]||s;return t?n.createElement(h,r(r({ref:a},o),{},{components:t})):n.createElement(h,r({ref:a},o))}));function h(e,a){var t=arguments,m=a&&a.mdxType;if("string"==typeof e||m){var s=t.length,r=new Array(s);r[0]=k;var p={};for(var i in a)hasOwnProperty.call(a,i)&&(p[i]=a[i]);p.originalType=e,p[c]="string"==typeof e?e:m,r[1]=p;for(var l=2;l{t.r(a),t.d(a,{assets:()=>i,contentTitle:()=>r,default:()=>N,frontMatter:()=>s,metadata:()=>p,toc:()=>l});var n=t(7462),m=(t(7294),t(3905));const s={id:"extend",title:"Time complexity of \u2039extend\u203a",description:"How to make inefficient algorithm unknowingly.\n",tags:["c","python","dynamic array","time complexity","recursion"],last_update:{date:new Date("2021-03-31T00:00:00.000Z")}},r=void 0,p={unversionedId:"time-complexity/extend",id:"time-complexity/extend",title:"Time complexity of \u2039extend\u203a",description:"How to make inefficient algorithm unknowingly.\n",source:"@site/ib002/03-time-complexity/2021-03-31-extend.md",sourceDirName:"03-time-complexity",slug:"/time-complexity/extend",permalink:"/ib002/time-complexity/extend",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/03-time-complexity/2021-03-31-extend.md",tags:[{label:"c",permalink:"/ib002/tags/c"},{label:"python",permalink:"/ib002/tags/python"},{label:"dynamic array",permalink:"/ib002/tags/dynamic-array"},{label:"time complexity",permalink:"/ib002/tags/time-complexity"},{label:"recursion",permalink:"/ib002/tags/recursion"}],version:"current",lastUpdatedAt:1617148800,formattedLastUpdatedAt:"Mar 31, 2021",frontMatter:{id:"extend",title:"Time complexity of \u2039extend\u203a",description:"How to make inefficient algorithm unknowingly.\n",tags:["c","python","dynamic array","time complexity","recursion"],last_update:{date:"2021-03-31T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Asymptotic Notation and Time Complexity",permalink:"/ib002/category/asymptotic-notation-and-time-complexity"},next:{title:"Recursion",permalink:"/ib002/category/recursion"}},i={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Technicalities",id:"technicalities",level:2},{value:"Example #1",id:"example-1",level:2},{value:"Example #2",id:"example-2",level:2},{value:"Implementation of extend",id:"implementation-of-extend",level:2}],o={toc:l},c="wrapper";function N(e){let{components:a,...s}=e;return(0,m.kt)(c,(0,n.Z)({},o,s,{components:a,mdxType:"MDXLayout"}),(0,m.kt)("h2",{id:"introduction"},"Introduction"),(0,m.kt)("p",null,"Each year there is a lot of confusion regarding time complexity of the ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," operation on the lists in Python. I will introduce two specific examples from previous year and also will try to explain it on one of the possible implementations of ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," operation."),(0,m.kt)("h2",{id:"technicalities"},"Technicalities"),(0,m.kt)("p",null,"At the beginning we should clear some of the \u201cmyths\u201d regarding extending of the lists. There is a common misunderstanding regarding differences between ",(0,m.kt)("inlineCode",{parentName:"p"},"a += b"),", ",(0,m.kt)("inlineCode",{parentName:"p"},"a.extend(b)")," and ",(0,m.kt)("inlineCode",{parentName:"p"},"a + b"),"."),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},(0,m.kt)("inlineCode",{parentName:"p"},"a.extend(b)")," - adds all elements from ",(0,m.kt)("inlineCode",{parentName:"p"},"b")," to ",(0,m.kt)("inlineCode",{parentName:"p"},"a"),"."),(0,m.kt)("p",{parentName:"li"},"Time complexity: ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," denotes the length of ",(0,m.kt)("inlineCode",{parentName:"p"},"b"),".")),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},(0,m.kt)("inlineCode",{parentName:"p"},"a += b")," - equivalent to ",(0,m.kt)("inlineCode",{parentName:"p"},"a.extend(b)"))),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},(0,m.kt)("inlineCode",{parentName:"p"},"a + b")," - constructs a new list that contains elements from ",(0,m.kt)("inlineCode",{parentName:"p"},"a")," followed by\nelements from ",(0,m.kt)("inlineCode",{parentName:"p"},"b"),"."),(0,m.kt)("p",{parentName:"li"},"Time complexity: ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"m"),(0,m.kt)("mo",{parentName:"mrow"},"+"),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(m + n)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"m"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,m.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"m"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"m, n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"m"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," denote the length of\n",(0,m.kt)("inlineCode",{parentName:"p"},"a")," and ",(0,m.kt)("inlineCode",{parentName:"p"},"b")," respectively."),(0,m.kt)("p",{parentName:"li"},"Space complexity: ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"m"),(0,m.kt)("mo",{parentName:"mrow"},"+"),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(m + n)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"m"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,m.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"m"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"m, n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"m"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," denote the length of\n",(0,m.kt)("inlineCode",{parentName:"p"},"a")," and ",(0,m.kt)("inlineCode",{parentName:"p"},"b")," respectively, since we construct new list."))),(0,m.kt)("h2",{id:"example-1"},"Example #1"),(0,m.kt)("p",null,"Let us assume function that uses divide & conquer strategy to return indices at which we can find specific element in any list."),(0,m.kt)("pre",null,(0,m.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def recursive_find_in_list(\n values: List[Any], key: Any, lower: int, upper: int\n) -> List[int]:\n if lower == upper:\n return [lower] if values[lower] == key else []\n\n indices = []\n mid = (lower + upper) // 2\n\n indices.extend(recursive_find_in_list(values, key, lower, mid))\n indices.extend(recursive_find_in_list(values, key, mid + 1, upper))\n\n return indices\n\n\ndef find_in_list(values: List[Any], key: Any) -> List[int]:\n return recursive_find_in_list(values, key, 0, len(values) - 1)\n")),(0,m.kt)("p",null,"This implementation works nicely, ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," is linear (with the respect to the length of the list that is being appended)."),(0,m.kt)("p",null,"Let us try to dissect the way this function works on some specific input (that will be pushed to the extreme, ",(0,m.kt)("em",{parentName:"p"},"just in case")," ;)"),(0,m.kt)("p",null,(0,m.kt)("inlineCode",{parentName:"p"},"find_in_list([1] * 5000, 1)"),". What shall be the result of this? Since we have ",(0,m.kt)("inlineCode",{parentName:"p"},"key = 1")," and the list contains only ",(0,m.kt)("inlineCode",{parentName:"p"},"1"),"s, we should get list of ",(0,m.kt)("strong",{parentName:"p"},"all")," indices."),(0,m.kt)("p",null,"If we were to draw a tree of call hierarchy of ",(0,m.kt)("inlineCode",{parentName:"p"},"recursive_find_in_list"),", we would notice that in sum it is still linear to the length. ",(0,m.kt)("strong",{parentName:"p"},"However we use ",(0,m.kt)("inlineCode",{parentName:"strong"},"extend"),"!")),(0,m.kt)("p",null,"In the leaves of the tree we return lists of length 1. In this case it means calling ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," 5000-times at the second-to-last level of the tree on the 1-element long lists, next level 2500 calls on 2-elements long lists, next one 1250 on 4-elements long lists, etc. At the top-level we get 2 calls on 5000/2-element long lists."),(0,m.kt)("p",null,"A lot of ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," calls, right? And the lengths of the lists are growing (in this example, second call happens on 2500-elements long lists)."),(0,m.kt)("p",null,"Because of the ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," in each level of the tree (call hierarchy) we traverse all of the elements. That means:"),(0,m.kt)("div",{className:"math math-display"},(0,m.kt)("span",{parentName:"div",className:"katex-display"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,m.kt)("mi",{parentName:"mrow"},"log"),(0,m.kt)("mo",{parentName:"mrow"},"\u2061"),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n \\cdot \\log n)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,m.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mop"},"lo",(0,m.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,m.kt)("p",null,"because we have ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"log"),(0,m.kt)("mo",{parentName:"mrow"},"\u2061"),(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\log n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mop"},"lo",(0,m.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," levels in the tree and ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," elements at each level."),(0,m.kt)("h2",{id:"example-2"},"Example #2"),(0,m.kt)("p",null,"As we could observe in the example above, ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," iterates over all of the elements that it adds. In case of recursive calls, it results in iterating over the same elements multiple times."),(0,m.kt)("p",null,"Consider constructing of this list:"),(0,m.kt)("p",null,(0,m.kt)("img",{alt:"Rendered construction of the list",src:t(1493).Z+"#gh-light-mode-only",width:"851",height:"276"}),"\n",(0,m.kt)("img",{alt:"Rendered construction of the list",src:t(4758).Z+"#gh-dark-mode-only",width:"851",height:"276"})),(0,m.kt)("p",null,"Let us assume that you extend the result with the list that you get from the recursive call."),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},"B iterates through 1, 2 and 3; returns ",(0,m.kt)("inlineCode",{parentName:"p"},"[1, 2, 3]"))),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},"C iterates through 4, 5 and 6; returns ",(0,m.kt)("inlineCode",{parentName:"p"},"[4, 5, 6]"))),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},"D iterates through 7, 8 and 9; returns ",(0,m.kt)("inlineCode",{parentName:"p"},"[7, 8, 9]"))),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},"now we return those lists to the calls from A), so each of the ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," calls iterates through:"),(0,m.kt)("ul",{parentName:"li"},(0,m.kt)("li",{parentName:"ul"},"1, 2, 3 that was returned from B"),(0,m.kt)("li",{parentName:"ul"},"4, 5, 6 that was returned from C"),(0,m.kt)("li",{parentName:"ul"},"7, 8, 9 that was returned from D")),(0,m.kt)("p",{parentName:"li"},"and returns ",(0,m.kt)("inlineCode",{parentName:"p"},"[1, 2, 3, 4, 5, 6, 7, 8, 9]")))),(0,m.kt)("p",null,"If the recursion had bigger depth and/or more elements, it would iterate through them more than twice, therefore it does not take constant time to do nor some constant multiple of the input, since it traverses all of the elements in each of the levels."),(0,m.kt)("h2",{id:"implementation-of-extend"},"Implementation of ",(0,m.kt)("inlineCode",{parentName:"h2"},"extend")),(0,m.kt)("p",null,"There is an example of dynamic array:"),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("a",{parentName:"li",href:"pathname:///files/ib002/time-complexity/extend/dynlist.h"},"interface (",(0,m.kt)("inlineCode",{parentName:"a"},"dynlist.h"),")")),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("a",{parentName:"li",href:"pathname:///files/ib002/time-complexity/extend/dynlist.c"},"implementation (",(0,m.kt)("inlineCode",{parentName:"a"},"dynlist.c"),")"))),(0,m.kt)("p",null,"For the sake of ",(0,m.kt)("em",{parentName:"p"},"Algorithms and Data Structures I")," we consider ",(0,m.kt)("inlineCode",{parentName:"p"},"APPEND")," operation, i.e. adding the element to the end of the list, to have time complexity ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mn",{parentName:"mrow"},"1"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(1)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord"},"1"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")")))))," (",(0,m.kt)("strong",{parentName:"p"},"amortized"),"; which is out of the scope of IB002)."),(0,m.kt)("p",null,"If we have a look at the ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," implementation in this dynamic array example:"),(0,m.kt)("pre",null,(0,m.kt)("code",{parentName:"pre",className:"language-c",metastring:"showLineNumbers",showLineNumbers:!0},"void dynamic_array_extend(struct dynamic_array_t *arr, struct dynamic_array_t *src)\n{\n if (arr == NULL || src == NULL)\n {\n return;\n }\n\n for (size_t i = 0; i < src->count; i++)\n {\n dynamic_array_push_back(arr, dynamic_array_at(src, i));\n }\n}\n")),(0,m.kt)("p",null,"Apart from checking edge cases, we can notice that we run ",(0,m.kt)("inlineCode",{parentName:"p"},"for"),"-loop over the elements from the other array and add them one-by-one to the ",(0,m.kt)("inlineCode",{parentName:"p"},"arr"),". Time complexity of this operation is time dependant on the ",(0,m.kt)("inlineCode",{parentName:"p"},"src")," array."),(0,m.kt)("p",null,"In this specific implementation, you could also resize the memory allocated for the array in one go and copy ",(0,m.kt)("em",{parentName:"p"},"whole")," ",(0,m.kt)("inlineCode",{parentName:"p"},"src")," array in one go. However even if you did so, it would be still dependant on the size of the ",(0,m.kt)("inlineCode",{parentName:"p"},"src")," array. Cause you still need to copy ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mtext",{parentName:"mrow",mathvariant:"monospace"},"count"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"s"),(0,m.kt)("mi",{parentName:"mrow"},"r"),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,m.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,m.kt)("mtext",{parentName:"mrow",mathvariant:"monospace"},"elementSize"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"s"),(0,m.kt)("mi",{parentName:"mrow"},"r"),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\texttt{count}(src) \\cdot \\texttt{elementSize}(src)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord text"},(0,m.kt)("span",{parentName:"span",className:"mord texttt"},"count")),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"src"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,m.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord text"},(0,m.kt)("span",{parentName:"span",className:"mord texttt"},"elementSize")),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"src"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")")))))," bytes. From that we can assume that for specific instance of array the ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mtext",{parentName:"mrow",mathvariant:"monospace"},"elementSize"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"s"),(0,m.kt)("mi",{parentName:"mrow"},"r"),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\texttt{elementSize}(src)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord text"},(0,m.kt)("span",{parentName:"span",className:"mord texttt"},"elementSize")),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"src"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")")))))," is fixed, therefore we consider it a constant. That way we are getting ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mtext",{parentName:"mrow",mathvariant:"monospace"},"count"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"s"),(0,m.kt)("mi",{parentName:"mrow"},"r"),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(\\texttt{count}(src))")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord text"},(0,m.kt)("span",{parentName:"span",className:"mord texttt"},"count")),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"src"),(0,m.kt)("span",{parentName:"span",className:"mclose"},"))")))))," as a time complexity of our ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," operation."))}N.isMDXComponent=!0},4758:(e,a,t)=>{t.d(a,{Z:()=>n});const n=t.p+"assets/images/construction_dark-fac28e7cafcc43d7e2fb5f0b6c25504e.svg"},1493:(e,a,t)=>{t.d(a,{Z:()=>n});const n=t.p+"assets/images/construction_light-02b0be76041a8b1379107378e8f8b64c.svg"}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9157],{3905:(e,a,t)=>{t.d(a,{Zo:()=>o,kt:()=>h});var n=t(7294);function m(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function s(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function r(e){for(var a=1;a=0||(m[t]=e[t]);return m}(e,a);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(m[t]=e[t])}return m}var i=n.createContext({}),l=function(e){var a=n.useContext(i),t=a;return e&&(t="function"==typeof e?e(a):r(r({},a),e)),t},o=function(e){var a=l(e.components);return n.createElement(i.Provider,{value:a},e.children)},c="mdxType",N={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},k=n.forwardRef((function(e,a){var t=e.components,m=e.mdxType,s=e.originalType,i=e.parentName,o=p(e,["components","mdxType","originalType","parentName"]),c=l(t),k=m,h=c["".concat(i,".").concat(k)]||c[k]||N[k]||s;return t?n.createElement(h,r(r({ref:a},o),{},{components:t})):n.createElement(h,r({ref:a},o))}));function h(e,a){var t=arguments,m=a&&a.mdxType;if("string"==typeof e||m){var s=t.length,r=new Array(s);r[0]=k;var p={};for(var i in a)hasOwnProperty.call(a,i)&&(p[i]=a[i]);p.originalType=e,p[c]="string"==typeof e?e:m,r[1]=p;for(var l=2;l{t.r(a),t.d(a,{assets:()=>i,contentTitle:()=>r,default:()=>N,frontMatter:()=>s,metadata:()=>p,toc:()=>l});var n=t(7462),m=(t(7294),t(3905));const s={id:"extend",title:"Time complexity of \u2039extend\u203a",description:"How to make inefficient algorithm unknowingly.\n",tags:["c","python","dynamic array","time complexity","recursion"],last_update:{date:new Date("2021-03-31T00:00:00.000Z")}},r=void 0,p={unversionedId:"time-complexity/extend",id:"time-complexity/extend",title:"Time complexity of \u2039extend\u203a",description:"How to make inefficient algorithm unknowingly.\n",source:"@site/ib002/03-time-complexity/2021-03-31-extend.md",sourceDirName:"03-time-complexity",slug:"/time-complexity/extend",permalink:"/ib002/time-complexity/extend",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/03-time-complexity/2021-03-31-extend.md",tags:[{label:"c",permalink:"/ib002/tags/c"},{label:"python",permalink:"/ib002/tags/python"},{label:"dynamic array",permalink:"/ib002/tags/dynamic-array"},{label:"time complexity",permalink:"/ib002/tags/time-complexity"},{label:"recursion",permalink:"/ib002/tags/recursion"}],version:"current",lastUpdatedAt:1617148800,formattedLastUpdatedAt:"Mar 31, 2021",frontMatter:{id:"extend",title:"Time complexity of \u2039extend\u203a",description:"How to make inefficient algorithm unknowingly.\n",tags:["c","python","dynamic array","time complexity","recursion"],last_update:{date:"2021-03-31T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Asymptotic Notation and Time Complexity",permalink:"/ib002/category/asymptotic-notation-and-time-complexity"},next:{title:"Recursion",permalink:"/ib002/category/recursion"}},i={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Technicalities",id:"technicalities",level:2},{value:"Example #1",id:"example-1",level:2},{value:"Example #2",id:"example-2",level:2},{value:"Implementation of extend",id:"implementation-of-extend",level:2}],o={toc:l},c="wrapper";function N(e){let{components:a,...s}=e;return(0,m.kt)(c,(0,n.Z)({},o,s,{components:a,mdxType:"MDXLayout"}),(0,m.kt)("h2",{id:"introduction"},"Introduction"),(0,m.kt)("p",null,"Each year there is a lot of confusion regarding time complexity of the ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," operation on the lists in Python. I will introduce two specific examples from previous year and also will try to explain it on one of the possible implementations of ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," operation."),(0,m.kt)("h2",{id:"technicalities"},"Technicalities"),(0,m.kt)("p",null,"At the beginning we should clear some of the \u201cmyths\u201d regarding extending of the lists. There is a common misunderstanding regarding differences between ",(0,m.kt)("inlineCode",{parentName:"p"},"a += b"),", ",(0,m.kt)("inlineCode",{parentName:"p"},"a.extend(b)")," and ",(0,m.kt)("inlineCode",{parentName:"p"},"a + b"),"."),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},(0,m.kt)("inlineCode",{parentName:"p"},"a.extend(b)")," - adds all elements from ",(0,m.kt)("inlineCode",{parentName:"p"},"b")," to ",(0,m.kt)("inlineCode",{parentName:"p"},"a"),"."),(0,m.kt)("p",{parentName:"li"},"Time complexity: ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," denotes the length of ",(0,m.kt)("inlineCode",{parentName:"p"},"b"),".")),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},(0,m.kt)("inlineCode",{parentName:"p"},"a += b")," - equivalent to ",(0,m.kt)("inlineCode",{parentName:"p"},"a.extend(b)"))),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},(0,m.kt)("inlineCode",{parentName:"p"},"a + b")," - constructs a new list that contains elements from ",(0,m.kt)("inlineCode",{parentName:"p"},"a")," followed by\nelements from ",(0,m.kt)("inlineCode",{parentName:"p"},"b"),"."),(0,m.kt)("p",{parentName:"li"},"Time complexity: ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"m"),(0,m.kt)("mo",{parentName:"mrow"},"+"),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(m + n)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"m"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,m.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"m"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"m, n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"m"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," denote the length of\n",(0,m.kt)("inlineCode",{parentName:"p"},"a")," and ",(0,m.kt)("inlineCode",{parentName:"p"},"b")," respectively."),(0,m.kt)("p",{parentName:"li"},"Space complexity: ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"m"),(0,m.kt)("mo",{parentName:"mrow"},"+"),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(m + n)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"m"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,m.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"m"),(0,m.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"m, n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"m"),(0,m.kt)("span",{parentName:"span",className:"mpunct"},","),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," denote the length of\n",(0,m.kt)("inlineCode",{parentName:"p"},"a")," and ",(0,m.kt)("inlineCode",{parentName:"p"},"b")," respectively, since we construct new list."))),(0,m.kt)("h2",{id:"example-1"},"Example #1"),(0,m.kt)("p",null,"Let us assume function that uses divide & conquer strategy to return indices at which we can find specific element in any list."),(0,m.kt)("pre",null,(0,m.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def recursive_find_in_list(\n values: List[Any], key: Any, lower: int, upper: int\n) -> List[int]:\n if lower == upper:\n return [lower] if values[lower] == key else []\n\n indices = []\n mid = (lower + upper) // 2\n\n indices.extend(recursive_find_in_list(values, key, lower, mid))\n indices.extend(recursive_find_in_list(values, key, mid + 1, upper))\n\n return indices\n\n\ndef find_in_list(values: List[Any], key: Any) -> List[int]:\n return recursive_find_in_list(values, key, 0, len(values) - 1)\n")),(0,m.kt)("p",null,"This implementation works nicely, ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," is linear (with the respect to the length of the list that is being appended)."),(0,m.kt)("p",null,"Let us try to dissect the way this function works on some specific input (that will be pushed to the extreme, ",(0,m.kt)("em",{parentName:"p"},"just in case")," ;)"),(0,m.kt)("p",null,(0,m.kt)("inlineCode",{parentName:"p"},"find_in_list([1] * 5000, 1)"),". What shall be the result of this? Since we have ",(0,m.kt)("inlineCode",{parentName:"p"},"key = 1")," and the list contains only ",(0,m.kt)("inlineCode",{parentName:"p"},"1"),"s, we should get list of ",(0,m.kt)("strong",{parentName:"p"},"all")," indices."),(0,m.kt)("p",null,"If we were to draw a tree of call hierarchy of ",(0,m.kt)("inlineCode",{parentName:"p"},"recursive_find_in_list"),", we would notice that in sum it is still linear to the length. ",(0,m.kt)("strong",{parentName:"p"},"However we use ",(0,m.kt)("inlineCode",{parentName:"strong"},"extend"),"!")),(0,m.kt)("p",null,"In the leaves of the tree we return lists of length 1. In this case it means calling ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," 5000-times at the second-to-last level of the tree on the 1-element long lists, next level 2500 calls on 2-elements long lists, next one 1250 on 4-elements long lists, etc. At the top-level we get 2 calls on 5000/2-element long lists."),(0,m.kt)("p",null,"A lot of ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," calls, right? And the lengths of the lists are growing (in this example, second call happens on 2500-elements long lists)."),(0,m.kt)("p",null,"Because of the ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," in each level of the tree (call hierarchy) we traverse all of the elements. That means:"),(0,m.kt)("div",{className:"math math-display"},(0,m.kt)("span",{parentName:"div",className:"katex-display"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,m.kt)("mi",{parentName:"mrow"},"log"),(0,m.kt)("mo",{parentName:"mrow"},"\u2061"),(0,m.kt)("mi",{parentName:"mrow"},"n"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n \\cdot \\log n)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,m.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mop"},"lo",(0,m.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,m.kt)("p",null,"because we have ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"log"),(0,m.kt)("mo",{parentName:"mrow"},"\u2061"),(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\log n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,m.kt)("span",{parentName:"span",className:"mop"},"lo",(0,m.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," levels in the tree and ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow"},"n")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," elements at each level."),(0,m.kt)("h2",{id:"example-2"},"Example #2"),(0,m.kt)("p",null,"As we could observe in the example above, ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," iterates over all of the elements that it adds. In case of recursive calls, it results in iterating over the same elements multiple times."),(0,m.kt)("p",null,"Consider constructing of this list:"),(0,m.kt)("p",null,(0,m.kt)("img",{alt:"Rendered construction of the list",src:t(1493).Z+"#gh-light-mode-only",width:"851",height:"276"}),"\n",(0,m.kt)("img",{alt:"Rendered construction of the list",src:t(4758).Z+"#gh-dark-mode-only",width:"851",height:"276"})),(0,m.kt)("p",null,"Let us assume that you extend the result with the list that you get from the recursive call."),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},"B iterates through 1, 2 and 3; returns ",(0,m.kt)("inlineCode",{parentName:"p"},"[1, 2, 3]"))),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},"C iterates through 4, 5 and 6; returns ",(0,m.kt)("inlineCode",{parentName:"p"},"[4, 5, 6]"))),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},"D iterates through 7, 8 and 9; returns ",(0,m.kt)("inlineCode",{parentName:"p"},"[7, 8, 9]"))),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("p",{parentName:"li"},"now we return those lists to the calls from A), so each of the ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," calls iterates through:"),(0,m.kt)("ul",{parentName:"li"},(0,m.kt)("li",{parentName:"ul"},"1, 2, 3 that was returned from B"),(0,m.kt)("li",{parentName:"ul"},"4, 5, 6 that was returned from C"),(0,m.kt)("li",{parentName:"ul"},"7, 8, 9 that was returned from D")),(0,m.kt)("p",{parentName:"li"},"and returns ",(0,m.kt)("inlineCode",{parentName:"p"},"[1, 2, 3, 4, 5, 6, 7, 8, 9]")))),(0,m.kt)("p",null,"If the recursion had bigger depth and/or more elements, it would iterate through them more than twice, therefore it does not take constant time to do nor some constant multiple of the input, since it traverses all of the elements in each of the levels."),(0,m.kt)("h2",{id:"implementation-of-extend"},"Implementation of ",(0,m.kt)("inlineCode",{parentName:"h2"},"extend")),(0,m.kt)("p",null,"There is an example of dynamic array:"),(0,m.kt)("ul",null,(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("a",{parentName:"li",href:"pathname:///files/ib002/time-complexity/extend/dynlist.h"},"interface (",(0,m.kt)("inlineCode",{parentName:"a"},"dynlist.h"),")")),(0,m.kt)("li",{parentName:"ul"},(0,m.kt)("a",{parentName:"li",href:"pathname:///files/ib002/time-complexity/extend/dynlist.c"},"implementation (",(0,m.kt)("inlineCode",{parentName:"a"},"dynlist.c"),")"))),(0,m.kt)("p",null,"For the sake of ",(0,m.kt)("em",{parentName:"p"},"Algorithms and Data Structures I")," we consider ",(0,m.kt)("inlineCode",{parentName:"p"},"APPEND")," operation, i.e. adding the element to the end of the list, to have time complexity ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mn",{parentName:"mrow"},"1"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(1)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord"},"1"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")")))))," (",(0,m.kt)("strong",{parentName:"p"},"amortized"),"; which is out of the scope of IB002)."),(0,m.kt)("p",null,"If we have a look at the ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," implementation in this dynamic array example:"),(0,m.kt)("pre",null,(0,m.kt)("code",{parentName:"pre",className:"language-c",metastring:"showLineNumbers",showLineNumbers:!0},"void dynamic_array_extend(struct dynamic_array_t *arr, struct dynamic_array_t *src)\n{\n if (arr == NULL || src == NULL)\n {\n return;\n }\n\n for (size_t i = 0; i < src->count; i++)\n {\n dynamic_array_push_back(arr, dynamic_array_at(src, i));\n }\n}\n")),(0,m.kt)("p",null,"Apart from checking edge cases, we can notice that we run ",(0,m.kt)("inlineCode",{parentName:"p"},"for"),"-loop over the elements from the other array and add them one-by-one to the ",(0,m.kt)("inlineCode",{parentName:"p"},"arr"),". Time complexity of this operation is time dependant on the ",(0,m.kt)("inlineCode",{parentName:"p"},"src")," array."),(0,m.kt)("p",null,"In this specific implementation, you could also resize the memory allocated for the array in one go and copy ",(0,m.kt)("em",{parentName:"p"},"whole")," ",(0,m.kt)("inlineCode",{parentName:"p"},"src")," array in one go. However even if you did so, it would be still dependant on the size of the ",(0,m.kt)("inlineCode",{parentName:"p"},"src")," array. Cause you still need to copy ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mtext",{parentName:"mrow",mathvariant:"monospace"},"count"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"s"),(0,m.kt)("mi",{parentName:"mrow"},"r"),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,m.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,m.kt)("mtext",{parentName:"mrow",mathvariant:"monospace"},"elementSize"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"s"),(0,m.kt)("mi",{parentName:"mrow"},"r"),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\texttt{count}(src) \\cdot \\texttt{elementSize}(src)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord text"},(0,m.kt)("span",{parentName:"span",className:"mord texttt"},"count")),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"src"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,m.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,m.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord text"},(0,m.kt)("span",{parentName:"span",className:"mord texttt"},"elementSize")),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"src"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")")))))," bytes. From that we can assume that for specific instance of array the ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mtext",{parentName:"mrow",mathvariant:"monospace"},"elementSize"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"s"),(0,m.kt)("mi",{parentName:"mrow"},"r"),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\texttt{elementSize}(src)")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord text"},(0,m.kt)("span",{parentName:"span",className:"mord texttt"},"elementSize")),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"src"),(0,m.kt)("span",{parentName:"span",className:"mclose"},")")))))," is fixed, therefore we consider it a constant. That way we are getting ",(0,m.kt)("span",{parentName:"p",className:"math math-inline"},(0,m.kt)("span",{parentName:"span",className:"katex"},(0,m.kt)("span",{parentName:"span",className:"katex-mathml"},(0,m.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,m.kt)("semantics",{parentName:"math"},(0,m.kt)("mrow",{parentName:"semantics"},(0,m.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mtext",{parentName:"mrow",mathvariant:"monospace"},"count"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,m.kt)("mi",{parentName:"mrow"},"s"),(0,m.kt)("mi",{parentName:"mrow"},"r"),(0,m.kt)("mi",{parentName:"mrow"},"c"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,m.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,m.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(\\texttt{count}(src))")))),(0,m.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,m.kt)("span",{parentName:"span",className:"base"},(0,m.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,m.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord text"},(0,m.kt)("span",{parentName:"span",className:"mord texttt"},"count")),(0,m.kt)("span",{parentName:"span",className:"mopen"},"("),(0,m.kt)("span",{parentName:"span",className:"mord mathnormal"},"src"),(0,m.kt)("span",{parentName:"span",className:"mclose"},"))")))))," as a time complexity of our ",(0,m.kt)("inlineCode",{parentName:"p"},"extend")," operation."))}N.isMDXComponent=!0},4758:(e,a,t)=>{t.d(a,{Z:()=>n});const n=t.p+"assets/images/construction_dark-fac28e7cafcc43d7e2fb5f0b6c25504e.svg"},1493:(e,a,t)=>{t.d(a,{Z:()=>n});const n=t.p+"assets/images/construction_light-02b0be76041a8b1379107378e8f8b64c.svg"}}]); \ No newline at end of file diff --git a/assets/js/7cf94373.373d5a6c.js b/assets/js/7cf94373.7832df69.js similarity index 98% rename from assets/js/7cf94373.373d5a6c.js rename to assets/js/7cf94373.7832df69.js index 6754573..d3c22a3 100644 --- a/assets/js/7cf94373.373d5a6c.js +++ b/assets/js/7cf94373.7832df69.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3095],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=p(n),d=r,k=m["".concat(s,".").concat(d)]||m[d]||c[d]||i;return n?a.createElement(k,o(o({ref:t},u),{},{components:n})):a.createElement(k,o({ref:t},u))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:r,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={id:"seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n"},o=void 0,l={unversionedId:"bonuses/seminar-10",id:"bonuses/seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n",source:"@site/pb071/bonuses/10.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-10",permalink:"/pb071/bonuses/seminar-10",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/10.md",tags:[],version:"current",lastUpdatedAt:1694110423,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n"},sidebar:"autogeneratedBar",previous:{title:"8th seminar",permalink:"/pb071/bonuses/seminar-08"},next:{title:"Practice Exams",permalink:"/pb071/category/practice-exams"}},s={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Project",id:"project",level:2},{value:"Summary of the gameplay",id:"summary-of-the-gameplay",level:3},{value:"Suggested workflow",id:"suggested-workflow",level:2},{value:"Tasks",id:"tasks",level:2},{value:"Dictionary",id:"dictionary",level:2},{value:"Submitting",id:"submitting",level:2}],u={toc:p},m="wrapper";function c(e){let{components:t,...i}=e;return(0,r.kt)(m,(0,a.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/10.tar.gz"},"Source")),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"For this bonus you are given almost finished project - The Hangman Game. Your\ntask is to try the game, in case you find any bugs point them out and cover as\nmuch of the game as possible with tests."),(0,r.kt)("p",null,"For this bonus you can get at maximum 2 K\u20a1."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Item"),(0,r.kt)("th",{parentName:"tr",align:null},"Bonus"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Fixing bugs from failing tests"),(0,r.kt)("td",{parentName:"tr",align:null},"0.25")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"word_guessed")),(0,r.kt)("td",{parentName:"tr",align:null},"0.50")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Hidden bug"),(0,r.kt)("td",{parentName:"tr",align:null},"0.50")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Extending tests, undetectable bugs or evil bug"),(0,r.kt)("td",{parentName:"tr",align:null},"0.37")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Refactor"),(0,r.kt)("td",{parentName:"tr",align:null},"0.38")))),(0,r.kt)("h2",{id:"project"},"Project"),(0,r.kt)("p",null,"Project consists of 2 source files - ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman.c")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"main.c"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"main.c")," is quite short and concise, there is nothing for you to do."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"hangman.c")," contains implementation of the game. In case you feel lost, consult\nthe documentation in ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman.h")," that represents an interface that can be used\nfor implementing the game."),(0,r.kt)("p",null,"Apart from those sources this project is a bit more complicated. ",(0,r.kt)("em",{parentName:"p"},"Game loop")," is\nrealised via single encapsulated function that complicates the testing. Because\nof that, there are 2 kinds of tests:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"Unit tests")," - that are present in ",(0,r.kt)("inlineCode",{parentName:"p"},"test_hangman.c")," and can be run via:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ make check-unit\n")),(0,r.kt)("p",{parentName:"li"},"They cover majorly functions that can be tested easily via testing framework.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"Functional tests")," - same as in ",(0,r.kt)("inlineCode",{parentName:"p"},"seminar-08")," and are focused on testing the\nprogram as whole. Basic smoke test is already included in ",(0,r.kt)("inlineCode",{parentName:"p"},"usage")," test case."),(0,r.kt)("p",{parentName:"li"},"They can be run via:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ make check-functional\n")),(0,r.kt)("p",{parentName:"li"},"When testing ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman")," function (the game loop), it is suggested to create\nfunctional tests."),(0,r.kt)("p",{parentName:"li"},"When submitting the files for review, please leave out functional tests that\nwere given as a part of the assignment, so that it is easier to navigate, I\nwill drag the common files myself. :)"))),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"Whole test suite can be run via:"),(0,r.kt)("pre",{parentName:"blockquote"},(0,r.kt)("code",{parentName:"pre"},"$ make check\n"))),(0,r.kt)("h3",{id:"summary-of-the-gameplay"},"Summary of the gameplay"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Secret word gets chosen from the file that's path is given as an argument."),(0,r.kt)("li",{parentName:"ol"},"You get 8 guesses."),(0,r.kt)("li",{parentName:"ol"},"Invalid characters don't count."),(0,r.kt)("li",{parentName:"ol"},"Already guessed characters don't count, even if not included in the secret."),(0,r.kt)("li",{parentName:"ol"},"You can guess the whole word at once",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"If you get it right, you won, game ends."),(0,r.kt)("li",{parentName:"ul"},"If you don't get it right, you get to see the secret, game ends."))),(0,r.kt)("li",{parentName:"ol"},"In case of end of input, game finishes via force."),(0,r.kt)("li",{parentName:"ol"},"In case of invalid input, no guesses are subtracted, game carries on."),(0,r.kt)("li",{parentName:"ol"},"Letters and words are not case sensitive.")),(0,r.kt)("h2",{id:"suggested-workflow"},"Suggested workflow"),(0,r.kt)("p",null,"As we have talked about on the seminar, I suggest you to follow\n",(0,r.kt)("em",{parentName:"p"},"Test-Driven Development"),"\nin this case."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"TDD workflow",src:n(1530).Z,width:"2814",height:"1652"})),(0,r.kt)("p",null,"In our current scenario we are already in the stage of refactoring and fixing the\nbugs. Therefore try to follow this succession of steps:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Try to reproduce the bug."),(0,r.kt)("li",{parentName:"ol"},"Create a test that proves the presence of the bug."),(0,r.kt)("li",{parentName:"ol"},"Fix the bug.")),(0,r.kt)("p",null,"In case you are submitting the bonus via GitLab, it is helpful to commit tests\nbefore commiting the fixes, so that it is apparent that the bug is manifested.\nExample of ",(0,r.kt)("inlineCode",{parentName:"p"},"git log")," (notice that the first line represents latest commit):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"feat: Implement fizz_buzzer\ntest: Add tests for fizz_buzzer\nfix: Fix NULL-check in print_name\ntest: Add test for NULL in print_name\n")),(0,r.kt)("h2",{id:"tasks"},"Tasks"),(0,r.kt)("p",null,"As to your tasks, there are multiple things wrong in this project."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},'There are 2 "bugs" that cannot be detected via tests, i.e. they are not bugs\nthat affect functionality of the game.')),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"There is one evil bug in ",(0,r.kt)("inlineCode",{parentName:"p"},"get_word"),". It is not required to be fixed ;) Assign\nit the lowest priority.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"There are some tests failing. Please try to figure it out, so you have green\ntests for the rest :)")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"We have gotten a bug report for ",(0,r.kt)("inlineCode",{parentName:"p"},"word_guessed"),", all we got is"),(0,r.kt)("blockquote",{parentName:"li"},(0,r.kt)("p",{parentName:"blockquote"},"doesn't work when there are too many ",(0,r.kt)("inlineCode",{parentName:"p"},"a"),"s")),(0,r.kt)("p",{parentName:"li"},"Please try to replicate the bug and create a tests, so we don't get any\nregression later on.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"One hidden bug :) Closely non-specified, we cannot reproduce it and we were\ndrunk while playing the game, so we don't remember a thing. :/")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Try to cover as much code via the tests as possible. We are not going to look\nat the metrics, but DRY is violated a lot, so as a last task try to remove as\nmuch of the duplicit code as possible."),(0,r.kt)("p",{parentName:"li"},"Tests should help you a lot in case there are some regressions."))),(0,r.kt)("hr",null),(0,r.kt)("p",null,"In case you wonder why there are always 3 same words in the file with words, it\nis because of the ",(0,r.kt)("inlineCode",{parentName:"p"},"get_word")," bug. It is not a bug that can be easily fixed, so\nit is a not requirement at all and you can still get all points for the bonus ;)"),(0,r.kt)("h2",{id:"dictionary"},"Dictionary"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Functional_testing"},"Functional tests")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Smoke_testing_%28software%29"},"Smoke test")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"},"DRY"))),(0,r.kt)("h2",{id:"submitting"},"Submitting"),(0,r.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,r.kt)("hr",null))}c.isMDXComponent=!0},1530:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/tdd_lifecycle-327ad9ee0ed8318ed11e19a28e02b2cc.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3095],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=p(n),d=r,k=m["".concat(s,".").concat(d)]||m[d]||c[d]||i;return n?a.createElement(k,o(o({ref:t},u),{},{components:n})):a.createElement(k,o({ref:t},u))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:r,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={id:"seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n"},o=void 0,l={unversionedId:"bonuses/seminar-10",id:"bonuses/seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n",source:"@site/pb071/bonuses/10.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-10",permalink:"/pb071/bonuses/seminar-10",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/bonuses/10.md",tags:[],version:"current",lastUpdatedAt:1694111094,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n"},sidebar:"autogeneratedBar",previous:{title:"8th seminar",permalink:"/pb071/bonuses/seminar-08"},next:{title:"Practice Exams",permalink:"/pb071/category/practice-exams"}},s={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Project",id:"project",level:2},{value:"Summary of the gameplay",id:"summary-of-the-gameplay",level:3},{value:"Suggested workflow",id:"suggested-workflow",level:2},{value:"Tasks",id:"tasks",level:2},{value:"Dictionary",id:"dictionary",level:2},{value:"Submitting",id:"submitting",level:2}],u={toc:p},m="wrapper";function c(e){let{components:t,...i}=e;return(0,r.kt)(m,(0,a.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/10.tar.gz"},"Source")),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"For this bonus you are given almost finished project - The Hangman Game. Your\ntask is to try the game, in case you find any bugs point them out and cover as\nmuch of the game as possible with tests."),(0,r.kt)("p",null,"For this bonus you can get at maximum 2 K\u20a1."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Item"),(0,r.kt)("th",{parentName:"tr",align:null},"Bonus"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Fixing bugs from failing tests"),(0,r.kt)("td",{parentName:"tr",align:null},"0.25")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"word_guessed")),(0,r.kt)("td",{parentName:"tr",align:null},"0.50")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Hidden bug"),(0,r.kt)("td",{parentName:"tr",align:null},"0.50")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Extending tests, undetectable bugs or evil bug"),(0,r.kt)("td",{parentName:"tr",align:null},"0.37")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Refactor"),(0,r.kt)("td",{parentName:"tr",align:null},"0.38")))),(0,r.kt)("h2",{id:"project"},"Project"),(0,r.kt)("p",null,"Project consists of 2 source files - ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman.c")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"main.c"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"main.c")," is quite short and concise, there is nothing for you to do."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"hangman.c")," contains implementation of the game. In case you feel lost, consult\nthe documentation in ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman.h")," that represents an interface that can be used\nfor implementing the game."),(0,r.kt)("p",null,"Apart from those sources this project is a bit more complicated. ",(0,r.kt)("em",{parentName:"p"},"Game loop")," is\nrealised via single encapsulated function that complicates the testing. Because\nof that, there are 2 kinds of tests:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"Unit tests")," - that are present in ",(0,r.kt)("inlineCode",{parentName:"p"},"test_hangman.c")," and can be run via:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ make check-unit\n")),(0,r.kt)("p",{parentName:"li"},"They cover majorly functions that can be tested easily via testing framework.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"Functional tests")," - same as in ",(0,r.kt)("inlineCode",{parentName:"p"},"seminar-08")," and are focused on testing the\nprogram as whole. Basic smoke test is already included in ",(0,r.kt)("inlineCode",{parentName:"p"},"usage")," test case."),(0,r.kt)("p",{parentName:"li"},"They can be run via:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ make check-functional\n")),(0,r.kt)("p",{parentName:"li"},"When testing ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman")," function (the game loop), it is suggested to create\nfunctional tests."),(0,r.kt)("p",{parentName:"li"},"When submitting the files for review, please leave out functional tests that\nwere given as a part of the assignment, so that it is easier to navigate, I\nwill drag the common files myself. :)"))),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"Whole test suite can be run via:"),(0,r.kt)("pre",{parentName:"blockquote"},(0,r.kt)("code",{parentName:"pre"},"$ make check\n"))),(0,r.kt)("h3",{id:"summary-of-the-gameplay"},"Summary of the gameplay"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Secret word gets chosen from the file that's path is given as an argument."),(0,r.kt)("li",{parentName:"ol"},"You get 8 guesses."),(0,r.kt)("li",{parentName:"ol"},"Invalid characters don't count."),(0,r.kt)("li",{parentName:"ol"},"Already guessed characters don't count, even if not included in the secret."),(0,r.kt)("li",{parentName:"ol"},"You can guess the whole word at once",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"If you get it right, you won, game ends."),(0,r.kt)("li",{parentName:"ul"},"If you don't get it right, you get to see the secret, game ends."))),(0,r.kt)("li",{parentName:"ol"},"In case of end of input, game finishes via force."),(0,r.kt)("li",{parentName:"ol"},"In case of invalid input, no guesses are subtracted, game carries on."),(0,r.kt)("li",{parentName:"ol"},"Letters and words are not case sensitive.")),(0,r.kt)("h2",{id:"suggested-workflow"},"Suggested workflow"),(0,r.kt)("p",null,"As we have talked about on the seminar, I suggest you to follow\n",(0,r.kt)("em",{parentName:"p"},"Test-Driven Development"),"\nin this case."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"TDD workflow",src:n(1530).Z,width:"2814",height:"1652"})),(0,r.kt)("p",null,"In our current scenario we are already in the stage of refactoring and fixing the\nbugs. Therefore try to follow this succession of steps:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Try to reproduce the bug."),(0,r.kt)("li",{parentName:"ol"},"Create a test that proves the presence of the bug."),(0,r.kt)("li",{parentName:"ol"},"Fix the bug.")),(0,r.kt)("p",null,"In case you are submitting the bonus via GitLab, it is helpful to commit tests\nbefore commiting the fixes, so that it is apparent that the bug is manifested.\nExample of ",(0,r.kt)("inlineCode",{parentName:"p"},"git log")," (notice that the first line represents latest commit):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"feat: Implement fizz_buzzer\ntest: Add tests for fizz_buzzer\nfix: Fix NULL-check in print_name\ntest: Add test for NULL in print_name\n")),(0,r.kt)("h2",{id:"tasks"},"Tasks"),(0,r.kt)("p",null,"As to your tasks, there are multiple things wrong in this project."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},'There are 2 "bugs" that cannot be detected via tests, i.e. they are not bugs\nthat affect functionality of the game.')),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"There is one evil bug in ",(0,r.kt)("inlineCode",{parentName:"p"},"get_word"),". It is not required to be fixed ;) Assign\nit the lowest priority.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"There are some tests failing. Please try to figure it out, so you have green\ntests for the rest :)")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"We have gotten a bug report for ",(0,r.kt)("inlineCode",{parentName:"p"},"word_guessed"),", all we got is"),(0,r.kt)("blockquote",{parentName:"li"},(0,r.kt)("p",{parentName:"blockquote"},"doesn't work when there are too many ",(0,r.kt)("inlineCode",{parentName:"p"},"a"),"s")),(0,r.kt)("p",{parentName:"li"},"Please try to replicate the bug and create a tests, so we don't get any\nregression later on.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"One hidden bug :) Closely non-specified, we cannot reproduce it and we were\ndrunk while playing the game, so we don't remember a thing. :/")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Try to cover as much code via the tests as possible. We are not going to look\nat the metrics, but DRY is violated a lot, so as a last task try to remove as\nmuch of the duplicit code as possible."),(0,r.kt)("p",{parentName:"li"},"Tests should help you a lot in case there are some regressions."))),(0,r.kt)("hr",null),(0,r.kt)("p",null,"In case you wonder why there are always 3 same words in the file with words, it\nis because of the ",(0,r.kt)("inlineCode",{parentName:"p"},"get_word")," bug. It is not a bug that can be easily fixed, so\nit is a not requirement at all and you can still get all points for the bonus ;)"),(0,r.kt)("h2",{id:"dictionary"},"Dictionary"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Functional_testing"},"Functional tests")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Smoke_testing_%28software%29"},"Smoke test")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"},"DRY"))),(0,r.kt)("h2",{id:"submitting"},"Submitting"),(0,r.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,r.kt)("hr",null))}c.isMDXComponent=!0},1530:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/tdd_lifecycle-327ad9ee0ed8318ed11e19a28e02b2cc.png"}}]); \ No newline at end of file diff --git a/assets/js/7d580cdb.fae43e52.js b/assets/js/7d580cdb.21c0eb66.js similarity index 99% rename from assets/js/7d580cdb.fae43e52.js rename to assets/js/7d580cdb.21c0eb66.js index 7802bb6..694b629 100644 --- a/assets/js/7d580cdb.fae43e52.js +++ b/assets/js/7d580cdb.21c0eb66.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[8442],{3905:(a,e,t)=>{t.d(e,{Zo:()=>o,kt:()=>h});var n=t(7294);function s(a,e,t){return e in a?Object.defineProperty(a,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):a[e]=t,a}function m(a,e){var t=Object.keys(a);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(a);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(a,e).enumerable}))),t.push.apply(t,n)}return t}function p(a){for(var e=1;e=0||(s[t]=a[t]);return s}(a,e);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(a);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(a,t)&&(s[t]=a[t])}return s}var l=n.createContext({}),i=function(a){var e=n.useContext(l),t=e;return a&&(t="function"==typeof a?a(e):p(p({},e),a)),t},o=function(a){var e=i(a.components);return n.createElement(l.Provider,{value:e},a.children)},N="mdxType",c={inlineCode:"code",wrapper:function(a){var e=a.children;return n.createElement(n.Fragment,{},e)}},k=n.forwardRef((function(a,e){var t=a.components,s=a.mdxType,m=a.originalType,l=a.parentName,o=r(a,["components","mdxType","originalType","parentName"]),N=i(t),k=s,h=N["".concat(l,".").concat(k)]||N[k]||c[k]||m;return t?n.createElement(h,p(p({ref:e},o),{},{components:t})):n.createElement(h,p({ref:e},o))}));function h(a,e){var t=arguments,s=e&&e.mdxType;if("string"==typeof a||s){var m=t.length,p=new Array(m);p[0]=k;var r={};for(var l in e)hasOwnProperty.call(e,l)&&(r[l]=e[l]);r.originalType=a,r[N]="string"==typeof a?a:s,p[1]=r;for(var i=2;i{t.r(e),t.d(e,{assets:()=>l,contentTitle:()=>p,default:()=>c,frontMatter:()=>m,metadata:()=>r,toc:()=>i});var n=t(7462),s=(t(7294),t(3905));const m={id:"pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",tags:["java","recursion","exponential","greedy","dynamic-programming","top-down-dp","bottom-up-dp"],last_updated:{date:new Date("2023-08-17T00:00:00.000Z")}},p=void 0,r={unversionedId:"recursion/pyramid-slide-down",id:"recursion/pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",source:"@site/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",sourceDirName:"04-recursion",slug:"/recursion/pyramid-slide-down",permalink:"/ib002/recursion/pyramid-slide-down",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",tags:[{label:"java",permalink:"/ib002/tags/java"},{label:"recursion",permalink:"/ib002/tags/recursion"},{label:"exponential",permalink:"/ib002/tags/exponential"},{label:"greedy",permalink:"/ib002/tags/greedy"},{label:"dynamic-programming",permalink:"/ib002/tags/dynamic-programming"},{label:"top-down-dp",permalink:"/ib002/tags/top-down-dp"},{label:"bottom-up-dp",permalink:"/ib002/tags/bottom-up-dp"}],version:"current",lastUpdatedAt:1694110423,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",tags:["java","recursion","exponential","greedy","dynamic-programming","top-down-dp","bottom-up-dp"],last_updated:{date:"2023-08-17T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Recursion and backtracking with Robot Karel",permalink:"/ib002/recursion/karel-1"},next:{title:"Red-Black Trees",permalink:"/ib002/category/red-black-trees"}},l={},i=[{value:"Problem",id:"problem",level:2},{value:"Solving the problem",id:"solving-the-problem",level:2},{value:"Na\xefve solution",id:"na\xefve-solution",level:2},{value:"Time complexity",id:"time-complexity",level:3},{value:"Greedy solution",id:"greedy-solution",level:2},{value:"Time complexity",id:"time-complexity-1",level:3},{value:"Running the tests",id:"running-the-tests",level:3},{value:"Top-down DP",id:"top-down-dp",level:2},{value:"Time complexity",id:"time-complexity-2",level:3},{value:"Memory complexity",id:"memory-complexity",level:3},{value:"Bottom-up DP",id:"bottom-up-dp",level:2},{value:"Time complexity",id:"time-complexity-3",level:3},{value:"Memory complexity",id:"memory-complexity-1",level:3},{value:"Summary",id:"summary",level:2}],o={toc:i},N="wrapper";function c(a){let{components:e,...t}=a;return(0,s.kt)(N,(0,n.Z)({},o,t,{components:e,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"In this post we will try to solve one problem in different ways."),(0,s.kt)("h2",{id:"problem"},"Problem"),(0,s.kt)("p",null,"The problem we are going to solve is one of ",(0,s.kt)("em",{parentName:"p"},"CodeWars")," katas and is called\n",(0,s.kt)("a",{parentName:"p",href:"https://www.codewars.com/kata/551f23362ff852e2ab000037"},"Pyramid Slide Down"),"."),(0,s.kt)("p",null,"We are given a 2D array of integers and we are to find the ",(0,s.kt)("em",{parentName:"p"},"slide down"),".\n",(0,s.kt)("em",{parentName:"p"},"Slide down")," is a maximum sum of consecutive numbers from the top to the bottom."),(0,s.kt)("p",null,"Let's have a look at few examples. Consider the following pyramid:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 3\n 7 4\n 2 4 6\n8 5 9 3\n")),(0,s.kt)("p",null,"This pyramid has following slide down:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," *3\n *7 4\n 2 *4 6\n8 5 *9 3\n")),(0,s.kt)("p",null,"And its value is ",(0,s.kt)("inlineCode",{parentName:"p"},"23"),"."),(0,s.kt)("p",null,"We can also have a look at a ",(0,s.kt)("em",{parentName:"p"},"bigger")," example:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 75\n 95 64\n 17 47 82\n 18 35 87 10\n 20 4 82 47 65\n 19 1 23 3 34\n 88 2 77 73 7 63 67\n 99 65 4 28 6 16 70 92\n 41 41 26 56 83 40 80 70 33\n 41 48 72 33 47 32 37 16 94 29\n 53 71 44 65 25 43 91 52 97 51 14\n 70 11 33 28 77 73 17 78 39 68 17 57\n 91 71 52 38 17 14 91 43 58 50 27 29 48\n 63 66 4 68 89 53 67 30 73 16 69 87 40 31\n 4 62 98 27 23 9 70 98 73 93 38 53 60 4 23\n")),(0,s.kt)("p",null,"Slide down in this case is equal to ",(0,s.kt)("inlineCode",{parentName:"p"},"1074"),"."),(0,s.kt)("h2",{id:"solving-the-problem"},"Solving the problem"),(0,s.kt)("admonition",{type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"I will describe the following ways you can approach this problem and implement\nthem in ",(0,s.kt)("em",{parentName:"p"},"Java"),(0,s.kt)("sup",{parentName:"p",id:"fnref-1"},(0,s.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),".")),(0,s.kt)("p",null,"For all of the following solutions I will be using basic ",(0,s.kt)("inlineCode",{parentName:"p"},"main")," function that\nwill output ",(0,s.kt)("inlineCode",{parentName:"p"},"true"),"/",(0,s.kt)("inlineCode",{parentName:"p"},"false")," based on the expected output of our algorithm. Any\nother differences will lie only in the solutions of the problem. You can see the\n",(0,s.kt)("inlineCode",{parentName:"p"},"main")," here:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},'public static void main(String[] args) {\n System.out.print("Test #1: ");\n System.out.println(longestSlideDown(new int[][] {\n { 3 },\n { 7, 4 },\n { 2, 4, 6 },\n { 8, 5, 9, 3 }\n }) == 23 ? "passed" : "failed");\n\n System.out.print("Test #2: ");\n System.out.println(longestSlideDown(new int[][] {\n { 75 },\n { 95, 64 },\n { 17, 47, 82 },\n { 18, 35, 87, 10 },\n { 20, 4, 82, 47, 65 },\n { 19, 1, 23, 75, 3, 34 },\n { 88, 2, 77, 73, 7, 63, 67 },\n { 99, 65, 4, 28, 6, 16, 70, 92 },\n { 41, 41, 26, 56, 83, 40, 80, 70, 33 },\n { 41, 48, 72, 33, 47, 32, 37, 16, 94, 29 },\n { 53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14 },\n { 70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57 },\n { 91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48 },\n { 63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31 },\n { 4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23 },\n }) == 1074 ? "passed" : "failed");\n}\n')),(0,s.kt)("h2",{id:"na\xefve-solution"},"Na\xefve solution"),(0,s.kt)("p",null,"Our na\xefve solution consists of trying out all the possible slides and finding\nthe one with maximum sum."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: We have gotten out of bounds, there's no reasonable value to\n // return, so we just return the \u2039MIN_VALUE\u203a to ensure that it cannot\n // be maximum.\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: Bottom of the pyramid, we just return the value, there's\n // nowhere to slide anymore.\n return pyramid[row][col];\n }\n\n // Otherwise we account for the current position and return maximum of the\n // available \u201cslides\u201d.\n return pyramid[row][col] + Math.max(\n longestSlideDown(pyramid, row + 1, col),\n longestSlideDown(pyramid, row + 1, col + 1));\n}\n\npublic static int longestSlideDown(int[][] pyramid) {\n // We start the slide in the top cell of the pyramid.\n return longestSlideDown(pyramid, 0, 0);\n}\n")),(0,s.kt)("p",null,"As you can see, we have 2 overloads:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"int longestSlideDown(int[][] pyramid);\nint longestSlideDown(int[][] pyramid, int row, int col);\n")),(0,s.kt)("p",null,"First one is used as a ",(0,s.kt)("em",{parentName:"p"},"public interface")," to the solution, you just pass in the\npyramid itself. Second one is the recursive \u201calgorithm\u201d that finds the slide\ndown."),(0,s.kt)("p",null,"It is a relatively simple solution\u2026 There's nothing to do at the bottom of the\npyramid, so we just return the value in the ",(0,s.kt)("em",{parentName:"p"},"cell"),". Otherwise we add it and try\nto slide down the available cells below the current row."),(0,s.kt)("h3",{id:"time-complexity"},"Time complexity"),(0,s.kt)("p",null,"If you get the source code and run it yourself, it runs rather fine\u2026 I hope you\nare wondering about the time complexity of the proposed solution and, since it\nreally is a na\xefve solution, the time complexity is pretty bad. Let's find the\nworst case scenario."),(0,s.kt)("p",null,"Let's start with the first overload:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid) {\n return longestSlideDown(pyramid, 0, 0);\n}\n")),(0,s.kt)("p",null,"There's not much to do here, so we can safely say that the time complexity of\nthis function is bounded by ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T")))))," is our second overload. This\ndoesn't tell us anything, so let's move on to the second overload where we are\ngoing to define the ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))," function."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: We have gotten out of bounds, there's no reasonable value to\n // return, so we just return the \u2039MIN_VALUE\u203a to ensure that it cannot\n // be maximum.\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: Bottom of the pyramid, we just return the value, there's\n // nowhere to slide anymore.\n return pyramid[row][col];\n }\n\n // Otherwise we account for the current position and return maximum of the\n // available \u201cslides\u201d.\n return pyramid[row][col] + Math.max(\n longestSlideDown(pyramid, row + 1, col),\n longestSlideDown(pyramid, row + 1, col + 1));\n}\n")),(0,s.kt)("p",null,"Fun fact is that the whole \u201calgorithm\u201d consists of just 2 ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statements\nand nothing else. Let's dissect them!"),(0,s.kt)("p",null,"First ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statement is the base case, so it has a constant time complexity."),(0,s.kt)("p",null,"Second one a bit tricky. We add two numbers together, which we'll consider as\nconstant, but for the right part of the expression we take maximum from the left\nand right paths. OK\u2026 So what happens? We evaluate the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown")," while\nchoosing the under and right both. They are separate computations though, so we\nare branching from each call of ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown"),", unless it's a base case."),(0,s.kt)("p",null,"What does that mean for us then? We basically get"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"{"),(0,s.kt)("mtable",{parentName:"mrow",rowspacing:"0.36em",columnalign:"left left",columnspacing:"1em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mn",{parentName:"mstyle"},"1"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mtext",{parentName:"mrow"},",\xa0if\xa0"),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mn",{parentName:"mrow"},"1"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"1"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mtext",{parentName:"mstyle"},",\xa0otherwise"))))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(y) = \\begin{cases} 1 & \\text{, if } y = rows \\\\ 1 + 2 \\cdot T(y + 1) & \\text{, otherwise} \\end{cases}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},(0,s.kt)("span",{parentName:"span",className:"delimsizing size4"},"{")),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.69em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.69em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"1"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.25em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"1"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"1"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.19em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"arraycolsep",style:{width:"1em"}}),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.69em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.69em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord text"},(0,s.kt)("span",{parentName:"span",className:"mord"},",\xa0if\xa0")),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.25em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord text"},(0,s.kt)("span",{parentName:"span",className:"mord"},",\xa0otherwise"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.19em"}},(0,s.kt)("span",{parentName:"span"}))))))),(0,s.kt)("span",{parentName:"span",className:"mclose nulldelimiter"}))))))),(0,s.kt)("p",null,"That looks rather easy to compute, isn't it? If you sum it up, you'll get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"\u2208"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("msup",{parentName:"mrow"},(0,s.kt)("mn",{parentName:"msup"},"2"),(0,s.kt)("mrow",{parentName:"msup"},(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"))),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(rows) \\in \\mathcal{O}(2^{rows})")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"\u2208"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.7144em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"s"))))))))),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"If you wonder why, I'll try to describe it intuitively:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"In each call to ",(0,s.kt)("inlineCode",{parentName:"li"},"longestSlideDown")," we do some work in constant time,\nregardless of being in the base case. Those are the ",(0,s.kt)("inlineCode",{parentName:"li"},"1"),"s in both cases."),(0,s.kt)("li",{parentName:"ol"},"If we are not in the base case, we move one row down ",(0,s.kt)("strong",{parentName:"li"},"twice"),". That's how we\nobtained ",(0,s.kt)("inlineCode",{parentName:"li"},"2 *")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"y + 1")," in the ",(0,s.kt)("em",{parentName:"li"},"otherwise")," case."),(0,s.kt)("li",{parentName:"ol"},"We move row-by-row, so we move down ",(0,s.kt)("inlineCode",{parentName:"li"},"y"),"-times and each call splits to two\nsubtrees."),(0,s.kt)("li",{parentName:"ol"},"Overall, if we were to represent the calls as a tree, we would get a full\nbinary tree of height ",(0,s.kt)("inlineCode",{parentName:"li"},"y"),", in each node we do some work in constant time,\ntherefore we can just sum the ones.")),(0,s.kt)("admonition",{type:"warning"},(0,s.kt)("p",{parentName:"admonition"},"It would've been more complicated to get an exact result. In the equation above\nwe are assuming that the width of the pyramid is bound by the height.")),(0,s.kt)("p",null,"Hopefully we can agree that this is not the best we can do. \ud83d\ude09"),(0,s.kt)("h2",{id:"greedy-solution"},"Greedy solution"),(0,s.kt)("p",null,"We will try to optimize it a bit. Let's start with a relatively simple ",(0,s.kt)("em",{parentName:"p"},"greedy"),"\napproach."),(0,s.kt)("admonition",{title:"Greedy algorithms",type:"info"},(0,s.kt)("p",{parentName:"admonition"},(0,s.kt)("em",{parentName:"p"},"Greedy algorithms")," can be described as algorithms that decide the action on the\noptimal option at the moment.")),(0,s.kt)("p",null,"We can try to adjust the na\xefve solution. The most problematic part are the\nrecursive calls. Let's apply the greedy approach there:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row == pyramid.length - 1) {\n // BASE: We're at the bottom\n return pyramid[row][col];\n }\n\n if (col + 1 >= pyramid[row + 1].length\n || pyramid[row + 1][col] > pyramid[row + 1][col + 1]) {\n // If we cannot go right or it's not feasible, we continue to the left.\n return pyramid[row][col] + longestSlideDown(pyramid, row + 1, col);\n }\n\n // Otherwise we just move to the right.\n return pyramid[row][col] + longestSlideDown(pyramid, row + 1, col + 1);\n}\n")),(0,s.kt)("p",null,"OK, if we cannot go right ",(0,s.kt)("strong",{parentName:"p"},"or")," the right path adds smaller value to the sum,\nwe simply go left."),(0,s.kt)("h3",{id:"time-complexity-1"},"Time complexity"),(0,s.kt)("p",null,"We have switched from ",(0,s.kt)("em",{parentName:"p"},"adding the maximum")," to ",(0,s.kt)("em",{parentName:"p"},"following the \u201cbigger\u201d path"),", so\nwe improved the time complexity tremendously. We just go down the pyramid all\nthe way to the bottom. Therefore we are getting:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"We have managed to convert our exponential solution into a linear one."),(0,s.kt)("h3",{id:"running-the-tests"},"Running the tests"),(0,s.kt)("p",null,"However, if we run the tests, we notice that the second test failed:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},"Test #1: passed\nTest #2: failed\n")),(0,s.kt)("p",null,"What's going on? Well, we have improved the time complexity, but greedy\nalgorithms are not the ideal solution to ",(0,s.kt)("strong",{parentName:"p"},"all")," problems. In this case there\nmay be a solution that is bigger than the one found using the greedy algorithm."),(0,s.kt)("p",null,"Imagine the following pyramid:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 1\n 2 3\n 5 6 7\n 8 9 10 11\n99 13 14 15 16\n")),(0,s.kt)("p",null,"We start at the top:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"1"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"2")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"3"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"3")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"3"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"6")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"7"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"7")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"7"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"10")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"11"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"11")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"11"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"15")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"16"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"16")," looks better, so\nwe choose it.")),(0,s.kt)("p",null,"Our final sum is: ",(0,s.kt)("inlineCode",{parentName:"p"},"1 + 3 + 7 + 11 + 16 = 38"),", but in the bottom left cell we\nhave a ",(0,s.kt)("inlineCode",{parentName:"p"},"99")," that is bigger than our whole sum."),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"Dijkstra's algorithm is a greedy algorithm too, try to think why it is correct.")),(0,s.kt)("h2",{id:"top-down-dp"},"Top-down DP"),(0,s.kt)("p",null,(0,s.kt)("em",{parentName:"p"},"Top-down dynamic programming")," is probably the most common approach, since (at\nleast looks like) is the easiest to implement. The whole point is avoiding the\nunnecessary computations that we have already done."),(0,s.kt)("p",null,"In our case, we can use our na\xefve solution and put a ",(0,s.kt)("em",{parentName:"p"},"cache")," on top of it that\nwill make sure, we don't do unnecessary calculations."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"// This \u201cstructure\u201d is required, since I have decided to use \u2039TreeMap\u203a which\n// requires the ordering on the keys. It represents one position in the pyramid.\nrecord Position(int row, int col) implements Comparable {\n public int compareTo(Position r) {\n if (row != r.row) {\n return Integer.valueOf(row).compareTo(r.row);\n }\n\n if (col != r.col) {\n return Integer.valueOf(col).compareTo(r.col);\n }\n\n return 0;\n }\n}\n\npublic static int longestSlideDown(\n int[][] pyramid,\n TreeMap cache,\n Position position) {\n int row = position.row;\n int col = position.col;\n\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: out of bounds\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: bottom of the pyramid\n return pyramid[position.row][position.col];\n }\n\n if (!cache.containsKey(position)) {\n // We haven't computed the position yet, so we run the same \u201cformula\u201d as\n // in the na\xefve version \xbband\xab we put calculated slide into the cache.\n // Next time we want the slide down from given position, it will be just\n // retrieved from the cache.\n int slideDown = Math.max(\n longestSlideDown(pyramid, cache, new Position(row + 1, col)),\n longestSlideDown(pyramid, cache, new Position(row + 1, col + 1)));\n cache.put(position, pyramid[row][col] + slideDown);\n }\n\n return cache.get(position);\n}\n\npublic static int longestSlideDown(int[][] pyramid) {\n // At the beginning we need to create a cache and share it across the calls.\n TreeMap cache = new TreeMap<>();\n return longestSlideDown(pyramid, cache, new Position(0, 0));\n}\n")),(0,s.kt)("p",null,"You have probably noticed that ",(0,s.kt)("inlineCode",{parentName:"p"},"record Position")," have appeared. Since we are\ncaching the already computed values, we need a \u201creasonable\u201d key. In this case we\nshare the cache only for one ",(0,s.kt)("em",{parentName:"p"},"run")," (i.e. pyramid) of the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown"),", so\nwe can cache just with the indices within the pyramid, i.e. the ",(0,s.kt)("inlineCode",{parentName:"p"},"Position"),"."),(0,s.kt)("admonition",{title:"Record",type:"tip"},(0,s.kt)("p",{parentName:"admonition"},(0,s.kt)("em",{parentName:"p"},"Record")," is relatively new addition to the Java language. It is basically an\nimmutable structure with implicitly defined ",(0,s.kt)("inlineCode",{parentName:"p"},".equals()"),", ",(0,s.kt)("inlineCode",{parentName:"p"},".hashCode()"),",\n",(0,s.kt)("inlineCode",{parentName:"p"},".toString()")," and getters for the attributes.")),(0,s.kt)("p",null,"Because of the choice of ",(0,s.kt)("inlineCode",{parentName:"p"},"TreeMap"),", we had to additionally define the ordering\non it."),(0,s.kt)("p",null,"In the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown")," you can notice that the computation which used to be\nat the end of the na\xefve version above, is now wrapped in an ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," statement that\nchecks for the presence of the position in the cache and computes the slide down\njust when it's needed."),(0,s.kt)("h3",{id:"time-complexity-2"},"Time complexity"),(0,s.kt)("p",null,"If you think that evaluating time complexity for this approach is a bit more\ntricky, you are right. Keeping the cache in mind, it is not the easiest thing\nto do. However there are some observations that might help us figure this out:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"Slide down from each position is calculated only once."),(0,s.kt)("li",{parentName:"ol"},"Once calculated, we use the result from the cache.")),(0,s.kt)("p",null,"Knowing this, we still cannot, at least easily, describe the time complexity of\nfinding the best slide down from a specific position, ",(0,s.kt)("strong",{parentName:"p"},"but")," we can bound it\nfrom above for the ",(0,s.kt)("strong",{parentName:"p"},"whole")," run from the top. Now the question is how we can do\nthat!"),(0,s.kt)("p",null,"Overall we are doing the same things for almost",(0,s.kt)("sup",{parentName:"p",id:"fnref-2"},(0,s.kt)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2"))," all of the positions within\nthe pyramid:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},"We calculate and store it (using the partial results stored in cache). This\nis done only once."),(0,s.kt)("p",{parentName:"li"},"For each calculation we take 2 values from the cache and insert one value.\nBecause we have chosen ",(0,s.kt)("inlineCode",{parentName:"p"},"TreeMap"),", these 3 operations have logarithmic time\ncomplexity and therefore this step is equivalent to ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mn",{parentName:"mrow"},"3"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"3 \\cdot \\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"3"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),"."),(0,s.kt)("p",{parentName:"li"},"However for the sake of simplicity, we are going to account only for the\ninsertion, the reason is rather simple, if we include the 2 retrievals here,\nit will be interleaved with the next step, therefore it is easier to keep the\nretrievals in the following point."),(0,s.kt)("admonition",{parentName:"li",type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"You might have noticed it's still not that easy, cause we're not having full\ncache right from the beginning, but the sum of those logarithms cannot be\nexpressed in a nice way, so taking the upper bound, i.e. expecting the cache\nto be full at all times, is the best option for nice and readable complexity\nof the whole approach.")),(0,s.kt)("p",{parentName:"li"},"Our final upper bound of this work is therefore ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),".")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},"We retrieve it from the cache. Same as in first point, but only twice, so we\nget ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2 \\cdot \\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),". "),(0,s.kt)("admonition",{parentName:"li",type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"It's done twice because of the ",(0,s.kt)("inlineCode",{parentName:"p"},".containsKey()")," in the ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," condition.")))),(0,s.kt)("p",null,"Okay, we have evaluated work done for each of the cells in the pyramid and now\nwe need to put it together."),(0,s.kt)("p",null,"Let's split the time complexity of our solution into two operands:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(r + s)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"r")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"r")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))))," will represent the ",(0,s.kt)("em",{parentName:"p"},"actual")," calculation of the cells and ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"s")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"s")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))))," will represent\nthe additional retrievals on top of the calculation."),(0,s.kt)("p",null,"We calculate the values only ",(0,s.kt)("strong",{parentName:"p"},"once"),", therefore we can safely agree on:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"r"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} r &= n \\cdot \\log{n} \\\\ \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1.5em",verticalAlign:"-0.5em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.16em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.5em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.16em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.5em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("p",null,"What about the ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"s")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"s")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))))," though? Key observation here is the fact that we have 2\nlookups on the tree in each of them ",(0,s.kt)("strong",{parentName:"p"},"and")," we do it twice, cause each cell has\nat most 2 parents:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"("),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",fence:"true"},")")))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"4"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} s &= n \\cdot 2 \\cdot \\left( 2 \\cdot \\log{n} \\right) \\\\ s &= 4 \\cdot n \\cdot \\log{n} \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose delimcenter",style:{top:"0em"}},")")))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"4"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"You might've noticed that lookups actually take more time than the construction\nof the results. This is not entirely true, since we have included the\n",(0,s.kt)("inlineCode",{parentName:"p"},".containsKey()")," and ",(0,s.kt)("inlineCode",{parentName:"p"},".get()")," from the ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statement in the second part."),(0,s.kt)("p",{parentName:"admonition"},"If we were to represent this more precisely, we could've gone with:"),(0,s.kt)("div",{parentName:"admonition",className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"r"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"3"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} r &= 3 \\cdot n \\cdot \\log{n} \\\\ s &= 2 \\cdot n \\cdot \\log{n} \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"3"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("p",{parentName:"admonition"},"On the other hand we are summing both numbers together, therefore in the end it\ndoesn't really matter."),(0,s.kt)("p",{parentName:"admonition"},"(",(0,s.kt)("em",{parentName:"p"},"Feel free to compare the sums of both \u201csplits\u201d."),")")),(0,s.kt)("p",null,"And so our final time complexity for the whole ",(0,s.kt)("em",{parentName:"p"},"top-down dynamic programming"),"\napproach is:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"4"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mn",{parentName:"mrow"},"5"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(r + s) \\\\ \\mathcal{O}(n \\cdot \\log{n} + 4 \\cdot n \\cdot \\log{n}) \\\\ \\mathcal{O}(5 \\cdot n \\cdot \\log{n}) \\\\ \\mathcal{O}(n \\cdot \\log{n})")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"4"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4445em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},"5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4445em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"As you can see, this is worse than our ",(0,s.kt)("em",{parentName:"p"},"greedy")," solution that was incorrect, but\nit's better than the ",(0,s.kt)("em",{parentName:"p"},"na\xefve")," one."),(0,s.kt)("h3",{id:"memory-complexity"},"Memory complexity"),(0,s.kt)("p",null,"With this approach we need to talk about the memory complexity too, because we\nhave introduced cache. If you think that the memory complexity is linear to the\ninput, you are right. We start at the top and try to find each and every slide\ndown. At the end we get the final result for ",(0,s.kt)("inlineCode",{parentName:"p"},"new Position(0, 0)"),", so we need to\ncompute everything below."),(0,s.kt)("p",null,"That's how we obtain:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," represents the total amount of cells in the pyramid, i.e."),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("munderover",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"munderover"},"\u2211"),(0,s.kt)("mrow",{parentName:"munderover"},(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"0")),(0,s.kt)("mrow",{parentName:"munderover"},(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"p"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"y"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"r"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"."),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"g"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"h")),(0,s.kt)("mo",{parentName:"mrow"},"\u2212"),(0,s.kt)("mn",{parentName:"mrow"},"1"))),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"p"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"y"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"r"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d")),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"["),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"]")),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"."),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"g"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"h"))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\sum_{y=0}^{\\mathtt{pyramid.length} - 1} \\mathtt{pyramid}\\left[y\\right]\\mathtt{.length}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3.2709em",verticalAlign:"-1.4032em"}}),(0,s.kt)("span",{parentName:"span",className:"mop op-limits"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.8677em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-1.8829em",marginLeft:"0em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mrel mtight"},"="),(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,s.kt)("span",{parentName:"span",style:{top:"-3.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span"},(0,s.kt)("span",{parentName:"span",className:"mop op-symbol large-op"},"\u2211"))),(0,s.kt)("span",{parentName:"span",style:{top:"-4.3666em",marginLeft:"0em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt mtight"},"pyramid.length")),(0,s.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.4032em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt"},"pyramid")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},"["),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mclose delimcenter",style:{top:"0em"}},"]")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt"},".length"))))))),(0,s.kt)("admonition",{type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"If you're wondering whether it's correct because of the second ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," in our\nfunction, your guess is right. However we are expressing the complexity in the\nBachmann-Landau notation, so we care about the ",(0,s.kt)("strong",{parentName:"p"},"upper bound"),", not the exact\nnumber.")),(0,s.kt)("admonition",{title:"Can this be optimized?",type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"Yes, it can! Try to think about a way, how can you minimize the memory\ncomplexity of this approach. I'll give you a hint:"),(0,s.kt)("div",{parentName:"admonition",className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"))))))),(0,s.kt)("h2",{id:"bottom-up-dp"},"Bottom-up DP"),(0,s.kt)("p",null,"If you try to think in depth about the top-down DP solution, you might notice\nthat the ",(0,s.kt)("em",{parentName:"p"},"core")," of it stands on caching the calculations that have been already\ndone on the lower \u201clevels\u201d of the pyramid. Our bottom-up implementation will be\nusing this fact!"),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"As I have said in the ",(0,s.kt)("em",{parentName:"p"},"top-down DP")," section, it is the easiest way to implement\nDP (unless the cached function has complicated parameters, in that case it might\nget messy)."),(0,s.kt)("p",{parentName:"admonition"},"Bottom-up dynamic programming can be more effective, but may be more complicated\nto implement right from the beginning.")),(0,s.kt)("p",null,"Let's see how we can implement it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid) {\n // In the beginning we declare new array. At this point it is easier to just\n // work with the one dimension, i.e. just allocating the space for the rows.\n int[][] slideDowns = new int[pyramid.length][];\n\n // Bottom row gets just copied, there's nothing else to do\u2026 It's the base\n // case.\n slideDowns[pyramid.length - 1] = Arrays.copyOf(pyramid[pyramid.length - 1],\n pyramid[pyramid.length - 1].length);\n\n // Then we need to propagate the found slide downs for each of the levels\n // above.\n for (int y = pyramid.length - 2; y >= 0; --y) {\n // We start by copying the values lying in the row we're processing.\n // They get included in the final sum and we need to allocate the space\n // for the precalculated slide downs anyways.\n int[] row = Arrays.copyOf(pyramid[y], pyramid[y].length);\n\n // At this we just need to \u201cfetch\u201d the partial results from \u201cneighbours\u201d\n for (int x = 0; x < row.length; ++x) {\n // We look under our position, since we expect the rows to get\n // shorter, we can safely assume such position exists.\n int under = slideDowns[y + 1][x];\n\n // Then we have a look to the right, such position doesn't have to\n // exist, e.g. on the right edge, so we validate the index, and if\n // it doesn't exist, we just assign minimum of the \u2039int\u203a which makes\n // sure that it doesn't get picked in the \u2039Math.max()\u203a call.\n int toRight = x + 1 < slideDowns[y + 1].length\n ? slideDowns[y + 1][x + 1]\n : Integer.MIN_VALUE;\n\n // Finally we add the best choice at this point.\n row[x] += Math.max(under, toRight);\n }\n\n // And save the row we've just calculated partial results for to the\n // \u201ctable\u201d.\n slideDowns[y] = row;\n }\n\n // At the end we can find our seeked slide down at the top cell.\n return slideDowns[0][0];\n}\n")),(0,s.kt)("p",null,"I've tried to explain the code as much as possible within the comments, since it\nmight be more beneficial to see right next to the \u201coffending\u201d lines."),(0,s.kt)("p",null,"As you can see, in this approach we go from the other side",(0,s.kt)("sup",{parentName:"p",id:"fnref-3"},(0,s.kt)("a",{parentName:"sup",href:"#fn-3",className:"footnote-ref"},"3")),", the bottom of\nthe pyramid and propagate the partial results up."),(0,s.kt)("admonition",{type:"info"},(0,s.kt)("mdxAdmonitionTitle",{parentName:"admonition"},"How is this different from the ",(0,s.kt)("em",{parentName:"mdxAdmonitionTitle"},"greedy")," solution???"),(0,s.kt)("p",{parentName:"admonition"},"If you try to compare them, you might find a very noticable difference. The\ngreedy approach is going from the top to the bottom without ",(0,s.kt)("strong",{parentName:"p"},"any")," knowledge of\nwhat's going on below. On the other hand, bottom-up DP is going from the bottom\n(",(0,s.kt)("em",{parentName:"p"},"DUH\u2026"),") and ",(0,s.kt)("strong",{parentName:"p"},"propagates")," the partial results to the top. The propagation is\nwhat makes sure that at the top I don't choose the best ",(0,s.kt)("strong",{parentName:"p"},"local")," choice, but\nthe best ",(0,s.kt)("strong",{parentName:"p"},"overall")," result I can achieve.")),(0,s.kt)("h3",{id:"time-complexity-3"},"Time complexity"),(0,s.kt)("p",null,"Time complexity of this solution is rather simple. We allocate an array for the\nrows and then for each row, we copy it and adjust the partial results. Doing\nthis we get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows + 2n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"Of course, this is an upper bound, since we iterate through the bottom row only\nonce."),(0,s.kt)("h3",{id:"memory-complexity-1"},"Memory complexity"),(0,s.kt)("p",null,"We're allocating an array for the pyramid ",(0,s.kt)("strong",{parentName:"p"},"again")," for our partial results, so\nwe get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"If we were writing this in C++ or Rust, we could've avoided that, but not\nreally."),(0,s.kt)("p",{parentName:"admonition"},"C++ would allow us to ",(0,s.kt)("strong",{parentName:"p"},"copy")," the pyramid rightaway into the parameter, so we\nwould be able to directly change it. However it's still a copy, even though we\ndon't need to allocate anything ourselves. It's just implicitly done for us."),(0,s.kt)("p",{parentName:"admonition"},"Rust is more funny in this case. If the pyramids weren't used after the call of\n",(0,s.kt)("inlineCode",{parentName:"p"},"longest_slide_down"),", it would simply ",(0,s.kt)("strong",{parentName:"p"},"move")," them into the functions. If they\nwere used afterwards, the compiler would force you to either borrow it, or\n",(0,s.kt)("em",{parentName:"p"},"clone-and-move")," for the function."),(0,s.kt)("hr",{parentName:"admonition"}),(0,s.kt)("p",{parentName:"admonition"},"Since we're doing it in Java, we get a reference to the ",(0,s.kt)("em",{parentName:"p"},"original")," array and we\ncan't do whatever we want with it.")),(0,s.kt)("h2",{id:"summary"},"Summary"),(0,s.kt)("p",null,"And we've finally reached the end. We have seen 4 different \u201csolutions\u201d",(0,s.kt)("sup",{parentName:"p",id:"fnref-4"},(0,s.kt)("a",{parentName:"sup",href:"#fn-4",className:"footnote-ref"},"4"))," of\nthe same problem using different approaches. Different approaches follow the\norder in which you might come up with them, each approach influences its\nsuccessor and represents the way we can enhance the existing implementation."),(0,s.kt)("hr",null),(0,s.kt)("admonition",{title:"source",type:"info"},(0,s.kt)("p",{parentName:"admonition"},"You can find source code referenced in the text\n",(0,s.kt)("a",{parentName:"p",href:"pathname:///files/ib002/recursion/pyramid-slide-down.tar.gz"},"here"),".")),(0,s.kt)("div",{className:"footnotes"},(0,s.kt)("hr",{parentName:"div"}),(0,s.kt)("ol",{parentName:"div"},(0,s.kt)("li",{parentName:"ol",id:"fn-1"},"cause why not, right!?",(0,s.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-2"},"except the bottom row",(0,s.kt)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-3"},"definitely not an RHCP reference \ud83d\ude09",(0,s.kt)("a",{parentName:"li",href:"#fnref-3",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-4"},"one was not correct, thus the quotes",(0,s.kt)("a",{parentName:"li",href:"#fnref-4",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[8442],{3905:(a,e,t)=>{t.d(e,{Zo:()=>o,kt:()=>h});var n=t(7294);function s(a,e,t){return e in a?Object.defineProperty(a,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):a[e]=t,a}function m(a,e){var t=Object.keys(a);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(a);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(a,e).enumerable}))),t.push.apply(t,n)}return t}function p(a){for(var e=1;e=0||(s[t]=a[t]);return s}(a,e);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(a);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(a,t)&&(s[t]=a[t])}return s}var i=n.createContext({}),l=function(a){var e=n.useContext(i),t=e;return a&&(t="function"==typeof a?a(e):p(p({},e),a)),t},o=function(a){var e=l(a.components);return n.createElement(i.Provider,{value:e},a.children)},N="mdxType",c={inlineCode:"code",wrapper:function(a){var e=a.children;return n.createElement(n.Fragment,{},e)}},k=n.forwardRef((function(a,e){var t=a.components,s=a.mdxType,m=a.originalType,i=a.parentName,o=r(a,["components","mdxType","originalType","parentName"]),N=l(t),k=s,h=N["".concat(i,".").concat(k)]||N[k]||c[k]||m;return t?n.createElement(h,p(p({ref:e},o),{},{components:t})):n.createElement(h,p({ref:e},o))}));function h(a,e){var t=arguments,s=e&&e.mdxType;if("string"==typeof a||s){var m=t.length,p=new Array(m);p[0]=k;var r={};for(var i in e)hasOwnProperty.call(e,i)&&(r[i]=e[i]);r.originalType=a,r[N]="string"==typeof a?a:s,p[1]=r;for(var l=2;l{t.r(e),t.d(e,{assets:()=>i,contentTitle:()=>p,default:()=>c,frontMatter:()=>m,metadata:()=>r,toc:()=>l});var n=t(7462),s=(t(7294),t(3905));const m={id:"pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",tags:["java","recursion","exponential","greedy","dynamic-programming","top-down-dp","bottom-up-dp"],last_updated:{date:new Date("2023-08-17T00:00:00.000Z")}},p=void 0,r={unversionedId:"recursion/pyramid-slide-down",id:"recursion/pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",source:"@site/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",sourceDirName:"04-recursion",slug:"/recursion/pyramid-slide-down",permalink:"/ib002/recursion/pyramid-slide-down",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",tags:[{label:"java",permalink:"/ib002/tags/java"},{label:"recursion",permalink:"/ib002/tags/recursion"},{label:"exponential",permalink:"/ib002/tags/exponential"},{label:"greedy",permalink:"/ib002/tags/greedy"},{label:"dynamic-programming",permalink:"/ib002/tags/dynamic-programming"},{label:"top-down-dp",permalink:"/ib002/tags/top-down-dp"},{label:"bottom-up-dp",permalink:"/ib002/tags/bottom-up-dp"}],version:"current",lastUpdatedAt:1694111094,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",tags:["java","recursion","exponential","greedy","dynamic-programming","top-down-dp","bottom-up-dp"],last_updated:{date:"2023-08-17T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Recursion and backtracking with Robot Karel",permalink:"/ib002/recursion/karel-1"},next:{title:"Red-Black Trees",permalink:"/ib002/category/red-black-trees"}},i={},l=[{value:"Problem",id:"problem",level:2},{value:"Solving the problem",id:"solving-the-problem",level:2},{value:"Na\xefve solution",id:"na\xefve-solution",level:2},{value:"Time complexity",id:"time-complexity",level:3},{value:"Greedy solution",id:"greedy-solution",level:2},{value:"Time complexity",id:"time-complexity-1",level:3},{value:"Running the tests",id:"running-the-tests",level:3},{value:"Top-down DP",id:"top-down-dp",level:2},{value:"Time complexity",id:"time-complexity-2",level:3},{value:"Memory complexity",id:"memory-complexity",level:3},{value:"Bottom-up DP",id:"bottom-up-dp",level:2},{value:"Time complexity",id:"time-complexity-3",level:3},{value:"Memory complexity",id:"memory-complexity-1",level:3},{value:"Summary",id:"summary",level:2}],o={toc:l},N="wrapper";function c(a){let{components:e,...t}=a;return(0,s.kt)(N,(0,n.Z)({},o,t,{components:e,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"In this post we will try to solve one problem in different ways."),(0,s.kt)("h2",{id:"problem"},"Problem"),(0,s.kt)("p",null,"The problem we are going to solve is one of ",(0,s.kt)("em",{parentName:"p"},"CodeWars")," katas and is called\n",(0,s.kt)("a",{parentName:"p",href:"https://www.codewars.com/kata/551f23362ff852e2ab000037"},"Pyramid Slide Down"),"."),(0,s.kt)("p",null,"We are given a 2D array of integers and we are to find the ",(0,s.kt)("em",{parentName:"p"},"slide down"),".\n",(0,s.kt)("em",{parentName:"p"},"Slide down")," is a maximum sum of consecutive numbers from the top to the bottom."),(0,s.kt)("p",null,"Let's have a look at few examples. Consider the following pyramid:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 3\n 7 4\n 2 4 6\n8 5 9 3\n")),(0,s.kt)("p",null,"This pyramid has following slide down:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," *3\n *7 4\n 2 *4 6\n8 5 *9 3\n")),(0,s.kt)("p",null,"And its value is ",(0,s.kt)("inlineCode",{parentName:"p"},"23"),"."),(0,s.kt)("p",null,"We can also have a look at a ",(0,s.kt)("em",{parentName:"p"},"bigger")," example:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 75\n 95 64\n 17 47 82\n 18 35 87 10\n 20 4 82 47 65\n 19 1 23 3 34\n 88 2 77 73 7 63 67\n 99 65 4 28 6 16 70 92\n 41 41 26 56 83 40 80 70 33\n 41 48 72 33 47 32 37 16 94 29\n 53 71 44 65 25 43 91 52 97 51 14\n 70 11 33 28 77 73 17 78 39 68 17 57\n 91 71 52 38 17 14 91 43 58 50 27 29 48\n 63 66 4 68 89 53 67 30 73 16 69 87 40 31\n 4 62 98 27 23 9 70 98 73 93 38 53 60 4 23\n")),(0,s.kt)("p",null,"Slide down in this case is equal to ",(0,s.kt)("inlineCode",{parentName:"p"},"1074"),"."),(0,s.kt)("h2",{id:"solving-the-problem"},"Solving the problem"),(0,s.kt)("admonition",{type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"I will describe the following ways you can approach this problem and implement\nthem in ",(0,s.kt)("em",{parentName:"p"},"Java"),(0,s.kt)("sup",{parentName:"p",id:"fnref-1"},(0,s.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),".")),(0,s.kt)("p",null,"For all of the following solutions I will be using basic ",(0,s.kt)("inlineCode",{parentName:"p"},"main")," function that\nwill output ",(0,s.kt)("inlineCode",{parentName:"p"},"true"),"/",(0,s.kt)("inlineCode",{parentName:"p"},"false")," based on the expected output of our algorithm. Any\nother differences will lie only in the solutions of the problem. You can see the\n",(0,s.kt)("inlineCode",{parentName:"p"},"main")," here:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},'public static void main(String[] args) {\n System.out.print("Test #1: ");\n System.out.println(longestSlideDown(new int[][] {\n { 3 },\n { 7, 4 },\n { 2, 4, 6 },\n { 8, 5, 9, 3 }\n }) == 23 ? "passed" : "failed");\n\n System.out.print("Test #2: ");\n System.out.println(longestSlideDown(new int[][] {\n { 75 },\n { 95, 64 },\n { 17, 47, 82 },\n { 18, 35, 87, 10 },\n { 20, 4, 82, 47, 65 },\n { 19, 1, 23, 75, 3, 34 },\n { 88, 2, 77, 73, 7, 63, 67 },\n { 99, 65, 4, 28, 6, 16, 70, 92 },\n { 41, 41, 26, 56, 83, 40, 80, 70, 33 },\n { 41, 48, 72, 33, 47, 32, 37, 16, 94, 29 },\n { 53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14 },\n { 70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57 },\n { 91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48 },\n { 63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31 },\n { 4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23 },\n }) == 1074 ? "passed" : "failed");\n}\n')),(0,s.kt)("h2",{id:"na\xefve-solution"},"Na\xefve solution"),(0,s.kt)("p",null,"Our na\xefve solution consists of trying out all the possible slides and finding\nthe one with maximum sum."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: We have gotten out of bounds, there's no reasonable value to\n // return, so we just return the \u2039MIN_VALUE\u203a to ensure that it cannot\n // be maximum.\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: Bottom of the pyramid, we just return the value, there's\n // nowhere to slide anymore.\n return pyramid[row][col];\n }\n\n // Otherwise we account for the current position and return maximum of the\n // available \u201cslides\u201d.\n return pyramid[row][col] + Math.max(\n longestSlideDown(pyramid, row + 1, col),\n longestSlideDown(pyramid, row + 1, col + 1));\n}\n\npublic static int longestSlideDown(int[][] pyramid) {\n // We start the slide in the top cell of the pyramid.\n return longestSlideDown(pyramid, 0, 0);\n}\n")),(0,s.kt)("p",null,"As you can see, we have 2 overloads:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"int longestSlideDown(int[][] pyramid);\nint longestSlideDown(int[][] pyramid, int row, int col);\n")),(0,s.kt)("p",null,"First one is used as a ",(0,s.kt)("em",{parentName:"p"},"public interface")," to the solution, you just pass in the\npyramid itself. Second one is the recursive \u201calgorithm\u201d that finds the slide\ndown."),(0,s.kt)("p",null,"It is a relatively simple solution\u2026 There's nothing to do at the bottom of the\npyramid, so we just return the value in the ",(0,s.kt)("em",{parentName:"p"},"cell"),". Otherwise we add it and try\nto slide down the available cells below the current row."),(0,s.kt)("h3",{id:"time-complexity"},"Time complexity"),(0,s.kt)("p",null,"If you get the source code and run it yourself, it runs rather fine\u2026 I hope you\nare wondering about the time complexity of the proposed solution and, since it\nreally is a na\xefve solution, the time complexity is pretty bad. Let's find the\nworst case scenario."),(0,s.kt)("p",null,"Let's start with the first overload:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid) {\n return longestSlideDown(pyramid, 0, 0);\n}\n")),(0,s.kt)("p",null,"There's not much to do here, so we can safely say that the time complexity of\nthis function is bounded by ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T")))))," is our second overload. This\ndoesn't tell us anything, so let's move on to the second overload where we are\ngoing to define the ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))," function."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: We have gotten out of bounds, there's no reasonable value to\n // return, so we just return the \u2039MIN_VALUE\u203a to ensure that it cannot\n // be maximum.\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: Bottom of the pyramid, we just return the value, there's\n // nowhere to slide anymore.\n return pyramid[row][col];\n }\n\n // Otherwise we account for the current position and return maximum of the\n // available \u201cslides\u201d.\n return pyramid[row][col] + Math.max(\n longestSlideDown(pyramid, row + 1, col),\n longestSlideDown(pyramid, row + 1, col + 1));\n}\n")),(0,s.kt)("p",null,"Fun fact is that the whole \u201calgorithm\u201d consists of just 2 ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statements\nand nothing else. Let's dissect them!"),(0,s.kt)("p",null,"First ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statement is the base case, so it has a constant time complexity."),(0,s.kt)("p",null,"Second one a bit tricky. We add two numbers together, which we'll consider as\nconstant, but for the right part of the expression we take maximum from the left\nand right paths. OK\u2026 So what happens? We evaluate the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown")," while\nchoosing the under and right both. They are separate computations though, so we\nare branching from each call of ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown"),", unless it's a base case."),(0,s.kt)("p",null,"What does that mean for us then? We basically get"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"{"),(0,s.kt)("mtable",{parentName:"mrow",rowspacing:"0.36em",columnalign:"left left",columnspacing:"1em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mn",{parentName:"mstyle"},"1"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mtext",{parentName:"mrow"},",\xa0if\xa0"),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mn",{parentName:"mrow"},"1"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"1"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mtext",{parentName:"mstyle"},",\xa0otherwise"))))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(y) = \\begin{cases} 1 & \\text{, if } y = rows \\\\ 1 + 2 \\cdot T(y + 1) & \\text{, otherwise} \\end{cases}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},(0,s.kt)("span",{parentName:"span",className:"delimsizing size4"},"{")),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.69em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.69em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"1"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.25em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"1"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"1"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.19em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"arraycolsep",style:{width:"1em"}}),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.69em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.69em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord text"},(0,s.kt)("span",{parentName:"span",className:"mord"},",\xa0if\xa0")),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.25em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord text"},(0,s.kt)("span",{parentName:"span",className:"mord"},",\xa0otherwise"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.19em"}},(0,s.kt)("span",{parentName:"span"}))))))),(0,s.kt)("span",{parentName:"span",className:"mclose nulldelimiter"}))))))),(0,s.kt)("p",null,"That looks rather easy to compute, isn't it? If you sum it up, you'll get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"\u2208"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("msup",{parentName:"mrow"},(0,s.kt)("mn",{parentName:"msup"},"2"),(0,s.kt)("mrow",{parentName:"msup"},(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"))),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(rows) \\in \\mathcal{O}(2^{rows})")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"\u2208"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.7144em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"s"))))))))),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"If you wonder why, I'll try to describe it intuitively:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"In each call to ",(0,s.kt)("inlineCode",{parentName:"li"},"longestSlideDown")," we do some work in constant time,\nregardless of being in the base case. Those are the ",(0,s.kt)("inlineCode",{parentName:"li"},"1"),"s in both cases."),(0,s.kt)("li",{parentName:"ol"},"If we are not in the base case, we move one row down ",(0,s.kt)("strong",{parentName:"li"},"twice"),". That's how we\nobtained ",(0,s.kt)("inlineCode",{parentName:"li"},"2 *")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"y + 1")," in the ",(0,s.kt)("em",{parentName:"li"},"otherwise")," case."),(0,s.kt)("li",{parentName:"ol"},"We move row-by-row, so we move down ",(0,s.kt)("inlineCode",{parentName:"li"},"y"),"-times and each call splits to two\nsubtrees."),(0,s.kt)("li",{parentName:"ol"},"Overall, if we were to represent the calls as a tree, we would get a full\nbinary tree of height ",(0,s.kt)("inlineCode",{parentName:"li"},"y"),", in each node we do some work in constant time,\ntherefore we can just sum the ones.")),(0,s.kt)("admonition",{type:"warning"},(0,s.kt)("p",{parentName:"admonition"},"It would've been more complicated to get an exact result. In the equation above\nwe are assuming that the width of the pyramid is bound by the height.")),(0,s.kt)("p",null,"Hopefully we can agree that this is not the best we can do. \ud83d\ude09"),(0,s.kt)("h2",{id:"greedy-solution"},"Greedy solution"),(0,s.kt)("p",null,"We will try to optimize it a bit. Let's start with a relatively simple ",(0,s.kt)("em",{parentName:"p"},"greedy"),"\napproach."),(0,s.kt)("admonition",{title:"Greedy algorithms",type:"info"},(0,s.kt)("p",{parentName:"admonition"},(0,s.kt)("em",{parentName:"p"},"Greedy algorithms")," can be described as algorithms that decide the action on the\noptimal option at the moment.")),(0,s.kt)("p",null,"We can try to adjust the na\xefve solution. The most problematic part are the\nrecursive calls. Let's apply the greedy approach there:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row == pyramid.length - 1) {\n // BASE: We're at the bottom\n return pyramid[row][col];\n }\n\n if (col + 1 >= pyramid[row + 1].length\n || pyramid[row + 1][col] > pyramid[row + 1][col + 1]) {\n // If we cannot go right or it's not feasible, we continue to the left.\n return pyramid[row][col] + longestSlideDown(pyramid, row + 1, col);\n }\n\n // Otherwise we just move to the right.\n return pyramid[row][col] + longestSlideDown(pyramid, row + 1, col + 1);\n}\n")),(0,s.kt)("p",null,"OK, if we cannot go right ",(0,s.kt)("strong",{parentName:"p"},"or")," the right path adds smaller value to the sum,\nwe simply go left."),(0,s.kt)("h3",{id:"time-complexity-1"},"Time complexity"),(0,s.kt)("p",null,"We have switched from ",(0,s.kt)("em",{parentName:"p"},"adding the maximum")," to ",(0,s.kt)("em",{parentName:"p"},"following the \u201cbigger\u201d path"),", so\nwe improved the time complexity tremendously. We just go down the pyramid all\nthe way to the bottom. Therefore we are getting:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"We have managed to convert our exponential solution into a linear one."),(0,s.kt)("h3",{id:"running-the-tests"},"Running the tests"),(0,s.kt)("p",null,"However, if we run the tests, we notice that the second test failed:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},"Test #1: passed\nTest #2: failed\n")),(0,s.kt)("p",null,"What's going on? Well, we have improved the time complexity, but greedy\nalgorithms are not the ideal solution to ",(0,s.kt)("strong",{parentName:"p"},"all")," problems. In this case there\nmay be a solution that is bigger than the one found using the greedy algorithm."),(0,s.kt)("p",null,"Imagine the following pyramid:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 1\n 2 3\n 5 6 7\n 8 9 10 11\n99 13 14 15 16\n")),(0,s.kt)("p",null,"We start at the top:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"1"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"2")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"3"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"3")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"3"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"6")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"7"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"7")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"7"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"10")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"11"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"11")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"11"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"15")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"16"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"16")," looks better, so\nwe choose it.")),(0,s.kt)("p",null,"Our final sum is: ",(0,s.kt)("inlineCode",{parentName:"p"},"1 + 3 + 7 + 11 + 16 = 38"),", but in the bottom left cell we\nhave a ",(0,s.kt)("inlineCode",{parentName:"p"},"99")," that is bigger than our whole sum."),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"Dijkstra's algorithm is a greedy algorithm too, try to think why it is correct.")),(0,s.kt)("h2",{id:"top-down-dp"},"Top-down DP"),(0,s.kt)("p",null,(0,s.kt)("em",{parentName:"p"},"Top-down dynamic programming")," is probably the most common approach, since (at\nleast looks like) is the easiest to implement. The whole point is avoiding the\nunnecessary computations that we have already done."),(0,s.kt)("p",null,"In our case, we can use our na\xefve solution and put a ",(0,s.kt)("em",{parentName:"p"},"cache")," on top of it that\nwill make sure, we don't do unnecessary calculations."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"// This \u201cstructure\u201d is required, since I have decided to use \u2039TreeMap\u203a which\n// requires the ordering on the keys. It represents one position in the pyramid.\nrecord Position(int row, int col) implements Comparable {\n public int compareTo(Position r) {\n if (row != r.row) {\n return Integer.valueOf(row).compareTo(r.row);\n }\n\n if (col != r.col) {\n return Integer.valueOf(col).compareTo(r.col);\n }\n\n return 0;\n }\n}\n\npublic static int longestSlideDown(\n int[][] pyramid,\n TreeMap cache,\n Position position) {\n int row = position.row;\n int col = position.col;\n\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: out of bounds\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: bottom of the pyramid\n return pyramid[position.row][position.col];\n }\n\n if (!cache.containsKey(position)) {\n // We haven't computed the position yet, so we run the same \u201cformula\u201d as\n // in the na\xefve version \xbband\xab we put calculated slide into the cache.\n // Next time we want the slide down from given position, it will be just\n // retrieved from the cache.\n int slideDown = Math.max(\n longestSlideDown(pyramid, cache, new Position(row + 1, col)),\n longestSlideDown(pyramid, cache, new Position(row + 1, col + 1)));\n cache.put(position, pyramid[row][col] + slideDown);\n }\n\n return cache.get(position);\n}\n\npublic static int longestSlideDown(int[][] pyramid) {\n // At the beginning we need to create a cache and share it across the calls.\n TreeMap cache = new TreeMap<>();\n return longestSlideDown(pyramid, cache, new Position(0, 0));\n}\n")),(0,s.kt)("p",null,"You have probably noticed that ",(0,s.kt)("inlineCode",{parentName:"p"},"record Position")," have appeared. Since we are\ncaching the already computed values, we need a \u201creasonable\u201d key. In this case we\nshare the cache only for one ",(0,s.kt)("em",{parentName:"p"},"run")," (i.e. pyramid) of the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown"),", so\nwe can cache just with the indices within the pyramid, i.e. the ",(0,s.kt)("inlineCode",{parentName:"p"},"Position"),"."),(0,s.kt)("admonition",{title:"Record",type:"tip"},(0,s.kt)("p",{parentName:"admonition"},(0,s.kt)("em",{parentName:"p"},"Record")," is relatively new addition to the Java language. It is basically an\nimmutable structure with implicitly defined ",(0,s.kt)("inlineCode",{parentName:"p"},".equals()"),", ",(0,s.kt)("inlineCode",{parentName:"p"},".hashCode()"),",\n",(0,s.kt)("inlineCode",{parentName:"p"},".toString()")," and getters for the attributes.")),(0,s.kt)("p",null,"Because of the choice of ",(0,s.kt)("inlineCode",{parentName:"p"},"TreeMap"),", we had to additionally define the ordering\non it."),(0,s.kt)("p",null,"In the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown")," you can notice that the computation which used to be\nat the end of the na\xefve version above, is now wrapped in an ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," statement that\nchecks for the presence of the position in the cache and computes the slide down\njust when it's needed."),(0,s.kt)("h3",{id:"time-complexity-2"},"Time complexity"),(0,s.kt)("p",null,"If you think that evaluating time complexity for this approach is a bit more\ntricky, you are right. Keeping the cache in mind, it is not the easiest thing\nto do. However there are some observations that might help us figure this out:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"Slide down from each position is calculated only once."),(0,s.kt)("li",{parentName:"ol"},"Once calculated, we use the result from the cache.")),(0,s.kt)("p",null,"Knowing this, we still cannot, at least easily, describe the time complexity of\nfinding the best slide down from a specific position, ",(0,s.kt)("strong",{parentName:"p"},"but")," we can bound it\nfrom above for the ",(0,s.kt)("strong",{parentName:"p"},"whole")," run from the top. Now the question is how we can do\nthat!"),(0,s.kt)("p",null,"Overall we are doing the same things for almost",(0,s.kt)("sup",{parentName:"p",id:"fnref-2"},(0,s.kt)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2"))," all of the positions within\nthe pyramid:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},"We calculate and store it (using the partial results stored in cache). This\nis done only once."),(0,s.kt)("p",{parentName:"li"},"For each calculation we take 2 values from the cache and insert one value.\nBecause we have chosen ",(0,s.kt)("inlineCode",{parentName:"p"},"TreeMap"),", these 3 operations have logarithmic time\ncomplexity and therefore this step is equivalent to ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mn",{parentName:"mrow"},"3"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"3 \\cdot \\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"3"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),"."),(0,s.kt)("p",{parentName:"li"},"However for the sake of simplicity, we are going to account only for the\ninsertion, the reason is rather simple, if we include the 2 retrievals here,\nit will be interleaved with the next step, therefore it is easier to keep the\nretrievals in the following point."),(0,s.kt)("admonition",{parentName:"li",type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"You might have noticed it's still not that easy, cause we're not having full\ncache right from the beginning, but the sum of those logarithms cannot be\nexpressed in a nice way, so taking the upper bound, i.e. expecting the cache\nto be full at all times, is the best option for nice and readable complexity\nof the whole approach.")),(0,s.kt)("p",{parentName:"li"},"Our final upper bound of this work is therefore ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),".")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},"We retrieve it from the cache. Same as in first point, but only twice, so we\nget ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2 \\cdot \\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),". "),(0,s.kt)("admonition",{parentName:"li",type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"It's done twice because of the ",(0,s.kt)("inlineCode",{parentName:"p"},".containsKey()")," in the ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," condition.")))),(0,s.kt)("p",null,"Okay, we have evaluated work done for each of the cells in the pyramid and now\nwe need to put it together."),(0,s.kt)("p",null,"Let's split the time complexity of our solution into two operands:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(r + s)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"r")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"r")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))))," will represent the ",(0,s.kt)("em",{parentName:"p"},"actual")," calculation of the cells and ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"s")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"s")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))))," will represent\nthe additional retrievals on top of the calculation."),(0,s.kt)("p",null,"We calculate the values only ",(0,s.kt)("strong",{parentName:"p"},"once"),", therefore we can safely agree on:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"r"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} r &= n \\cdot \\log{n} \\\\ \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1.5em",verticalAlign:"-0.5em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.16em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.5em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.16em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.5em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("p",null,"What about the ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"s")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"s")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))))," though? Key observation here is the fact that we have 2\nlookups on the tree in each of them ",(0,s.kt)("strong",{parentName:"p"},"and")," we do it twice, cause each cell has\nat most 2 parents:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"("),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",fence:"true"},")")))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"4"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} s &= n \\cdot 2 \\cdot \\left( 2 \\cdot \\log{n} \\right) \\\\ s &= 4 \\cdot n \\cdot \\log{n} \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose delimcenter",style:{top:"0em"}},")")))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"4"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"You might've noticed that lookups actually take more time than the construction\nof the results. This is not entirely true, since we have included the\n",(0,s.kt)("inlineCode",{parentName:"p"},".containsKey()")," and ",(0,s.kt)("inlineCode",{parentName:"p"},".get()")," from the ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statement in the second part."),(0,s.kt)("p",{parentName:"admonition"},"If we were to represent this more precisely, we could've gone with:"),(0,s.kt)("div",{parentName:"admonition",className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"r"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"3"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} r &= 3 \\cdot n \\cdot \\log{n} \\\\ s &= 2 \\cdot n \\cdot \\log{n} \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"3"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("p",{parentName:"admonition"},"On the other hand we are summing both numbers together, therefore in the end it\ndoesn't really matter."),(0,s.kt)("p",{parentName:"admonition"},"(",(0,s.kt)("em",{parentName:"p"},"Feel free to compare the sums of both \u201csplits\u201d."),")")),(0,s.kt)("p",null,"And so our final time complexity for the whole ",(0,s.kt)("em",{parentName:"p"},"top-down dynamic programming"),"\napproach is:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"4"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mn",{parentName:"mrow"},"5"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(r + s) \\\\ \\mathcal{O}(n \\cdot \\log{n} + 4 \\cdot n \\cdot \\log{n}) \\\\ \\mathcal{O}(5 \\cdot n \\cdot \\log{n}) \\\\ \\mathcal{O}(n \\cdot \\log{n})")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"4"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4445em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},"5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4445em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"As you can see, this is worse than our ",(0,s.kt)("em",{parentName:"p"},"greedy")," solution that was incorrect, but\nit's better than the ",(0,s.kt)("em",{parentName:"p"},"na\xefve")," one."),(0,s.kt)("h3",{id:"memory-complexity"},"Memory complexity"),(0,s.kt)("p",null,"With this approach we need to talk about the memory complexity too, because we\nhave introduced cache. If you think that the memory complexity is linear to the\ninput, you are right. We start at the top and try to find each and every slide\ndown. At the end we get the final result for ",(0,s.kt)("inlineCode",{parentName:"p"},"new Position(0, 0)"),", so we need to\ncompute everything below."),(0,s.kt)("p",null,"That's how we obtain:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," represents the total amount of cells in the pyramid, i.e."),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("munderover",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"munderover"},"\u2211"),(0,s.kt)("mrow",{parentName:"munderover"},(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"0")),(0,s.kt)("mrow",{parentName:"munderover"},(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"p"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"y"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"r"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"."),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"g"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"h")),(0,s.kt)("mo",{parentName:"mrow"},"\u2212"),(0,s.kt)("mn",{parentName:"mrow"},"1"))),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"p"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"y"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"r"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d")),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"["),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"]")),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"."),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"g"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"h"))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\sum_{y=0}^{\\mathtt{pyramid.length} - 1} \\mathtt{pyramid}\\left[y\\right]\\mathtt{.length}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3.2709em",verticalAlign:"-1.4032em"}}),(0,s.kt)("span",{parentName:"span",className:"mop op-limits"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.8677em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-1.8829em",marginLeft:"0em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mrel mtight"},"="),(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,s.kt)("span",{parentName:"span",style:{top:"-3.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span"},(0,s.kt)("span",{parentName:"span",className:"mop op-symbol large-op"},"\u2211"))),(0,s.kt)("span",{parentName:"span",style:{top:"-4.3666em",marginLeft:"0em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt mtight"},"pyramid.length")),(0,s.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.4032em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt"},"pyramid")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},"["),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mclose delimcenter",style:{top:"0em"}},"]")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt"},".length"))))))),(0,s.kt)("admonition",{type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"If you're wondering whether it's correct because of the second ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," in our\nfunction, your guess is right. However we are expressing the complexity in the\nBachmann-Landau notation, so we care about the ",(0,s.kt)("strong",{parentName:"p"},"upper bound"),", not the exact\nnumber.")),(0,s.kt)("admonition",{title:"Can this be optimized?",type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"Yes, it can! Try to think about a way, how can you minimize the memory\ncomplexity of this approach. I'll give you a hint:"),(0,s.kt)("div",{parentName:"admonition",className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"))))))),(0,s.kt)("h2",{id:"bottom-up-dp"},"Bottom-up DP"),(0,s.kt)("p",null,"If you try to think in depth about the top-down DP solution, you might notice\nthat the ",(0,s.kt)("em",{parentName:"p"},"core")," of it stands on caching the calculations that have been already\ndone on the lower \u201clevels\u201d of the pyramid. Our bottom-up implementation will be\nusing this fact!"),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"As I have said in the ",(0,s.kt)("em",{parentName:"p"},"top-down DP")," section, it is the easiest way to implement\nDP (unless the cached function has complicated parameters, in that case it might\nget messy)."),(0,s.kt)("p",{parentName:"admonition"},"Bottom-up dynamic programming can be more effective, but may be more complicated\nto implement right from the beginning.")),(0,s.kt)("p",null,"Let's see how we can implement it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid) {\n // In the beginning we declare new array. At this point it is easier to just\n // work with the one dimension, i.e. just allocating the space for the rows.\n int[][] slideDowns = new int[pyramid.length][];\n\n // Bottom row gets just copied, there's nothing else to do\u2026 It's the base\n // case.\n slideDowns[pyramid.length - 1] = Arrays.copyOf(pyramid[pyramid.length - 1],\n pyramid[pyramid.length - 1].length);\n\n // Then we need to propagate the found slide downs for each of the levels\n // above.\n for (int y = pyramid.length - 2; y >= 0; --y) {\n // We start by copying the values lying in the row we're processing.\n // They get included in the final sum and we need to allocate the space\n // for the precalculated slide downs anyways.\n int[] row = Arrays.copyOf(pyramid[y], pyramid[y].length);\n\n // At this we just need to \u201cfetch\u201d the partial results from \u201cneighbours\u201d\n for (int x = 0; x < row.length; ++x) {\n // We look under our position, since we expect the rows to get\n // shorter, we can safely assume such position exists.\n int under = slideDowns[y + 1][x];\n\n // Then we have a look to the right, such position doesn't have to\n // exist, e.g. on the right edge, so we validate the index, and if\n // it doesn't exist, we just assign minimum of the \u2039int\u203a which makes\n // sure that it doesn't get picked in the \u2039Math.max()\u203a call.\n int toRight = x + 1 < slideDowns[y + 1].length\n ? slideDowns[y + 1][x + 1]\n : Integer.MIN_VALUE;\n\n // Finally we add the best choice at this point.\n row[x] += Math.max(under, toRight);\n }\n\n // And save the row we've just calculated partial results for to the\n // \u201ctable\u201d.\n slideDowns[y] = row;\n }\n\n // At the end we can find our seeked slide down at the top cell.\n return slideDowns[0][0];\n}\n")),(0,s.kt)("p",null,"I've tried to explain the code as much as possible within the comments, since it\nmight be more beneficial to see right next to the \u201coffending\u201d lines."),(0,s.kt)("p",null,"As you can see, in this approach we go from the other side",(0,s.kt)("sup",{parentName:"p",id:"fnref-3"},(0,s.kt)("a",{parentName:"sup",href:"#fn-3",className:"footnote-ref"},"3")),", the bottom of\nthe pyramid and propagate the partial results up."),(0,s.kt)("admonition",{type:"info"},(0,s.kt)("mdxAdmonitionTitle",{parentName:"admonition"},"How is this different from the ",(0,s.kt)("em",{parentName:"mdxAdmonitionTitle"},"greedy")," solution???"),(0,s.kt)("p",{parentName:"admonition"},"If you try to compare them, you might find a very noticable difference. The\ngreedy approach is going from the top to the bottom without ",(0,s.kt)("strong",{parentName:"p"},"any")," knowledge of\nwhat's going on below. On the other hand, bottom-up DP is going from the bottom\n(",(0,s.kt)("em",{parentName:"p"},"DUH\u2026"),") and ",(0,s.kt)("strong",{parentName:"p"},"propagates")," the partial results to the top. The propagation is\nwhat makes sure that at the top I don't choose the best ",(0,s.kt)("strong",{parentName:"p"},"local")," choice, but\nthe best ",(0,s.kt)("strong",{parentName:"p"},"overall")," result I can achieve.")),(0,s.kt)("h3",{id:"time-complexity-3"},"Time complexity"),(0,s.kt)("p",null,"Time complexity of this solution is rather simple. We allocate an array for the\nrows and then for each row, we copy it and adjust the partial results. Doing\nthis we get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows + 2n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"Of course, this is an upper bound, since we iterate through the bottom row only\nonce."),(0,s.kt)("h3",{id:"memory-complexity-1"},"Memory complexity"),(0,s.kt)("p",null,"We're allocating an array for the pyramid ",(0,s.kt)("strong",{parentName:"p"},"again")," for our partial results, so\nwe get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"If we were writing this in C++ or Rust, we could've avoided that, but not\nreally."),(0,s.kt)("p",{parentName:"admonition"},"C++ would allow us to ",(0,s.kt)("strong",{parentName:"p"},"copy")," the pyramid rightaway into the parameter, so we\nwould be able to directly change it. However it's still a copy, even though we\ndon't need to allocate anything ourselves. It's just implicitly done for us."),(0,s.kt)("p",{parentName:"admonition"},"Rust is more funny in this case. If the pyramids weren't used after the call of\n",(0,s.kt)("inlineCode",{parentName:"p"},"longest_slide_down"),", it would simply ",(0,s.kt)("strong",{parentName:"p"},"move")," them into the functions. If they\nwere used afterwards, the compiler would force you to either borrow it, or\n",(0,s.kt)("em",{parentName:"p"},"clone-and-move")," for the function."),(0,s.kt)("hr",{parentName:"admonition"}),(0,s.kt)("p",{parentName:"admonition"},"Since we're doing it in Java, we get a reference to the ",(0,s.kt)("em",{parentName:"p"},"original")," array and we\ncan't do whatever we want with it.")),(0,s.kt)("h2",{id:"summary"},"Summary"),(0,s.kt)("p",null,"And we've finally reached the end. We have seen 4 different \u201csolutions\u201d",(0,s.kt)("sup",{parentName:"p",id:"fnref-4"},(0,s.kt)("a",{parentName:"sup",href:"#fn-4",className:"footnote-ref"},"4"))," of\nthe same problem using different approaches. Different approaches follow the\norder in which you might come up with them, each approach influences its\nsuccessor and represents the way we can enhance the existing implementation."),(0,s.kt)("hr",null),(0,s.kt)("admonition",{title:"source",type:"info"},(0,s.kt)("p",{parentName:"admonition"},"You can find source code referenced in the text\n",(0,s.kt)("a",{parentName:"p",href:"pathname:///files/ib002/recursion/pyramid-slide-down.tar.gz"},"here"),".")),(0,s.kt)("div",{className:"footnotes"},(0,s.kt)("hr",{parentName:"div"}),(0,s.kt)("ol",{parentName:"div"},(0,s.kt)("li",{parentName:"ol",id:"fn-1"},"cause why not, right!?",(0,s.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-2"},"except the bottom row",(0,s.kt)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-3"},"definitely not an RHCP reference \ud83d\ude09",(0,s.kt)("a",{parentName:"li",href:"#fnref-3",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-4"},"one was not correct, thus the quotes",(0,s.kt)("a",{parentName:"li",href:"#fnref-4",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/834ed470.ae70d26f.js b/assets/js/834ed470.15bfe5dc.js similarity index 96% rename from assets/js/834ed470.ae70d26f.js rename to assets/js/834ed470.15bfe5dc.js index f773bb0..9d4c36f 100644 --- a/assets/js/834ed470.ae70d26f.js +++ b/assets/js/834ed470.15bfe5dc.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3223],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=o,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"ib002-intro",title:"Introduction",slug:"/"},i=void 0,s={unversionedId:"ib002-intro",id:"ib002-intro",title:"Introduction",description:"In this part you can find \u201crandom\u201d additional materials I have written over the",source:"@site/ib002/00-intro-ib002.md",sourceDirName:".",slug:"/",permalink:"/ib002/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/00-intro-ib002.md",tags:[],version:"current",lastUpdatedAt:1694110423,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"ib002-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Algorithms and Correctness",permalink:"/ib002/category/algorithms-and-correctness"}},c={},l=[],u={toc:l},p="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"In this part you can find \u201crandom\u201d additional materials I have written over the\ncourse of teaching ",(0,o.kt)("em",{parentName:"p"},"Algorithms and data structures I"),"."),(0,o.kt)("p",null,"It is a various mix of stuff that may have been produced as a follow-up on some\nquestion asked at the seminar or spontanously."),(0,o.kt)("p",null,"If you have some ideas for posts, please do not hesitate to submit them as issues\nin the linked ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/xfocko/kb/issues"},"GitLab"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3223],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=o,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"ib002-intro",title:"Introduction",slug:"/"},i=void 0,s={unversionedId:"ib002-intro",id:"ib002-intro",title:"Introduction",description:"In this part you can find \u201crandom\u201d additional materials I have written over the",source:"@site/ib002/00-intro-ib002.md",sourceDirName:".",slug:"/",permalink:"/ib002/",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/00-intro-ib002.md",tags:[],version:"current",lastUpdatedAt:1694111094,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"ib002-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Algorithms and Correctness",permalink:"/ib002/category/algorithms-and-correctness"}},c={},l=[],u={toc:l},p="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"In this part you can find \u201crandom\u201d additional materials I have written over the\ncourse of teaching ",(0,o.kt)("em",{parentName:"p"},"Algorithms and data structures I"),"."),(0,o.kt)("p",null,"It is a various mix of stuff that may have been produced as a follow-up on some\nquestion asked at the seminar or spontanously."),(0,o.kt)("p",null,"If you have some ideas for posts, please do not hesitate to submit them as issues\nin the linked ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/xfocko/kb/issues"},"GitLab"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/83bf91d3.d0466885.js b/assets/js/83bf91d3.e7bae794.js similarity index 98% rename from assets/js/83bf91d3.d0466885.js rename to assets/js/83bf91d3.e7bae794.js index 65dbd8b..0a32c3a 100644 --- a/assets/js/83bf91d3.d0466885.js +++ b/assets/js/83bf91d3.e7bae794.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7823],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=p(n),h=a,d=m["".concat(l,".").concat(h)]||m[h]||c[h]||o;return n?r.createElement(d,i(i({ref:t},u),{},{components:n})):r.createElement(d,i({ref:t},u))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:a,i[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const o={title:"Submitting merge requests"},i="Submitting merge requests for review",s={unversionedId:"mr",id:"mr",title:"Submitting merge requests",description:"This tutorial aims to show you how to follow basic git workflow and submit changes",source:"@site/pb071/mr.md",sourceDirName:".",slug:"/mr",permalink:"/pb071/mr",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/mr.md",tags:[],version:"current",lastUpdatedAt:1694110423,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{title:"Submitting merge requests"},sidebar:"autogeneratedBar",previous:{title:"Practice exam C",permalink:"/pb071/pexam/cams"}},l={},p=[{value:"Tutorial",id:"tutorial",level:2},{value:"Step #1 - Starting from the clean repository",id:"step-1---starting-from-the-clean-repository",level:3},{value:"Step #2 - Create new branch",id:"step-2---create-new-branch",level:3},{value:"Step #3 - Do the assignment",id:"step-3---do-the-assignment",level:3},{value:"Step #4 - Commit and upload the changes to GitLab",id:"step-4---commit-and-upload-the-changes-to-gitlab",level:3},{value:"Step #5 - Creating a merge request manually",id:"step-5---creating-a-merge-request-manually",level:3},{value:"Step #6 - Set assignees",id:"step-6---set-assignees",level:3},{value:"Step #7 - Return to default branch",id:"step-7---return-to-default-branch",level:3}],u={toc:p},m="wrapper";function c(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"submitting-merge-requests-for-review"},"Submitting merge requests for review"),(0,a.kt)("p",null,"This tutorial aims to show you how to follow basic git workflow and submit changes\nthrough ",(0,a.kt)("em",{parentName:"p"},"Merge Requests")," for review."),(0,a.kt)("p",null,"The rudimentary idea behind aims for changes to be present on a separate branch\nthat is supposedly ",(0,a.kt)("em",{parentName:"p"},"merged")," into the default branch. Till then changes can be reviewed\non ",(0,a.kt)("em",{parentName:"p"},"Merge Request")," and additional changes may be made based on the reviews. Once\nthe changes satisfy requirements, the merge request is merged."),(0,a.kt)("h2",{id:"tutorial"},"Tutorial"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Use this tutorial only for bonus assignments ",(0,a.kt)("strong",{parentName:"p"},"made by your tutors")," or in case\nyou need to make up for the absence.")),(0,a.kt)("h3",{id:"step-1---starting-from-the-clean-repository"},"Step #1 - Starting from the clean repository"),(0,a.kt)("p",null,"In your repository (either locally or on aisa) type ",(0,a.kt)("inlineCode",{parentName:"p"},"git status")," and check if your\nrepository is clean and you are present on the main branch (",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," or\n",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),"). If you do not know what your default branch is, it is probably ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),"\nand you should not be on any other branch."),(0,a.kt)("p",null,"Output of the command should look like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git status\nOn branch master # Or main or trunk.\nYour branch is up to date with 'origin/master'.\n\nnothing to commit, working tree clean\n")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"In case you are on different branch or there are uncommitted changes,\n",(0,a.kt)("strong",{parentName:"p"},"do not continue!!!")," Clean your repository (commit the changes or discard\nthem), before you continue.")),(0,a.kt)("h3",{id:"step-2---create-new-branch"},"Step #2 - Create new branch"),(0,a.kt)("p",null,"In your repository write command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git checkout -b BRANCH\nSwitched to a new branch 'BRANCH'\n")),(0,a.kt)("p",null,"Instead of ",(0,a.kt)("inlineCode",{parentName:"p"},"BRANCH")," use some reasonable name for the branch. For example if you\nare working on the seminar from 3rd week, name the branch ",(0,a.kt)("inlineCode",{parentName:"p"},"seminar-03"),"."),(0,a.kt)("h3",{id:"step-3---do-the-assignment"},"Step #3 - Do the assignment"),(0,a.kt)("p",null,"Download the skeleton for the seminar assignment, extract and program. For example\nif you are working on 3rd seminar, you can do so by:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ wget https://www.fi.muni.cz/pb071/seminars/seminar-03/pb071-seminar-03.zip\naisa$ unzip pb071-seminar-03.zip\n# Now you should have directory 'seminar-03'.\naisa$ rm pb071-seminar-03.zip\naisa$ cd seminar-03\n# You can work on the assignment.\n")),(0,a.kt)("h3",{id:"step-4---commit-and-upload-the-changes-to-gitlab"},"Step #4 - Commit and upload the changes to GitLab"),(0,a.kt)("p",null,"The same way you ",(0,a.kt)("em",{parentName:"p"},"add")," and ",(0,a.kt)("em",{parentName:"p"},"commit")," files for the homework assignments, you do for\nthe seminar."),(0,a.kt)("p",null,"Now you can upload the changes to GitLab. ",(0,a.kt)("inlineCode",{parentName:"p"},"git push")," is not enough, since repository\non GitLab does not know your new branch. You can solve this by adding arguments:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git push origin BRANCH\n...\nremote: To create a merge request for BRANCH, visit:\nremote: https://gitlab.fi.muni.cz/login/pb071/merge_requests/new?merge_request%5Bsource_branch%5D=BRANCH\n...\n")),(0,a.kt)("p",null,"In the output you should have a link for creating a merge request. If you see this\nlink, open it and skip next step."),(0,a.kt)("h3",{id:"step-5---creating-a-merge-request-manually"},"Step #5 - Creating a merge request manually"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Open your repository on GitLab."),(0,a.kt)("li",{parentName:"ol"},"On the left panel click on ",(0,a.kt)("em",{parentName:"li"},"Merge Requests"),"."),(0,a.kt)("li",{parentName:"ol"},"Click on ",(0,a.kt)("em",{parentName:"li"},"New Merge Request"),"."),(0,a.kt)("li",{parentName:"ol"},"In ",(0,a.kt)("em",{parentName:"li"},"Source branch")," select ",(0,a.kt)("inlineCode",{parentName:"li"},"login/pb071")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"BRANCH"),", which you created."),(0,a.kt)("li",{parentName:"ol"},"In ",(0,a.kt)("em",{parentName:"li"},"Target branch")," select ",(0,a.kt)("inlineCode",{parentName:"li"},"login/pb071")," and your default branch you have seen\nin the output of the first command. (most likely ",(0,a.kt)("inlineCode",{parentName:"li"},"master"),")"),(0,a.kt)("li",{parentName:"ol"},"Click on ",(0,a.kt)("em",{parentName:"li"},"Compare branches and continue"),".")),(0,a.kt)("h3",{id:"step-6---set-assignees"},"Step #6 - Set assignees"),(0,a.kt)("p",null,"On the page that is opened, please check at the top that you are creating merge\nrequest ",(0,a.kt)("strong",{parentName:"p"},"from")," your new branch ",(0,a.kt)("strong",{parentName:"p"},"to")," your default branch (one of ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"main"),"\nor ",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),")."),(0,a.kt)("p",null,"Then in the field ",(0,a.kt)("em",{parentName:"p"},"Assignees")," set your tutors based on the seminar group. You can\nuse login for a quick look up."),(0,a.kt)("p",null,"In the end click on ",(0,a.kt)("em",{parentName:"p"},"Submit merge request"),"."),(0,a.kt)("h3",{id:"step-7---return-to-default-branch"},"Step #7 - Return to default branch"),(0,a.kt)("p",null,"Homework assignments can be submitted only from branches specified in the rules\nfor the course. Because of that, before you do anything else, you should switch\nback to your default branch."),(0,a.kt)("p",null,"First of all, same as in step #1, check that your repository is clean with ",(0,a.kt)("inlineCode",{parentName:"p"},"git status"),".\nFor the sake of safety, do not continue without clean repository. Then with command\n",(0,a.kt)("inlineCode",{parentName:"p"},"git checkout BRANCH")," switch to your default branch ",(0,a.kt)("inlineCode",{parentName:"p"},"BRANCH"),"."),(0,a.kt)("p",null,"If you do not know which branch is your default, try ",(0,a.kt)("inlineCode",{parentName:"p"},"git branch")," that outputs all branches in your repository. Default branch is typically ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", but can\nbe ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git status\n# Check if repository is clean\n\n# If you know, what is your default branch, you can skip next command.\naisa$ git branch\n# Find the default branch in the list; should be one of the `master`, `main` or\n# `trunk` and you should not have more than one of those.\n# In case the list clears the terminal and you cannot see shell prompt, you can\n# press `q` to quit the pager.\n\naisa$ git checkout master\n")),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Adapted from: ",(0,a.kt)("a",{parentName:"p",href:"https://www.fi.muni.cz/~xlacko1/pb071/mr.html"},"https://www.fi.muni.cz/~xlacko1/pb071/mr.html")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7823],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=p(n),h=a,d=m["".concat(l,".").concat(h)]||m[h]||c[h]||o;return n?r.createElement(d,i(i({ref:t},u),{},{components:n})):r.createElement(d,i({ref:t},u))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:a,i[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const o={title:"Submitting merge requests"},i="Submitting merge requests for review",s={unversionedId:"mr",id:"mr",title:"Submitting merge requests",description:"This tutorial aims to show you how to follow basic git workflow and submit changes",source:"@site/pb071/mr.md",sourceDirName:".",slug:"/mr",permalink:"/pb071/mr",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/mr.md",tags:[],version:"current",lastUpdatedAt:1694111094,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{title:"Submitting merge requests"},sidebar:"autogeneratedBar",previous:{title:"Practice exam C",permalink:"/pb071/pexam/cams"}},l={},p=[{value:"Tutorial",id:"tutorial",level:2},{value:"Step #1 - Starting from the clean repository",id:"step-1---starting-from-the-clean-repository",level:3},{value:"Step #2 - Create new branch",id:"step-2---create-new-branch",level:3},{value:"Step #3 - Do the assignment",id:"step-3---do-the-assignment",level:3},{value:"Step #4 - Commit and upload the changes to GitLab",id:"step-4---commit-and-upload-the-changes-to-gitlab",level:3},{value:"Step #5 - Creating a merge request manually",id:"step-5---creating-a-merge-request-manually",level:3},{value:"Step #6 - Set assignees",id:"step-6---set-assignees",level:3},{value:"Step #7 - Return to default branch",id:"step-7---return-to-default-branch",level:3}],u={toc:p},m="wrapper";function c(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"submitting-merge-requests-for-review"},"Submitting merge requests for review"),(0,a.kt)("p",null,"This tutorial aims to show you how to follow basic git workflow and submit changes\nthrough ",(0,a.kt)("em",{parentName:"p"},"Merge Requests")," for review."),(0,a.kt)("p",null,"The rudimentary idea behind aims for changes to be present on a separate branch\nthat is supposedly ",(0,a.kt)("em",{parentName:"p"},"merged")," into the default branch. Till then changes can be reviewed\non ",(0,a.kt)("em",{parentName:"p"},"Merge Request")," and additional changes may be made based on the reviews. Once\nthe changes satisfy requirements, the merge request is merged."),(0,a.kt)("h2",{id:"tutorial"},"Tutorial"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Use this tutorial only for bonus assignments ",(0,a.kt)("strong",{parentName:"p"},"made by your tutors")," or in case\nyou need to make up for the absence.")),(0,a.kt)("h3",{id:"step-1---starting-from-the-clean-repository"},"Step #1 - Starting from the clean repository"),(0,a.kt)("p",null,"In your repository (either locally or on aisa) type ",(0,a.kt)("inlineCode",{parentName:"p"},"git status")," and check if your\nrepository is clean and you are present on the main branch (",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," or\n",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),"). If you do not know what your default branch is, it is probably ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),"\nand you should not be on any other branch."),(0,a.kt)("p",null,"Output of the command should look like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git status\nOn branch master # Or main or trunk.\nYour branch is up to date with 'origin/master'.\n\nnothing to commit, working tree clean\n")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"In case you are on different branch or there are uncommitted changes,\n",(0,a.kt)("strong",{parentName:"p"},"do not continue!!!")," Clean your repository (commit the changes or discard\nthem), before you continue.")),(0,a.kt)("h3",{id:"step-2---create-new-branch"},"Step #2 - Create new branch"),(0,a.kt)("p",null,"In your repository write command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git checkout -b BRANCH\nSwitched to a new branch 'BRANCH'\n")),(0,a.kt)("p",null,"Instead of ",(0,a.kt)("inlineCode",{parentName:"p"},"BRANCH")," use some reasonable name for the branch. For example if you\nare working on the seminar from 3rd week, name the branch ",(0,a.kt)("inlineCode",{parentName:"p"},"seminar-03"),"."),(0,a.kt)("h3",{id:"step-3---do-the-assignment"},"Step #3 - Do the assignment"),(0,a.kt)("p",null,"Download the skeleton for the seminar assignment, extract and program. For example\nif you are working on 3rd seminar, you can do so by:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ wget https://www.fi.muni.cz/pb071/seminars/seminar-03/pb071-seminar-03.zip\naisa$ unzip pb071-seminar-03.zip\n# Now you should have directory 'seminar-03'.\naisa$ rm pb071-seminar-03.zip\naisa$ cd seminar-03\n# You can work on the assignment.\n")),(0,a.kt)("h3",{id:"step-4---commit-and-upload-the-changes-to-gitlab"},"Step #4 - Commit and upload the changes to GitLab"),(0,a.kt)("p",null,"The same way you ",(0,a.kt)("em",{parentName:"p"},"add")," and ",(0,a.kt)("em",{parentName:"p"},"commit")," files for the homework assignments, you do for\nthe seminar."),(0,a.kt)("p",null,"Now you can upload the changes to GitLab. ",(0,a.kt)("inlineCode",{parentName:"p"},"git push")," is not enough, since repository\non GitLab does not know your new branch. You can solve this by adding arguments:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git push origin BRANCH\n...\nremote: To create a merge request for BRANCH, visit:\nremote: https://gitlab.fi.muni.cz/login/pb071/merge_requests/new?merge_request%5Bsource_branch%5D=BRANCH\n...\n")),(0,a.kt)("p",null,"In the output you should have a link for creating a merge request. If you see this\nlink, open it and skip next step."),(0,a.kt)("h3",{id:"step-5---creating-a-merge-request-manually"},"Step #5 - Creating a merge request manually"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Open your repository on GitLab."),(0,a.kt)("li",{parentName:"ol"},"On the left panel click on ",(0,a.kt)("em",{parentName:"li"},"Merge Requests"),"."),(0,a.kt)("li",{parentName:"ol"},"Click on ",(0,a.kt)("em",{parentName:"li"},"New Merge Request"),"."),(0,a.kt)("li",{parentName:"ol"},"In ",(0,a.kt)("em",{parentName:"li"},"Source branch")," select ",(0,a.kt)("inlineCode",{parentName:"li"},"login/pb071")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"BRANCH"),", which you created."),(0,a.kt)("li",{parentName:"ol"},"In ",(0,a.kt)("em",{parentName:"li"},"Target branch")," select ",(0,a.kt)("inlineCode",{parentName:"li"},"login/pb071")," and your default branch you have seen\nin the output of the first command. (most likely ",(0,a.kt)("inlineCode",{parentName:"li"},"master"),")"),(0,a.kt)("li",{parentName:"ol"},"Click on ",(0,a.kt)("em",{parentName:"li"},"Compare branches and continue"),".")),(0,a.kt)("h3",{id:"step-6---set-assignees"},"Step #6 - Set assignees"),(0,a.kt)("p",null,"On the page that is opened, please check at the top that you are creating merge\nrequest ",(0,a.kt)("strong",{parentName:"p"},"from")," your new branch ",(0,a.kt)("strong",{parentName:"p"},"to")," your default branch (one of ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"main"),"\nor ",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),")."),(0,a.kt)("p",null,"Then in the field ",(0,a.kt)("em",{parentName:"p"},"Assignees")," set your tutors based on the seminar group. You can\nuse login for a quick look up."),(0,a.kt)("p",null,"In the end click on ",(0,a.kt)("em",{parentName:"p"},"Submit merge request"),"."),(0,a.kt)("h3",{id:"step-7---return-to-default-branch"},"Step #7 - Return to default branch"),(0,a.kt)("p",null,"Homework assignments can be submitted only from branches specified in the rules\nfor the course. Because of that, before you do anything else, you should switch\nback to your default branch."),(0,a.kt)("p",null,"First of all, same as in step #1, check that your repository is clean with ",(0,a.kt)("inlineCode",{parentName:"p"},"git status"),".\nFor the sake of safety, do not continue without clean repository. Then with command\n",(0,a.kt)("inlineCode",{parentName:"p"},"git checkout BRANCH")," switch to your default branch ",(0,a.kt)("inlineCode",{parentName:"p"},"BRANCH"),"."),(0,a.kt)("p",null,"If you do not know which branch is your default, try ",(0,a.kt)("inlineCode",{parentName:"p"},"git branch")," that outputs all branches in your repository. Default branch is typically ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", but can\nbe ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git status\n# Check if repository is clean\n\n# If you know, what is your default branch, you can skip next command.\naisa$ git branch\n# Find the default branch in the list; should be one of the `master`, `main` or\n# `trunk` and you should not have more than one of those.\n# In case the list clears the terminal and you cannot see shell prompt, you can\n# press `q` to quit the pager.\n\naisa$ git checkout master\n")),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Adapted from: ",(0,a.kt)("a",{parentName:"p",href:"https://www.fi.muni.cz/~xlacko1/pb071/mr.html"},"https://www.fi.muni.cz/~xlacko1/pb071/mr.html")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/90425ffc.955d8c56.js b/assets/js/90425ffc.a4229fd7.js similarity index 99% rename from assets/js/90425ffc.955d8c56.js rename to assets/js/90425ffc.a4229fd7.js index df40a0c..8d8cba4 100644 --- a/assets/js/90425ffc.955d8c56.js +++ b/assets/js/90425ffc.a4229fd7.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[8769],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>h});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},m=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=o,h=u["".concat(l,".").concat(d)]||u[d]||c[d]||i;return n?a.createElement(h,r(r({ref:t},m),{},{components:n})):a.createElement(h,r({ref:t},m))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:o,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={id:"seminar-03",title:"3rd seminar",description:"Select sort implementation on arrays.\n",last_update:{date:new Date("2023-03-07T00:00:00.000Z")}},r=void 0,s={unversionedId:"bonuses/seminar-03",id:"bonuses/seminar-03",title:"3rd seminar",description:"Select sort implementation on arrays.\n",source:"@site/pb071/bonuses/03.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-03",permalink:"/pb071/bonuses/seminar-03",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/03.md",tags:[],version:"current",lastUpdatedAt:1678147200,formattedLastUpdatedAt:"Mar 7, 2023",frontMatter:{id:"seminar-03",title:"3rd seminar",description:"Select sort implementation on arrays.\n",last_update:{date:"2023-03-07T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Bonuses",permalink:"/pb071/category/bonuses"},next:{title:"4th seminar",permalink:"/pb071/bonuses/seminar-04"}},l={},p=[{value:"Light version (main_light.c)",id:"light-version-main_lightc",level:2},{value:"Full fat version (main.c)",id:"full-fat-version-mainc",level:2},{value:"Submitting",id:"submitting",level:2}],m={toc:p},u="wrapper";function c(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,a.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Deadline for the submission of the bonus is ",(0,o.kt)("strong",{parentName:"p"},"March 16th 24:00"),".")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"In case you have any questions, feel free to reach out either by email, Discord\nor just by submitting an issue ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/xfocko/kb/-/issues/new"},"here"),".")),(0,o.kt)("p",null,"This assignment has two versions. For the light version you can get 1.5 K\u20a1. For\nthe ",(0,o.kt)("em",{parentName:"p"},"full fat")," 3 K\u20a1. ",(0,o.kt)("strong",{parentName:"p"},"You can choose only one of them"),"."),(0,o.kt)("p",null,"To both of them you are given some basic tests. You can also have a look at the\ncode used by the tests and use it to your advantage."),(0,o.kt)("p",null,"Details can be found in the doxygen comments included in the source files."),(0,o.kt)("h2",{id:"light-version-main_lightc"},"Light version (",(0,o.kt)("inlineCode",{parentName:"h2"},"main_light.c"),")"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/03/main_light.c"},"Source")),(0,o.kt)("p",null,"For the light version you have 3 functions to finish:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"swap")," - that swaps two ints passed by pointers."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"maximum")," - that returns index of the biggest ",(0,o.kt)("inlineCode",{parentName:"li"},"int")," in the array."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"select_sort")," - that sorts passed array using Select Sort.")),(0,o.kt)("h2",{id:"full-fat-version-mainc"},"Full fat version (",(0,o.kt)("inlineCode",{parentName:"h2"},"main.c"),")"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/03/main.c"},"Source")),(0,o.kt)("p",null,"For the full fat version you have 4 functions to implement:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"swap")," - that swaps two variables passed by pointers."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"maximum")," - that returns index of the biggest element in the array using the\ncomparator."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"select_sort")," - that sorts passed array using Select Sort."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"int_comparator")," - that is used for generic sort and maximum")),(0,o.kt)("p",null,"To 2nd and 3rd function you are given a pseudocode that you can use to implement\nit."),(0,o.kt)("admonition",{title:"Function pointers",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"In the skeleton of the \u201cfull fat\u201d version you might have noticed a weird type\nsignature of both the ",(0,o.kt)("inlineCode",{parentName:"p"},"maximum")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"select_sort")," functions. Those functions get\npassed a ",(0,o.kt)("em",{parentName:"p"},"function pointer")," to the comparator that you use for comparing the\nrespective elements in the passed in array."),(0,o.kt)("p",{parentName:"admonition"},"If we take the parameter from one of the functions from the skeleton:"),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre",className:"language-c"},"int (*comp)(const void *, const void *)\n")),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"comp")," is a function pointer to a function that takes two pointers of unspecified\ntype, i.e. pure address to the memory (you don't know what stored in there), and\nreturns an ",(0,o.kt)("inlineCode",{parentName:"p"},"int"),"."),(0,o.kt)("p",{parentName:"admonition"},"You can pass the function by simply using its name. (There is no need to use ",(0,o.kt)("inlineCode",{parentName:"p"},"&"),"\nto get its address.) And you can also call the function by \u201ccalling\u201d the function\npointer, e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},"comp(left, right)"),".")),(0,o.kt)("h2",{id:"submitting"},"Submitting"),(0,o.kt)("p",null,"For submitting the bonus assignment you can follow the same procedure as for\nsubmitting the homeworks, that is:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"On branch ",(0,o.kt)("inlineCode",{parentName:"li"},"main")," add the provided skeleton."),(0,o.kt)("li",{parentName:"ol"},"Checkout new branch ",(0,o.kt)("inlineCode",{parentName:"li"},"seminar-bonus-03"),"."),(0,o.kt)("li",{parentName:"ol"},"Add your solution to the newly created branch."),(0,o.kt)("li",{parentName:"ol"},"Create a MR to the ",(0,o.kt)("inlineCode",{parentName:"li"},"main")," branch with me (",(0,o.kt)("inlineCode",{parentName:"li"},"@xfocko"),") as the reviewer.")),(0,o.kt)("admonition",{title:"Directory structure for bonuses",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Ideally create a directory ",(0,o.kt)("inlineCode",{parentName:"p"},"seminar-bonuses")," in the root of your repository with\nbonuses in their own subdirectories."),(0,o.kt)("p",{parentName:"admonition"},"Structure of your repository can look like this:"),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre"},".\n\u251c\u2500\u2500 bonuses\n\u2502 \u2514\u2500\u2500 seminar-03\n\u251c\u2500\u2500 hello\n\u251c\u2500\u2500 hw01\n\u251c\u2500\u2500 hw02\n\u251c\u2500\u2500 seminar-01\n\u251c\u2500\u2500 seminar-02\n\u2514\u2500\u2500 seminar-03\n")),(0,o.kt)("p",{parentName:"admonition"},"or"),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre"},".\n\u251c\u2500\u2500 bonus-seminar-03\n\u251c\u2500\u2500 hello\n\u251c\u2500\u2500 hw01\n\u251c\u2500\u2500 hw02\n\u251c\u2500\u2500 seminar-01\n\u251c\u2500\u2500 seminar-02\n\u2514\u2500\u2500 seminar-03\n")),(0,o.kt)("p",{parentName:"admonition"},"Structure of the bonuses is entirely up to you, just keep it consistent.")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[8769],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>h});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},m=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=o,h=u["".concat(l,".").concat(d)]||u[d]||c[d]||i;return n?a.createElement(h,r(r({ref:t},m),{},{components:n})):a.createElement(h,r({ref:t},m))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:o,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={id:"seminar-03",title:"3rd seminar",description:"Select sort implementation on arrays.\n",last_update:{date:new Date("2023-03-07T00:00:00.000Z")}},r=void 0,s={unversionedId:"bonuses/seminar-03",id:"bonuses/seminar-03",title:"3rd seminar",description:"Select sort implementation on arrays.\n",source:"@site/pb071/bonuses/03.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-03",permalink:"/pb071/bonuses/seminar-03",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/bonuses/03.md",tags:[],version:"current",lastUpdatedAt:1678147200,formattedLastUpdatedAt:"Mar 7, 2023",frontMatter:{id:"seminar-03",title:"3rd seminar",description:"Select sort implementation on arrays.\n",last_update:{date:"2023-03-07T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Bonuses",permalink:"/pb071/category/bonuses"},next:{title:"4th seminar",permalink:"/pb071/bonuses/seminar-04"}},l={},p=[{value:"Light version (main_light.c)",id:"light-version-main_lightc",level:2},{value:"Full fat version (main.c)",id:"full-fat-version-mainc",level:2},{value:"Submitting",id:"submitting",level:2}],m={toc:p},u="wrapper";function c(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,a.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Deadline for the submission of the bonus is ",(0,o.kt)("strong",{parentName:"p"},"March 16th 24:00"),".")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"In case you have any questions, feel free to reach out either by email, Discord\nor just by submitting an issue ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/xfocko/kb/-/issues/new"},"here"),".")),(0,o.kt)("p",null,"This assignment has two versions. For the light version you can get 1.5 K\u20a1. For\nthe ",(0,o.kt)("em",{parentName:"p"},"full fat")," 3 K\u20a1. ",(0,o.kt)("strong",{parentName:"p"},"You can choose only one of them"),"."),(0,o.kt)("p",null,"To both of them you are given some basic tests. You can also have a look at the\ncode used by the tests and use it to your advantage."),(0,o.kt)("p",null,"Details can be found in the doxygen comments included in the source files."),(0,o.kt)("h2",{id:"light-version-main_lightc"},"Light version (",(0,o.kt)("inlineCode",{parentName:"h2"},"main_light.c"),")"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/03/main_light.c"},"Source")),(0,o.kt)("p",null,"For the light version you have 3 functions to finish:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"swap")," - that swaps two ints passed by pointers."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"maximum")," - that returns index of the biggest ",(0,o.kt)("inlineCode",{parentName:"li"},"int")," in the array."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"select_sort")," - that sorts passed array using Select Sort.")),(0,o.kt)("h2",{id:"full-fat-version-mainc"},"Full fat version (",(0,o.kt)("inlineCode",{parentName:"h2"},"main.c"),")"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/03/main.c"},"Source")),(0,o.kt)("p",null,"For the full fat version you have 4 functions to implement:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"swap")," - that swaps two variables passed by pointers."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"maximum")," - that returns index of the biggest element in the array using the\ncomparator."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"select_sort")," - that sorts passed array using Select Sort."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"int_comparator")," - that is used for generic sort and maximum")),(0,o.kt)("p",null,"To 2nd and 3rd function you are given a pseudocode that you can use to implement\nit."),(0,o.kt)("admonition",{title:"Function pointers",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"In the skeleton of the \u201cfull fat\u201d version you might have noticed a weird type\nsignature of both the ",(0,o.kt)("inlineCode",{parentName:"p"},"maximum")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"select_sort")," functions. Those functions get\npassed a ",(0,o.kt)("em",{parentName:"p"},"function pointer")," to the comparator that you use for comparing the\nrespective elements in the passed in array."),(0,o.kt)("p",{parentName:"admonition"},"If we take the parameter from one of the functions from the skeleton:"),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre",className:"language-c"},"int (*comp)(const void *, const void *)\n")),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"comp")," is a function pointer to a function that takes two pointers of unspecified\ntype, i.e. pure address to the memory (you don't know what stored in there), and\nreturns an ",(0,o.kt)("inlineCode",{parentName:"p"},"int"),"."),(0,o.kt)("p",{parentName:"admonition"},"You can pass the function by simply using its name. (There is no need to use ",(0,o.kt)("inlineCode",{parentName:"p"},"&"),"\nto get its address.) And you can also call the function by \u201ccalling\u201d the function\npointer, e.g. ",(0,o.kt)("inlineCode",{parentName:"p"},"comp(left, right)"),".")),(0,o.kt)("h2",{id:"submitting"},"Submitting"),(0,o.kt)("p",null,"For submitting the bonus assignment you can follow the same procedure as for\nsubmitting the homeworks, that is:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"On branch ",(0,o.kt)("inlineCode",{parentName:"li"},"main")," add the provided skeleton."),(0,o.kt)("li",{parentName:"ol"},"Checkout new branch ",(0,o.kt)("inlineCode",{parentName:"li"},"seminar-bonus-03"),"."),(0,o.kt)("li",{parentName:"ol"},"Add your solution to the newly created branch."),(0,o.kt)("li",{parentName:"ol"},"Create a MR to the ",(0,o.kt)("inlineCode",{parentName:"li"},"main")," branch with me (",(0,o.kt)("inlineCode",{parentName:"li"},"@xfocko"),") as the reviewer.")),(0,o.kt)("admonition",{title:"Directory structure for bonuses",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Ideally create a directory ",(0,o.kt)("inlineCode",{parentName:"p"},"seminar-bonuses")," in the root of your repository with\nbonuses in their own subdirectories."),(0,o.kt)("p",{parentName:"admonition"},"Structure of your repository can look like this:"),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre"},".\n\u251c\u2500\u2500 bonuses\n\u2502 \u2514\u2500\u2500 seminar-03\n\u251c\u2500\u2500 hello\n\u251c\u2500\u2500 hw01\n\u251c\u2500\u2500 hw02\n\u251c\u2500\u2500 seminar-01\n\u251c\u2500\u2500 seminar-02\n\u2514\u2500\u2500 seminar-03\n")),(0,o.kt)("p",{parentName:"admonition"},"or"),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre"},".\n\u251c\u2500\u2500 bonus-seminar-03\n\u251c\u2500\u2500 hello\n\u251c\u2500\u2500 hw01\n\u251c\u2500\u2500 hw02\n\u251c\u2500\u2500 seminar-01\n\u251c\u2500\u2500 seminar-02\n\u2514\u2500\u2500 seminar-03\n")),(0,o.kt)("p",{parentName:"admonition"},"Structure of the bonuses is entirely up to you, just keep it consistent.")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/95f41f0b.79e14732.js b/assets/js/95f41f0b.6fe751ba.js similarity index 98% rename from assets/js/95f41f0b.79e14732.js rename to assets/js/95f41f0b.6fe751ba.js index 88c5eac..952b9b4 100644 --- a/assets/js/95f41f0b.79e14732.js +++ b/assets/js/95f41f0b.6fe751ba.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9385],{3905:(e,t,r)=>{r.d(t,{Zo:()=>f,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},f=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,f=c(e,["components","mdxType","originalType","parentName"]),u=s(r),d=o,m=u["".concat(l,".").concat(d)]||u[d]||p[d]||a;return r?n.createElement(m,i(i({ref:t},f),{},{components:r})):n.createElement(m,i({ref:t},f))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15",slug:"aoc-2022/1st-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/1st-week",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/01-week-1.md",source:"@site/blog/aoc-2022/01-week-1.md",title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15:00.000Z",formattedDate:"December 15, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:12.4,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15",slug:"aoc-2022/1st-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"2nd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/2nd-week"},nextItem:{title:"Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/intro"}},l={authorsImageUrls:[void 0]},s=[],f={toc:s},u="wrapper";function p(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the first week of ","[",(0,o.kt)("em",{parentName:"p"},"Advent of Code"),"]"," in Rust."))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9385],{3905:(e,t,r)=>{r.d(t,{Zo:()=>f,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},f=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,f=c(e,["components","mdxType","originalType","parentName"]),u=s(r),d=o,m=u["".concat(l,".").concat(d)]||u[d]||p[d]||a;return r?n.createElement(m,i(i({ref:t},f),{},{components:r})):n.createElement(m,i({ref:t},f))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(7462),o=(r(7294),r(3905));const a={title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15",slug:"aoc-2022/1st-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/1st-week",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/01-week-1.md",source:"@site/blog/aoc-2022/01-week-1.md",title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15:00.000Z",formattedDate:"December 15, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:12.4,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15",slug:"aoc-2022/1st-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"2nd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/2nd-week"},nextItem:{title:"Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/intro"}},l={authorsImageUrls:[void 0]},s=[],f={toc:s},u="wrapper";function p(e){let{components:t,...r}=e;return(0,o.kt)(u,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the first week of ","[",(0,o.kt)("em",{parentName:"p"},"Advent of Code"),"]"," in Rust."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9eb50c57.bc586b34.js b/assets/js/9eb50c57.23f36b2e.js similarity index 97% rename from assets/js/9eb50c57.bc586b34.js rename to assets/js/9eb50c57.23f36b2e.js index 9b31e59..dd34a39 100644 --- a/assets/js/9eb50c57.bc586b34.js +++ b/assets/js/9eb50c57.23f36b2e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7509],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var i=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=i.createContext({}),p=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=p(e.components);return i.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=p(n),d=o,h=m["".concat(l,".").concat(d)]||m[d]||u[d]||a;return n?i.createElement(h,r(r({ref:t},c),{},{components:n})):i.createElement(h,r({ref:t},c))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,r=new Array(a);r[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:o,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var i=n(7462),o=(n(7294),n(3905));const a={id:"postcondition-ambiguity",title:"Vague postconditions and proving correctness of algorithms",description:"Debugging and testing with precise postconditions.\n",tags:["python","testing","postconditions","sorting"],last_update:{date:new Date("2021-03-18T00:00:00.000Z")}},r=void 0,s={unversionedId:"algorithms-correctness/postcondition-ambiguity",id:"algorithms-correctness/postcondition-ambiguity",title:"Vague postconditions and proving correctness of algorithms",description:"Debugging and testing with precise postconditions.\n",source:"@site/ib002/02-algorithms-correctness/2021-03-18-postcondition-ambiguity.md",sourceDirName:"02-algorithms-correctness",slug:"/algorithms-correctness/postcondition-ambiguity",permalink:"/ib002/algorithms-correctness/postcondition-ambiguity",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/02-algorithms-correctness/2021-03-18-postcondition-ambiguity.md",tags:[{label:"python",permalink:"/ib002/tags/python"},{label:"testing",permalink:"/ib002/tags/testing"},{label:"postconditions",permalink:"/ib002/tags/postconditions"},{label:"sorting",permalink:"/ib002/tags/sorting"}],version:"current",lastUpdatedAt:1616025600,formattedLastUpdatedAt:"Mar 18, 2021",frontMatter:{id:"postcondition-ambiguity",title:"Vague postconditions and proving correctness of algorithms",description:"Debugging and testing with precise postconditions.\n",tags:["python","testing","postconditions","sorting"],last_update:{date:"2021-03-18T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Algorithms and Correctness",permalink:"/ib002/category/algorithms-and-correctness"},next:{title:"Asymptotic Notation and Time Complexity",permalink:"/ib002/category/asymptotic-notation-and-time-complexity"}},l={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Implementation of select sort from the exercises",id:"implementation-of-select-sort-from-the-exercises",level:2},{value:"Discussed preconditions, loop invariants and postconditions",id:"discussed-preconditions-loop-invariants-and-postconditions",level:2},{value:"Precondition",id:"precondition",level:3},{value:"Loop invariant",id:"loop-invariant",level:3},{value:"Postcondition",id:"postcondition",level:3},{value:"So is the permutation really required?",id:"so-is-the-permutation-really-required",level:2},{value:"Implementation of the broken select sort",id:"implementation-of-the-broken-select-sort",level:2},{value:"Property-based tests for our sorts",id:"property-based-tests-for-our-sorts",level:2},{value:"Loop invariant",id:"loop-invariant-1",level:3},{value:"Postcondition(s)",id:"postconditions",level:3},{value:"Putting it together",id:"putting-it-together",level:3},{value:"Let's run the tests!",id:"lets-run-the-tests",level:3},{value:"Summary",id:"summary",level:2}],c={toc:p},m="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,i.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"introduction"},"Introduction"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"pathname:///files/ib002/algorithms-correctness/postcondition-ambiguity/test_sort.py"},"Source code")," used later on."),(0,o.kt)("h2",{id:"implementation-of-select-sort-from-the-exercises"},"Implementation of select sort from the exercises"),(0,o.kt)("p",null,"To implement select sort from the exercises and make it as easy to read as possible, I have implemented maximum function that returns index of the biggest element from the first ",(0,o.kt)("span",{parentName:"p",className:"math math-inline"},(0,o.kt)("span",{parentName:"span",className:"katex"},(0,o.kt)("span",{parentName:"span",className:"katex-mathml"},(0,o.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,o.kt)("semantics",{parentName:"math"},(0,o.kt)("mrow",{parentName:"semantics"},(0,o.kt)("mi",{parentName:"mrow"},"n")),(0,o.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,o.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,o.kt)("span",{parentName:"span",className:"base"},(0,o.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,o.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," elements."),(0,o.kt)("p",null,"For the sake of time and memory complexity, I am also using ",(0,o.kt)("inlineCode",{parentName:"p"},"itertools.islice"),", which makes a slice, but does not copy the elements into the memory like normal slice does."),(0,o.kt)("p",null,"There is also a ",(0,o.kt)("inlineCode",{parentName:"p"},"check_loop_invariant")," function that will be described later."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def compare_by_value(pair):\n index, value = pair\n return value\n\n\ndef maximum(arr, n):\n first_n_elements = itertools.islice(enumerate(arr), n)\n index, value = max(first_n_elements, key=compare_by_value)\n return index\n\n\ndef select_sort(arr, n):\n assert n == len(arr)\n\n check_loop_invariant(arr, n, n)\n for i in reversed(range(1, n)):\n j = maximum(arr, i + 1)\n arr[i], arr[j] = arr[j], arr[i]\n\n check_loop_invariant(arr, n, i)\n\n return arr\n")),(0,o.kt)("h2",{id:"discussed-preconditions-loop-invariants-and-postconditions"},"Discussed preconditions, loop invariants and postconditions"),(0,o.kt)("p",null,"You can safely replace ",(0,o.kt)("inlineCode",{parentName:"p"},"A")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"arr")," or array for list."),(0,o.kt)("h3",{id:"precondition"},"Precondition"),(0,o.kt)("p",null,"As a precondition we have established that ",(0,o.kt)("inlineCode",{parentName:"p"},"A")," represents an array of values and ",(0,o.kt)("span",{parentName:"p",className:"math math-inline"},(0,o.kt)("span",{parentName:"span",className:"katex"},(0,o.kt)("span",{parentName:"span",className:"katex-mathml"},(0,o.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,o.kt)("semantics",{parentName:"math"},(0,o.kt)("mrow",{parentName:"semantics"},(0,o.kt)("mi",{parentName:"mrow"},"n")),(0,o.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,o.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,o.kt)("span",{parentName:"span",className:"base"},(0,o.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,o.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," is length of the ",(0,o.kt)("inlineCode",{parentName:"p"},"A"),"."),(0,o.kt)("h3",{id:"loop-invariant"},"Loop invariant"),(0,o.kt)("p",null,"As for loop invariant we have established that we require two properties:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"A[i + 1 : n]")," is sorted"),(0,o.kt)("li",{parentName:"ol"},"all elements of ",(0,o.kt)("inlineCode",{parentName:"li"},"A[i + 1 : n]")," are bigger or equal to the other elements")),(0,o.kt)("p",null,"This invariant is later defined as ",(0,o.kt)("inlineCode",{parentName:"p"},"check_loop_invariant")," function. It is checked before the first iteration and after each iteration."),(0,o.kt)("h3",{id:"postcondition"},"Postcondition"),(0,o.kt)("p",null,"For the postcondition the first suggestion was that ",(0,o.kt)("inlineCode",{parentName:"p"},"A")," must be sorted. And later we have added that ",(0,o.kt)("inlineCode",{parentName:"p"},"A'")," must be a permutation of ",(0,o.kt)("inlineCode",{parentName:"p"},"A"),"."),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"However at the end of the session question arose if it is really required to state in the postcondition that ",(0,o.kt)("inlineCode",{parentName:"p"},"A'")," is a permutation.")),(0,o.kt)("h2",{id:"so-is-the-permutation-really-required"},"So is the permutation really required?"),(0,o.kt)("p",null,"As I have said it is better to have postconditions explicit and do not expect anything that is not stated explicitly, e.g. ",(0,o.kt)("em",{parentName:"p"},"name suggests it"),". In reality we could consider it as a smaller mistake (but it has consequences)."),(0,o.kt)("p",null,"On the other hand explicit postconditions can be used to our advantage ",(0,o.kt)("strong",{parentName:"p"},"and also")," help our proof of correctness."),(0,o.kt)("p",null,"Consequences:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Property-based testing"),(0,o.kt)("p",{parentName:"li"},"If we have explicit postconditions we can use them to define properties of the output from our algorithms. That way we can use property-based testing, which does not depend on specific inputs and expected outputs, but rather on randomly generated input and checking if the output conforms to our expectations (the postconditions are fulfilled).")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Proof of correctness"),(0,o.kt)("p",{parentName:"li"},"If we can prove that algorithm is correct even for algorithm that ",(0,o.kt)("strong",{parentName:"p"},"is not")," correct, we have a problem. That proof has no value and is useless."))),(0,o.kt)("p",null,'For the sake of showcasing the power of postconditions I will introduce "select sort" that is not correct, but will comply with both the loop invariant and our vague postcondition and thus pass the tests.'),(0,o.kt)("h2",{id:"implementation-of-the-broken-select-sort"},"Implementation of the broken select sort"),(0,o.kt)("p",null,"To make sure this thing passes everything, but our explicit postcondition with permutation will ",(0,o.kt)("em",{parentName:"p"},"blow it up"),', I have designed this "select sort" as follows:'),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"If I get empty list, there is nothing to do."),(0,o.kt)("li",{parentName:"ol"},"I find maximum in the array."),(0,o.kt)("li",{parentName:"ol"},"For each index from the end, I will assign ",(0,o.kt)("inlineCode",{parentName:"li"},"maximum + index"),".\nThis will ensure that even if the maximum in the original array was the first element, I will always satisfy that 2nd part of the loop invariant.")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def broken_select_sort(arr, n):\n assert n == len(arr)\n\n if not arr:\n return\n\n max_value = max(arr)\n\n check_loop_invariant(arr, n, n)\n for i in reversed(range(n)):\n arr[i] = max_value + i\n\n check_loop_invariant(arr, n, i)\n\n return arr\n")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"There is also an easier way to break this, I leave that as an exercise ;)")),(0,o.kt)("h2",{id:"property-based-tests-for-our-sorts"},"Property-based tests for our sorts"),(0,o.kt)("p",null,"Since we have talked a lot about proofs at the seminar, I would like to demonstrate it on the testing of the sorts. In the following text I will cover implementation of the loop invariant and both postconditions we have talked about and then test our sorts using them."),(0,o.kt)("h3",{id:"loop-invariant-1"},"Loop invariant"),(0,o.kt)("p",null,"To check loop invariant I have implemented this function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},'def check_loop_invariant(arr, n, i):\n # A[i + 1 : n] is sorted\n for x, y in zip(itertools.islice(arr, i + 1, n), itertools.islice(arr, i + 2, n)):\n assert x <= y\n\n # all elements of A[i + 1 : n] are bigger or equal to the other elements\n if i + 1 >= n:\n # in case there are no elements\n return\n\n # otherwise, since the "tail" is sorted, we can assume that it is enough to\n # check the other elements to the smallest value of the tail\n smallest = arr[i + 1]\n for element in itertools.islice(arr, i + 1):\n assert smallest >= element\n')),(0,o.kt)("p",null,'First part checks if the "ending" of the array is sorted.'),(0,o.kt)("p",null,"In second part I have used a ",(0,o.kt)("em",{parentName:"p"},"dirty trick")," of taking just the first element that is the smallest and compared the rest of the elements to it. Why is it enough? I leave it as an exercise ;)"),(0,o.kt)("h3",{id:"postconditions"},"Postcondition(s)"),(0,o.kt)("p",null,"I have defined both the vague and explicit postconditions:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def check_vague_postcondition(original_arr, arr):\n if not arr:\n return\n\n # check ordering\n for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):\n assert x <= y\n\n\ndef check_postcondition(original_arr, arr):\n if not arr:\n return\n\n # check ordering\n for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):\n assert x <= y\n\n # get counts from original list\n original_counts = {}\n for value in original_arr:\n original_counts[value] = 1 + original_counts.get(value, 0)\n\n # get counts from resulting list\n counts = {}\n for value in arr:\n counts[value] = 1 + counts.get(value, 0)\n\n # if arr is permutation of original_arr then all counts must be the same\n assert counts == original_counts\n")),(0,o.kt)("h3",{id:"putting-it-together"},"Putting it together"),(0,o.kt)("p",null,"Now that we have everything implement, we can move on to the implementation of the tests:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},'from hypothesis import given, settings\nfrom hypothesis.strategies import integers, lists\nimport pytest\n\n@given(lists(integers()))\n@settings(max_examples=1000)\n@pytest.mark.parametrize(\n "postcondition", [check_vague_postcondition, check_postcondition]\n)\n@pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])\ndef test_select_sort(sorting_function, postcondition, numbers):\n result = sorting_function(numbers[:], len(numbers))\n postcondition(numbers, result)\n')),(0,o.kt)("p",null,"Since it might seem a bit scary, I will disect it by parts."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Parameters of test function"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def test_select_sort(sorting_function, postcondition, numbers):\n")),(0,o.kt)("p",{parentName:"li"},"We are given 3 parameters:"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"sorting_function")," - as the name suggests is the sorting function we test"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"postcondition")," - as the name suggests is the postcondition that we check"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"numbers")," - is random list of numbers that we will be sorting"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Body of the test"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"result = sorting_function(numbers[:], len(numbers))\npostcondition(numbers, result)\n")),(0,o.kt)("p",{parentName:"li"},"We pass to the sorting function ",(0,o.kt)("strong",{parentName:"p"},"copy")," of the numbers we got, this ensures that once we are checking the more strict postcondition, we can gather the necessary information even after sorting the list in-situ, i.e. we can check if the ",(0,o.kt)("inlineCode",{parentName:"p"},"result")," is really a ",(0,o.kt)("inlineCode",{parentName:"p"},"permutation")," of the ",(0,o.kt)("inlineCode",{parentName:"p"},"numbers")," even though the sorting functions has modified the passed in list."))),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Now we get to the more complicated part and it is the ",(0,o.kt)("em",{parentName:"p"},"decorators"),".")),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"1st ",(0,o.kt)("inlineCode",{parentName:"p"},"parametrize")," from the bottom"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},'@pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])\n')),(0,o.kt)("p",{parentName:"li"},"This tells pytest, that we want to pass the values from the list to the parameter ",(0,o.kt)("inlineCode",{parentName:"p"},"sorting_function"),". In other words, this lets us use the same test function for both the correct and incorrect select sort.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"2nd ",(0,o.kt)("inlineCode",{parentName:"p"},"parametrize")," from the bottom is similar, but works with the postcondition.\nThe reason why they are separated is pretty simple, this way they act like cartesian product: for each sorting function we also use each postcondition.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"@settings")," raises the count of tests that hypothesis runs (from default of 100(?)).")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"@given(lists(integers()))"),"\nThis means hypothesis is randomly creating lists of integers and passing them to the function, which has only one parameter left and that is ",(0,o.kt)("inlineCode",{parentName:"p"},"numbers"),"."))),(0,o.kt)("h3",{id:"lets-run-the-tests"},"Let's run the tests!"),(0,o.kt)("p",null,"In case you want to experiment locally, you should install ",(0,o.kt)("inlineCode",{parentName:"p"},"pytest")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"hypothesis")," from the PyPI."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'% pytest -v test_sort.py\n=================================== test session starts ====================================\nplatform linux -- Python 3.6.8, pytest-3.8.2, py-1.7.0, pluggy-0.13.1 -- /usr/bin/python3\ncachedir: .pytest_cache\nrootdir: /home/xfocko/git/xfocko/ib002/postcondition-ambiguity, inifile:\nplugins: hypothesis-5.16.1\ncollected 4 items\n\ntest_sort.py::test_select_sort[select_sort-check_vague_postcondition] PASSED [ 25%]\ntest_sort.py::test_select_sort[select_sort-check_postcondition] PASSED [ 50%]\ntest_sort.py::test_select_sort[broken_select_sort-check_vague_postcondition] PASSED [ 75%]\ntest_sort.py::test_select_sort[broken_select_sort-check_postcondition] FAILED [100%]\n\n========================================= FAILURES =========================================\n_________________ test_select_sort[broken_select_sort-check_postcondition] _________________\n\nsorting_function = \npostcondition = \n\n @given(lists(integers()))\n> @settings(max_examples=1000)\n @pytest.mark.parametrize(\n "postcondition", [check_vague_postcondition, check_postcondition]\n )\n @pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])\n def test_select_sort(sorting_function, postcondition, numbers):\n\ntest_sort.py:132:\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\ntest_sort.py:139: in test_select_sort\n postcondition(numbers, result)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\noriginal_arr = [0, 0], arr = [0, 1]\n\n def check_postcondition(original_arr, arr):\n if not arr:\n return\n\n # check ordering\n for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):\n assert x <= y\n\n # get counts from original list\n original_counts = {}\n for value in original_arr:\n original_counts[value] = 1 + original_counts.get(value, 0)\n\n # get counts from resulting list\n counts = {}\n for value in arr:\n counts[value] = 1 + counts.get(value, 0)\n\n # if arr is permutation of original_arr then all counts must be the same\n> assert counts == original_counts\nE assert {0: 1, 1: 1} == {0: 2}\nE Differing items:\nE {0: 1} != {0: 2}\nE Left contains more items:\nE {1: 1}\nE Full diff:\nE - {0: 1, 1: 1}\nE + {0: 2}\n\ntest_sort.py:128: AssertionError\n----------------------------------- Captured stdout call -----------------------------------\nFalsifying example: test_select_sort(\n sorting_function=,\n postcondition=,\n numbers=[0, 0],\n)\n============================ 1 failed, 3 passed in 6.84 seconds ============================\n')),(0,o.kt)("p",null,"We can clearly see that our broken select sort has passed the ",(0,o.kt)("em",{parentName:"p"},"vague postcondition"),", but the explicit one was not satisfied."),(0,o.kt)("h2",{id:"summary"},"Summary"),(0,o.kt)("p",null,"For proving the correctness of the algorithm it is better to be explicit than prove that algorithm is correct even though it is not. Being explicit also allows you to test smaller ",(0,o.kt)("em",{parentName:"p"},"chunks")," of code better."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7509],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>d});var i=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=i.createContext({}),p=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=p(e.components);return i.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=p(n),h=o,d=m["".concat(l,".").concat(h)]||m[h]||u[h]||a;return n?i.createElement(d,r(r({ref:t},c),{},{components:n})):i.createElement(d,r({ref:t},c))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,r=new Array(a);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:o,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>p});var i=n(7462),o=(n(7294),n(3905));const a={id:"postcondition-ambiguity",title:"Vague postconditions and proving correctness of algorithms",description:"Debugging and testing with precise postconditions.\n",tags:["python","testing","postconditions","sorting"],last_update:{date:new Date("2021-03-18T00:00:00.000Z")}},r=void 0,s={unversionedId:"algorithms-correctness/postcondition-ambiguity",id:"algorithms-correctness/postcondition-ambiguity",title:"Vague postconditions and proving correctness of algorithms",description:"Debugging and testing with precise postconditions.\n",source:"@site/ib002/02-algorithms-correctness/2021-03-18-postcondition-ambiguity.md",sourceDirName:"02-algorithms-correctness",slug:"/algorithms-correctness/postcondition-ambiguity",permalink:"/ib002/algorithms-correctness/postcondition-ambiguity",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/02-algorithms-correctness/2021-03-18-postcondition-ambiguity.md",tags:[{label:"python",permalink:"/ib002/tags/python"},{label:"testing",permalink:"/ib002/tags/testing"},{label:"postconditions",permalink:"/ib002/tags/postconditions"},{label:"sorting",permalink:"/ib002/tags/sorting"}],version:"current",lastUpdatedAt:1616025600,formattedLastUpdatedAt:"Mar 18, 2021",frontMatter:{id:"postcondition-ambiguity",title:"Vague postconditions and proving correctness of algorithms",description:"Debugging and testing with precise postconditions.\n",tags:["python","testing","postconditions","sorting"],last_update:{date:"2021-03-18T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Algorithms and Correctness",permalink:"/ib002/category/algorithms-and-correctness"},next:{title:"Asymptotic Notation and Time Complexity",permalink:"/ib002/category/asymptotic-notation-and-time-complexity"}},l={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Implementation of select sort from the exercises",id:"implementation-of-select-sort-from-the-exercises",level:2},{value:"Discussed preconditions, loop invariants and postconditions",id:"discussed-preconditions-loop-invariants-and-postconditions",level:2},{value:"Precondition",id:"precondition",level:3},{value:"Loop invariant",id:"loop-invariant",level:3},{value:"Postcondition",id:"postcondition",level:3},{value:"So is the permutation really required?",id:"so-is-the-permutation-really-required",level:2},{value:"Implementation of the broken select sort",id:"implementation-of-the-broken-select-sort",level:2},{value:"Property-based tests for our sorts",id:"property-based-tests-for-our-sorts",level:2},{value:"Loop invariant",id:"loop-invariant-1",level:3},{value:"Postcondition(s)",id:"postconditions",level:3},{value:"Putting it together",id:"putting-it-together",level:3},{value:"Let's run the tests!",id:"lets-run-the-tests",level:3},{value:"Summary",id:"summary",level:2}],c={toc:p},m="wrapper";function u(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,i.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"introduction"},"Introduction"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"pathname:///files/ib002/algorithms-correctness/postcondition-ambiguity/test_sort.py"},"Source code")," used later on."),(0,o.kt)("h2",{id:"implementation-of-select-sort-from-the-exercises"},"Implementation of select sort from the exercises"),(0,o.kt)("p",null,"To implement select sort from the exercises and make it as easy to read as possible, I have implemented maximum function that returns index of the biggest element from the first ",(0,o.kt)("span",{parentName:"p",className:"math math-inline"},(0,o.kt)("span",{parentName:"span",className:"katex"},(0,o.kt)("span",{parentName:"span",className:"katex-mathml"},(0,o.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,o.kt)("semantics",{parentName:"math"},(0,o.kt)("mrow",{parentName:"semantics"},(0,o.kt)("mi",{parentName:"mrow"},"n")),(0,o.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,o.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,o.kt)("span",{parentName:"span",className:"base"},(0,o.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,o.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," elements."),(0,o.kt)("p",null,"For the sake of time and memory complexity, I am also using ",(0,o.kt)("inlineCode",{parentName:"p"},"itertools.islice"),", which makes a slice, but does not copy the elements into the memory like normal slice does."),(0,o.kt)("p",null,"There is also a ",(0,o.kt)("inlineCode",{parentName:"p"},"check_loop_invariant")," function that will be described later."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def compare_by_value(pair):\n index, value = pair\n return value\n\n\ndef maximum(arr, n):\n first_n_elements = itertools.islice(enumerate(arr), n)\n index, value = max(first_n_elements, key=compare_by_value)\n return index\n\n\ndef select_sort(arr, n):\n assert n == len(arr)\n\n check_loop_invariant(arr, n, n)\n for i in reversed(range(1, n)):\n j = maximum(arr, i + 1)\n arr[i], arr[j] = arr[j], arr[i]\n\n check_loop_invariant(arr, n, i)\n\n return arr\n")),(0,o.kt)("h2",{id:"discussed-preconditions-loop-invariants-and-postconditions"},"Discussed preconditions, loop invariants and postconditions"),(0,o.kt)("p",null,"You can safely replace ",(0,o.kt)("inlineCode",{parentName:"p"},"A")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"arr")," or array for list."),(0,o.kt)("h3",{id:"precondition"},"Precondition"),(0,o.kt)("p",null,"As a precondition we have established that ",(0,o.kt)("inlineCode",{parentName:"p"},"A")," represents an array of values and ",(0,o.kt)("span",{parentName:"p",className:"math math-inline"},(0,o.kt)("span",{parentName:"span",className:"katex"},(0,o.kt)("span",{parentName:"span",className:"katex-mathml"},(0,o.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,o.kt)("semantics",{parentName:"math"},(0,o.kt)("mrow",{parentName:"semantics"},(0,o.kt)("mi",{parentName:"mrow"},"n")),(0,o.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,o.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,o.kt)("span",{parentName:"span",className:"base"},(0,o.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,o.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," is length of the ",(0,o.kt)("inlineCode",{parentName:"p"},"A"),"."),(0,o.kt)("h3",{id:"loop-invariant"},"Loop invariant"),(0,o.kt)("p",null,"As for loop invariant we have established that we require two properties:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"A[i + 1 : n]")," is sorted"),(0,o.kt)("li",{parentName:"ol"},"all elements of ",(0,o.kt)("inlineCode",{parentName:"li"},"A[i + 1 : n]")," are bigger or equal to the other elements")),(0,o.kt)("p",null,"This invariant is later defined as ",(0,o.kt)("inlineCode",{parentName:"p"},"check_loop_invariant")," function. It is checked before the first iteration and after each iteration."),(0,o.kt)("h3",{id:"postcondition"},"Postcondition"),(0,o.kt)("p",null,"For the postcondition the first suggestion was that ",(0,o.kt)("inlineCode",{parentName:"p"},"A")," must be sorted. And later we have added that ",(0,o.kt)("inlineCode",{parentName:"p"},"A'")," must be a permutation of ",(0,o.kt)("inlineCode",{parentName:"p"},"A"),"."),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"However at the end of the session question arose if it is really required to state in the postcondition that ",(0,o.kt)("inlineCode",{parentName:"p"},"A'")," is a permutation.")),(0,o.kt)("h2",{id:"so-is-the-permutation-really-required"},"So is the permutation really required?"),(0,o.kt)("p",null,"As I have said it is better to have postconditions explicit and do not expect anything that is not stated explicitly, e.g. ",(0,o.kt)("em",{parentName:"p"},"name suggests it"),". In reality we could consider it as a smaller mistake (but it has consequences)."),(0,o.kt)("p",null,"On the other hand explicit postconditions can be used to our advantage ",(0,o.kt)("strong",{parentName:"p"},"and also")," help our proof of correctness."),(0,o.kt)("p",null,"Consequences:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Property-based testing"),(0,o.kt)("p",{parentName:"li"},"If we have explicit postconditions we can use them to define properties of the output from our algorithms. That way we can use property-based testing, which does not depend on specific inputs and expected outputs, but rather on randomly generated input and checking if the output conforms to our expectations (the postconditions are fulfilled).")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Proof of correctness"),(0,o.kt)("p",{parentName:"li"},"If we can prove that algorithm is correct even for algorithm that ",(0,o.kt)("strong",{parentName:"p"},"is not")," correct, we have a problem. That proof has no value and is useless."))),(0,o.kt)("p",null,'For the sake of showcasing the power of postconditions I will introduce "select sort" that is not correct, but will comply with both the loop invariant and our vague postcondition and thus pass the tests.'),(0,o.kt)("h2",{id:"implementation-of-the-broken-select-sort"},"Implementation of the broken select sort"),(0,o.kt)("p",null,"To make sure this thing passes everything, but our explicit postcondition with permutation will ",(0,o.kt)("em",{parentName:"p"},"blow it up"),', I have designed this "select sort" as follows:'),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"If I get empty list, there is nothing to do."),(0,o.kt)("li",{parentName:"ol"},"I find maximum in the array."),(0,o.kt)("li",{parentName:"ol"},"For each index from the end, I will assign ",(0,o.kt)("inlineCode",{parentName:"li"},"maximum + index"),".\nThis will ensure that even if the maximum in the original array was the first element, I will always satisfy that 2nd part of the loop invariant.")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def broken_select_sort(arr, n):\n assert n == len(arr)\n\n if not arr:\n return\n\n max_value = max(arr)\n\n check_loop_invariant(arr, n, n)\n for i in reversed(range(n)):\n arr[i] = max_value + i\n\n check_loop_invariant(arr, n, i)\n\n return arr\n")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"There is also an easier way to break this, I leave that as an exercise ;)")),(0,o.kt)("h2",{id:"property-based-tests-for-our-sorts"},"Property-based tests for our sorts"),(0,o.kt)("p",null,"Since we have talked a lot about proofs at the seminar, I would like to demonstrate it on the testing of the sorts. In the following text I will cover implementation of the loop invariant and both postconditions we have talked about and then test our sorts using them."),(0,o.kt)("h3",{id:"loop-invariant-1"},"Loop invariant"),(0,o.kt)("p",null,"To check loop invariant I have implemented this function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},'def check_loop_invariant(arr, n, i):\n # A[i + 1 : n] is sorted\n for x, y in zip(itertools.islice(arr, i + 1, n), itertools.islice(arr, i + 2, n)):\n assert x <= y\n\n # all elements of A[i + 1 : n] are bigger or equal to the other elements\n if i + 1 >= n:\n # in case there are no elements\n return\n\n # otherwise, since the "tail" is sorted, we can assume that it is enough to\n # check the other elements to the smallest value of the tail\n smallest = arr[i + 1]\n for element in itertools.islice(arr, i + 1):\n assert smallest >= element\n')),(0,o.kt)("p",null,'First part checks if the "ending" of the array is sorted.'),(0,o.kt)("p",null,"In second part I have used a ",(0,o.kt)("em",{parentName:"p"},"dirty trick")," of taking just the first element that is the smallest and compared the rest of the elements to it. Why is it enough? I leave it as an exercise ;)"),(0,o.kt)("h3",{id:"postconditions"},"Postcondition(s)"),(0,o.kt)("p",null,"I have defined both the vague and explicit postconditions:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def check_vague_postcondition(original_arr, arr):\n if not arr:\n return\n\n # check ordering\n for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):\n assert x <= y\n\n\ndef check_postcondition(original_arr, arr):\n if not arr:\n return\n\n # check ordering\n for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):\n assert x <= y\n\n # get counts from original list\n original_counts = {}\n for value in original_arr:\n original_counts[value] = 1 + original_counts.get(value, 0)\n\n # get counts from resulting list\n counts = {}\n for value in arr:\n counts[value] = 1 + counts.get(value, 0)\n\n # if arr is permutation of original_arr then all counts must be the same\n assert counts == original_counts\n")),(0,o.kt)("h3",{id:"putting-it-together"},"Putting it together"),(0,o.kt)("p",null,"Now that we have everything implement, we can move on to the implementation of the tests:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},'from hypothesis import given, settings\nfrom hypothesis.strategies import integers, lists\nimport pytest\n\n@given(lists(integers()))\n@settings(max_examples=1000)\n@pytest.mark.parametrize(\n "postcondition", [check_vague_postcondition, check_postcondition]\n)\n@pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])\ndef test_select_sort(sorting_function, postcondition, numbers):\n result = sorting_function(numbers[:], len(numbers))\n postcondition(numbers, result)\n')),(0,o.kt)("p",null,"Since it might seem a bit scary, I will disect it by parts."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Parameters of test function"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"def test_select_sort(sorting_function, postcondition, numbers):\n")),(0,o.kt)("p",{parentName:"li"},"We are given 3 parameters:"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"sorting_function")," - as the name suggests is the sorting function we test"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"postcondition")," - as the name suggests is the postcondition that we check"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"numbers")," - is random list of numbers that we will be sorting"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Body of the test"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},"result = sorting_function(numbers[:], len(numbers))\npostcondition(numbers, result)\n")),(0,o.kt)("p",{parentName:"li"},"We pass to the sorting function ",(0,o.kt)("strong",{parentName:"p"},"copy")," of the numbers we got, this ensures that once we are checking the more strict postcondition, we can gather the necessary information even after sorting the list in-situ, i.e. we can check if the ",(0,o.kt)("inlineCode",{parentName:"p"},"result")," is really a ",(0,o.kt)("inlineCode",{parentName:"p"},"permutation")," of the ",(0,o.kt)("inlineCode",{parentName:"p"},"numbers")," even though the sorting functions has modified the passed in list."))),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Now we get to the more complicated part and it is the ",(0,o.kt)("em",{parentName:"p"},"decorators"),".")),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"1st ",(0,o.kt)("inlineCode",{parentName:"p"},"parametrize")," from the bottom"),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-py",metastring:"showLineNumbers",showLineNumbers:!0},'@pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])\n')),(0,o.kt)("p",{parentName:"li"},"This tells pytest, that we want to pass the values from the list to the parameter ",(0,o.kt)("inlineCode",{parentName:"p"},"sorting_function"),". In other words, this lets us use the same test function for both the correct and incorrect select sort.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"2nd ",(0,o.kt)("inlineCode",{parentName:"p"},"parametrize")," from the bottom is similar, but works with the postcondition.\nThe reason why they are separated is pretty simple, this way they act like cartesian product: for each sorting function we also use each postcondition.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"@settings")," raises the count of tests that hypothesis runs (from default of 100(?)).")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"@given(lists(integers()))"),"\nThis means hypothesis is randomly creating lists of integers and passing them to the function, which has only one parameter left and that is ",(0,o.kt)("inlineCode",{parentName:"p"},"numbers"),"."))),(0,o.kt)("h3",{id:"lets-run-the-tests"},"Let's run the tests!"),(0,o.kt)("p",null,"In case you want to experiment locally, you should install ",(0,o.kt)("inlineCode",{parentName:"p"},"pytest")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"hypothesis")," from the PyPI."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'% pytest -v test_sort.py\n=================================== test session starts ====================================\nplatform linux -- Python 3.6.8, pytest-3.8.2, py-1.7.0, pluggy-0.13.1 -- /usr/bin/python3\ncachedir: .pytest_cache\nrootdir: /home/xfocko/git/xfocko/ib002/postcondition-ambiguity, inifile:\nplugins: hypothesis-5.16.1\ncollected 4 items\n\ntest_sort.py::test_select_sort[select_sort-check_vague_postcondition] PASSED [ 25%]\ntest_sort.py::test_select_sort[select_sort-check_postcondition] PASSED [ 50%]\ntest_sort.py::test_select_sort[broken_select_sort-check_vague_postcondition] PASSED [ 75%]\ntest_sort.py::test_select_sort[broken_select_sort-check_postcondition] FAILED [100%]\n\n========================================= FAILURES =========================================\n_________________ test_select_sort[broken_select_sort-check_postcondition] _________________\n\nsorting_function = \npostcondition = \n\n @given(lists(integers()))\n> @settings(max_examples=1000)\n @pytest.mark.parametrize(\n "postcondition", [check_vague_postcondition, check_postcondition]\n )\n @pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])\n def test_select_sort(sorting_function, postcondition, numbers):\n\ntest_sort.py:132:\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\ntest_sort.py:139: in test_select_sort\n postcondition(numbers, result)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\noriginal_arr = [0, 0], arr = [0, 1]\n\n def check_postcondition(original_arr, arr):\n if not arr:\n return\n\n # check ordering\n for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):\n assert x <= y\n\n # get counts from original list\n original_counts = {}\n for value in original_arr:\n original_counts[value] = 1 + original_counts.get(value, 0)\n\n # get counts from resulting list\n counts = {}\n for value in arr:\n counts[value] = 1 + counts.get(value, 0)\n\n # if arr is permutation of original_arr then all counts must be the same\n> assert counts == original_counts\nE assert {0: 1, 1: 1} == {0: 2}\nE Differing items:\nE {0: 1} != {0: 2}\nE Left contains more items:\nE {1: 1}\nE Full diff:\nE - {0: 1, 1: 1}\nE + {0: 2}\n\ntest_sort.py:128: AssertionError\n----------------------------------- Captured stdout call -----------------------------------\nFalsifying example: test_select_sort(\n sorting_function=,\n postcondition=,\n numbers=[0, 0],\n)\n============================ 1 failed, 3 passed in 6.84 seconds ============================\n')),(0,o.kt)("p",null,"We can clearly see that our broken select sort has passed the ",(0,o.kt)("em",{parentName:"p"},"vague postcondition"),", but the explicit one was not satisfied."),(0,o.kt)("h2",{id:"summary"},"Summary"),(0,o.kt)("p",null,"For proving the correctness of the algorithm it is better to be explicit than prove that algorithm is correct even though it is not. Being explicit also allows you to test smaller ",(0,o.kt)("em",{parentName:"p"},"chunks")," of code better."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a2be6ffb.f8d1346f.js b/assets/js/a2be6ffb.7a939c96.js similarity index 99% rename from assets/js/a2be6ffb.f8d1346f.js rename to assets/js/a2be6ffb.7a939c96.js index 169da96..bf60ea9 100644 --- a/assets/js/a2be6ffb.f8d1346f.js +++ b/assets/js/a2be6ffb.7a939c96.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[4800],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>g});var o=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=o.createContext({}),p=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=p(e.components);return o.createElement(s.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),m=p(n),d=i,g=m["".concat(s,".").concat(d)]||m[d]||u[d]||a;return n?o.createElement(g,r(r({ref:t},c),{},{components:n})):o.createElement(g,r({ref:t},c))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,r=new Array(a);r[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:i,r[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var o=n(7462),i=(n(7294),n(3905));const a={title:"Environment",description:"Suggestions for setting up a local environment for C++ course.\n",last_update:{date:new Date("2023-02-18T00:00:00.000Z")}},r=void 0,l={unversionedId:"environment",id:"environment",title:"Environment",description:"Suggestions for setting up a local environment for C++ course.\n",source:"@site/pb161/environment.md",sourceDirName:".",slug:"/environment",permalink:"/pb161/environment",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb161/environment.md",tags:[],version:"current",lastUpdatedAt:1676678400,formattedLastUpdatedAt:"Feb 18, 2023",frontMatter:{title:"Environment",description:"Suggestions for setting up a local environment for C++ course.\n",last_update:{date:"2023-02-18T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Introduction",permalink:"/pb161/"}},s={},p=[{value:"Required tools per OS",id:"required-tools-per-os",level:2},{value:"Windows",id:"windows",level:3},{value:"Linux",id:"linux",level:3},{value:"macOS",id:"macos",level:3},{value:"nix(OS)",id:"nixos",level:3},{value:"IDEs",id:"ides",level:2},{value:"git",id:"git",level:2},{value:"pre-commit (link)",id:"pre-commit-link",level:3},{value:"Testing",id:"testing",level:2},{value:"catch2",id:"catch2",level:3},{value:"Google Test",id:"google-test",level:3}],c={toc:p},m="wrapper";function u(e){let{components:t,...n}=e;return(0,i.kt)(m,(0,o.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"required-tools-per-os"},"Required tools per OS"),(0,i.kt)("h3",{id:"windows"},"Windows"),(0,i.kt)("p",null,"Most likely WSL, VM or VPS. If you consider setting up either of those PITA, then\nVSCode + SSH to ",(0,i.kt)("em",{parentName:"p"},"aisa")," might be the best option for you."),(0,i.kt)("admonition",{title:"VSCode @ aisa",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Be careful when using VSCode on aisa, most notably:"),(0,i.kt)("ol",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ol"},"VSCode can leave lingering processes running in the background that can \u201eeat\nup\u201c your quota for running processes.\nAFAIK UNIX team has implemented some periodic clean up of those."),(0,i.kt)("li",{parentName:"ol"},"Disk quota can be also affected, because of the C/C++ extension toolkit that\nhas a cache for IntelliSense."))),(0,i.kt)("p",null,"Either of those will be linux distros, so jump to ",(0,i.kt)("a",{parentName:"p",href:"#linux"},"next section"),"."),(0,i.kt)("h3",{id:"linux"},"Linux"),(0,i.kt)("p",null,"Majority (if not all) of the provided materials include makefile (contains absolute\npath, so in case of linting and compiling, you need to adjust to your needs). You\nbasically need following list of tools:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"gcc")," - for compiling"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"clang-tidy")," - for linting (depends on distribution, might be provided with\nclang itself or in separate package, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"clang-tools-extra"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"clang-format")," - for your own sanity of keeping consistent formatting"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"make")," - since you are provided makefiles and it might be quickest to set up"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"valgrind")," - in case you manage to create memory errors in your code")),(0,i.kt)("p",null,"In case of Fedora it is following set of packages:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-sh"},"sudo dnf install -y clang clang-tools-extra valgrind gcc make\n# If you decide to use google test: add `gtest` or `llvm-googletest` for clang\n")),(0,i.kt)("h3",{id:"macos"},"macOS"),(0,i.kt)("p",null,"In case of macOS you should be able to find all of the packages in brew.sh, except\n",(0,i.kt)("inlineCode",{parentName:"p"},"valgrind"),", not sure if you can solve with podman/docker."),(0,i.kt)("p",null,"There is also an alterantive to homebrew, that is nixpkgs."),(0,i.kt)("h3",{id:"nixos"},"nix(OS)"),(0,i.kt)("p",null,"In case you run nixOS or linux distribution with nixpkgs or you use nixpkgs as a\nreplacement for homebrew on macOS. You should be fine with the following config:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-nix"},'with import {};\nstdenv.mkDerivation {\n name = "cppenv";\n buildInputs = [\n clang-tools\n\n gnumake\n\n gmock # used for google test\n valgrind # not sure about macOS though\n ];\n}\n')),(0,i.kt)("h2",{id:"ides"},"IDEs"),(0,i.kt)("p",null,"Choice of the IDE is mostly up to you, you do not need to use IDE at all ;)"),(0,i.kt)("p",null,"I would probably recommend VSCode + appropriate extension or CLion if you are used\nto the JetBrains IDEs."),(0,i.kt)("h2",{id:"git"},"git"),(0,i.kt)("p",null,"I recommend you using some basic versioning for your code, even though you submit\nonly the sources on ",(0,i.kt)("em",{parentName:"p"},"aisa"),". There are specific reasons why I suggest it:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"if you build a ",(0,i.kt)("em",{parentName:"li"},"commit, tag and submit")," habit, you might be able to address\nsome of the smaller problems in your sources even before submission; more info\nin the ",(0,i.kt)("a",{parentName:"li",href:"#pre-commit"},"pre-commit section"))),(0,i.kt)("p",null,"In case you are planning to use git branches for separating different\nassignments and/or merge requests I suggest you to keep specifications and\nskeletons on your default branch, since ",(0,i.kt)("em",{parentName:"p"},"frag")," on ",(0,i.kt)("em",{parentName:"p"},"aisa")," automatically downloads\neverything that is not present and by that can create conflicts when switching\nbranches."),(0,i.kt)("admonition",{title:"Commit conventions",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"When creating smaller and well defined commits, you can more easily argue about\ncorrectness of your implementation and also identify bugs, since they are better\ncontained.")),(0,i.kt)("p",null,"Since frag creates a lot of support files (majority of them are dotfiles, i.e.\nhidden files), I recommend you to use following\n",(0,i.kt)("a",{parentName:"p",href:"pathname:///files/pb161/environment/gitignore"},"gitignore")," configuration that\nshould cover most of the scenarios."),(0,i.kt)("h3",{id:"pre-commit-link"},"pre-commit (",(0,i.kt)("a",{parentName:"h3",href:"https://pre-commit.com/"},"link"),")"),(0,i.kt)("p",null,'Pre-commit basically allows you to "check" your code before committing. It functions\nas a git hook, i.e. you want to make a commit, pre-commit checks it before-hand.'),(0,i.kt)("p",null,"In case of C++ there are few use-cases:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"formatting")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"linting")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"building and/or running tests, in case you feel like masochist"),(0,i.kt)("p",{parentName:"li"},"However this might be a challenging task to implement, since most of the tasks\nare published from the beginning."))),(0,i.kt)("p",null,"In case of formatting and linting, there are already existing hooks (there is a\nlist of supported ones on the page), but there is also an option for you setting\nit up yourself (it is just a matter of specifying command and files it should run\non)."),(0,i.kt)("admonition",{title:"Formatting",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"For formatting you can the following ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/pre-commit/mirrors-clang-format#using-clang-format-with-pre-commit"},"git hook"),"."),(0,i.kt)("p",{parentName:"admonition"},"This hook follows the formatting conventions defined by the ",(0,i.kt)("inlineCode",{parentName:"p"},".clang-format")," file\nthat is looked up recursively all the way to the root of the filesystem, therefore\nit is ideal to keep it in the root of the git repository."),(0,i.kt)("p",{parentName:"admonition"},"You can look up the different codestyles ",(0,i.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/pb071/codestyles"},"here"),".")),(0,i.kt)("h2",{id:"testing"},"Testing"),(0,i.kt)("p",null,"I have tried 2 frameworks for testing, one of them will be probably showcased in\nlectures. If you have not picked one yet, you can take an inspiration from the\nfollowing."),(0,i.kt)("h3",{id:"catch2"},"catch2"),(0,i.kt)("p",null,"It is quite popular, only one header-file, also might be easier to set up."),(0,i.kt)("p",null,"Might feel slow to compile, this can be addressed by having one object file with\nprecompiled ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," for tests, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},'/* File: catch_main.cpp\n * Compile it with: g++ $(CXXFLAGS) -c catch_main.cpp\n *\n * Once you have source file with tests, e.g. test_something.cpp, compile it in\n * a similar fashion: g++ $(CXXFLAGS) -c test_something.cpp $(LDLIBS)\n *\n * And link them together:\n * g++ catch_main.o test_something.o -o test_something\n *\n * Now you can run ./test_something and if you change it, you do not need to compile\n * the main again.\n */\n#define CATCH_CONFIG_MAIN\n#include "catch.hpp"\n')),(0,i.kt)("h3",{id:"google-test"},"Google Test"),(0,i.kt)("p",null,"It is faster compared to catch2, even if you do not precompile the ",(0,i.kt)("inlineCode",{parentName:"p"},"main"),". Might\nbe more complicated to set up, since there are multiple files (it is not one header\nfile). Not very user friendly on ",(0,i.kt)("em",{parentName:"p"},"aisa"),". However can be installed through package\nmanager."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[4800],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>g});var o=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=o.createContext({}),p=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=p(e.components);return o.createElement(s.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),m=p(n),d=i,g=m["".concat(s,".").concat(d)]||m[d]||u[d]||a;return n?o.createElement(g,r(r({ref:t},c),{},{components:n})):o.createElement(g,r({ref:t},c))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,r=new Array(a);r[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:i,r[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var o=n(7462),i=(n(7294),n(3905));const a={title:"Environment",description:"Suggestions for setting up a local environment for C++ course.\n",last_update:{date:new Date("2023-02-18T00:00:00.000Z")}},r=void 0,l={unversionedId:"environment",id:"environment",title:"Environment",description:"Suggestions for setting up a local environment for C++ course.\n",source:"@site/pb161/environment.md",sourceDirName:".",slug:"/environment",permalink:"/pb161/environment",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb161/environment.md",tags:[],version:"current",lastUpdatedAt:1676678400,formattedLastUpdatedAt:"Feb 18, 2023",frontMatter:{title:"Environment",description:"Suggestions for setting up a local environment for C++ course.\n",last_update:{date:"2023-02-18T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Introduction",permalink:"/pb161/"}},s={},p=[{value:"Required tools per OS",id:"required-tools-per-os",level:2},{value:"Windows",id:"windows",level:3},{value:"Linux",id:"linux",level:3},{value:"macOS",id:"macos",level:3},{value:"nix(OS)",id:"nixos",level:3},{value:"IDEs",id:"ides",level:2},{value:"git",id:"git",level:2},{value:"pre-commit (link)",id:"pre-commit-link",level:3},{value:"Testing",id:"testing",level:2},{value:"catch2",id:"catch2",level:3},{value:"Google Test",id:"google-test",level:3}],c={toc:p},m="wrapper";function u(e){let{components:t,...n}=e;return(0,i.kt)(m,(0,o.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"required-tools-per-os"},"Required tools per OS"),(0,i.kt)("h3",{id:"windows"},"Windows"),(0,i.kt)("p",null,"Most likely WSL, VM or VPS. If you consider setting up either of those PITA, then\nVSCode + SSH to ",(0,i.kt)("em",{parentName:"p"},"aisa")," might be the best option for you."),(0,i.kt)("admonition",{title:"VSCode @ aisa",type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Be careful when using VSCode on aisa, most notably:"),(0,i.kt)("ol",{parentName:"admonition"},(0,i.kt)("li",{parentName:"ol"},"VSCode can leave lingering processes running in the background that can \u201eeat\nup\u201c your quota for running processes.\nAFAIK UNIX team has implemented some periodic clean up of those."),(0,i.kt)("li",{parentName:"ol"},"Disk quota can be also affected, because of the C/C++ extension toolkit that\nhas a cache for IntelliSense."))),(0,i.kt)("p",null,"Either of those will be linux distros, so jump to ",(0,i.kt)("a",{parentName:"p",href:"#linux"},"next section"),"."),(0,i.kt)("h3",{id:"linux"},"Linux"),(0,i.kt)("p",null,"Majority (if not all) of the provided materials include makefile (contains absolute\npath, so in case of linting and compiling, you need to adjust to your needs). You\nbasically need following list of tools:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"gcc")," - for compiling"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"clang-tidy")," - for linting (depends on distribution, might be provided with\nclang itself or in separate package, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"clang-tools-extra"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"clang-format")," - for your own sanity of keeping consistent formatting"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"make")," - since you are provided makefiles and it might be quickest to set up"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"valgrind")," - in case you manage to create memory errors in your code")),(0,i.kt)("p",null,"In case of Fedora it is following set of packages:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-sh"},"sudo dnf install -y clang clang-tools-extra valgrind gcc make\n# If you decide to use google test: add `gtest` or `llvm-googletest` for clang\n")),(0,i.kt)("h3",{id:"macos"},"macOS"),(0,i.kt)("p",null,"In case of macOS you should be able to find all of the packages in brew.sh, except\n",(0,i.kt)("inlineCode",{parentName:"p"},"valgrind"),", not sure if you can solve with podman/docker."),(0,i.kt)("p",null,"There is also an alterantive to homebrew, that is nixpkgs."),(0,i.kt)("h3",{id:"nixos"},"nix(OS)"),(0,i.kt)("p",null,"In case you run nixOS or linux distribution with nixpkgs or you use nixpkgs as a\nreplacement for homebrew on macOS. You should be fine with the following config:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-nix"},'with import {};\nstdenv.mkDerivation {\n name = "cppenv";\n buildInputs = [\n clang-tools\n\n gnumake\n\n gmock # used for google test\n valgrind # not sure about macOS though\n ];\n}\n')),(0,i.kt)("h2",{id:"ides"},"IDEs"),(0,i.kt)("p",null,"Choice of the IDE is mostly up to you, you do not need to use IDE at all ;)"),(0,i.kt)("p",null,"I would probably recommend VSCode + appropriate extension or CLion if you are used\nto the JetBrains IDEs."),(0,i.kt)("h2",{id:"git"},"git"),(0,i.kt)("p",null,"I recommend you using some basic versioning for your code, even though you submit\nonly the sources on ",(0,i.kt)("em",{parentName:"p"},"aisa"),". There are specific reasons why I suggest it:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"if you build a ",(0,i.kt)("em",{parentName:"li"},"commit, tag and submit")," habit, you might be able to address\nsome of the smaller problems in your sources even before submission; more info\nin the ",(0,i.kt)("a",{parentName:"li",href:"#pre-commit"},"pre-commit section"))),(0,i.kt)("p",null,"In case you are planning to use git branches for separating different\nassignments and/or merge requests I suggest you to keep specifications and\nskeletons on your default branch, since ",(0,i.kt)("em",{parentName:"p"},"frag")," on ",(0,i.kt)("em",{parentName:"p"},"aisa")," automatically downloads\neverything that is not present and by that can create conflicts when switching\nbranches."),(0,i.kt)("admonition",{title:"Commit conventions",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"When creating smaller and well defined commits, you can more easily argue about\ncorrectness of your implementation and also identify bugs, since they are better\ncontained.")),(0,i.kt)("p",null,"Since frag creates a lot of support files (majority of them are dotfiles, i.e.\nhidden files), I recommend you to use following\n",(0,i.kt)("a",{parentName:"p",href:"pathname:///files/pb161/environment/gitignore"},"gitignore")," configuration that\nshould cover most of the scenarios."),(0,i.kt)("h3",{id:"pre-commit-link"},"pre-commit (",(0,i.kt)("a",{parentName:"h3",href:"https://pre-commit.com/"},"link"),")"),(0,i.kt)("p",null,'Pre-commit basically allows you to "check" your code before committing. It functions\nas a git hook, i.e. you want to make a commit, pre-commit checks it before-hand.'),(0,i.kt)("p",null,"In case of C++ there are few use-cases:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"formatting")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"linting")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"building and/or running tests, in case you feel like masochist"),(0,i.kt)("p",{parentName:"li"},"However this might be a challenging task to implement, since most of the tasks\nare published from the beginning."))),(0,i.kt)("p",null,"In case of formatting and linting, there are already existing hooks (there is a\nlist of supported ones on the page), but there is also an option for you setting\nit up yourself (it is just a matter of specifying command and files it should run\non)."),(0,i.kt)("admonition",{title:"Formatting",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"For formatting you can the following ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/pre-commit/mirrors-clang-format#using-clang-format-with-pre-commit"},"git hook"),"."),(0,i.kt)("p",{parentName:"admonition"},"This hook follows the formatting conventions defined by the ",(0,i.kt)("inlineCode",{parentName:"p"},".clang-format")," file\nthat is looked up recursively all the way to the root of the filesystem, therefore\nit is ideal to keep it in the root of the git repository."),(0,i.kt)("p",{parentName:"admonition"},"You can look up the different codestyles ",(0,i.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/pb071/codestyles"},"here"),".")),(0,i.kt)("h2",{id:"testing"},"Testing"),(0,i.kt)("p",null,"I have tried 2 frameworks for testing, one of them will be probably showcased in\nlectures. If you have not picked one yet, you can take an inspiration from the\nfollowing."),(0,i.kt)("h3",{id:"catch2"},"catch2"),(0,i.kt)("p",null,"It is quite popular, only one header-file, also might be easier to set up."),(0,i.kt)("p",null,"Might feel slow to compile, this can be addressed by having one object file with\nprecompiled ",(0,i.kt)("inlineCode",{parentName:"p"},"main")," for tests, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},'/* File: catch_main.cpp\n * Compile it with: g++ $(CXXFLAGS) -c catch_main.cpp\n *\n * Once you have source file with tests, e.g. test_something.cpp, compile it in\n * a similar fashion: g++ $(CXXFLAGS) -c test_something.cpp $(LDLIBS)\n *\n * And link them together:\n * g++ catch_main.o test_something.o -o test_something\n *\n * Now you can run ./test_something and if you change it, you do not need to compile\n * the main again.\n */\n#define CATCH_CONFIG_MAIN\n#include "catch.hpp"\n')),(0,i.kt)("h3",{id:"google-test"},"Google Test"),(0,i.kt)("p",null,"It is faster compared to catch2, even if you do not precompile the ",(0,i.kt)("inlineCode",{parentName:"p"},"main"),". Might\nbe more complicated to set up, since there are multiple files (it is not one header\nfile). Not very user friendly on ",(0,i.kt)("em",{parentName:"p"},"aisa"),". However can be installed through package\nmanager."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a6a48ea2.d5faeb42.js b/assets/js/a6a48ea2.50fc62cb.js similarity index 98% rename from assets/js/a6a48ea2.d5faeb42.js rename to assets/js/a6a48ea2.50fc62cb.js index dfc5c33..b29b1ba 100644 --- a/assets/js/a6a48ea2.d5faeb42.js +++ b/assets/js/a6a48ea2.50fc62cb.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3618],{3905:(e,t,n)=>{n.d(t,{Zo:()=>f,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),s=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},f=function(e){var t=s(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,f=c(e,["components","mdxType","originalType","parentName"]),u=s(n),p=o,m=u["".concat(l,".").concat(p)]||u[p]||d[p]||a;return n?r.createElement(m,i(i({ref:t},f),{},{components:n})):r.createElement(m,i({ref:t},f))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var s=2;s{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var r=n(7462),o=(n(7294),n(3905));const a={title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15",slug:"aoc-2022/2nd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/2nd-week",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/02-week-2.md",source:"@site/blog/aoc-2022/02-week-2.md",title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15:00.000Z",formattedDate:"December 25, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:20.875,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15",slug:"aoc-2022/2nd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"Sort the matrix diagonally",permalink:"/blog/leetcode/sort-diagonally"},nextItem:{title:"1st week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/1st-week"}},l={authorsImageUrls:[void 0]},s=[],f={toc:s},u="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,r.Z)({},f,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the second week of ","[",(0,o.kt)("em",{parentName:"p"},"Advent of Code"),"]"," in Rust."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3618],{3905:(e,t,n)=>{n.d(t,{Zo:()=>f,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),s=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},f=function(e){var t=s(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,f=c(e,["components","mdxType","originalType","parentName"]),u=s(n),p=o,m=u["".concat(l,".").concat(p)]||u[p]||d[p]||a;return n?r.createElement(m,i(i({ref:t},f),{},{components:n})):r.createElement(m,i({ref:t},f))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var s=2;s{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var r=n(7462),o=(n(7294),n(3905));const a={title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15",slug:"aoc-2022/2nd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/2nd-week",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/02-week-2.md",source:"@site/blog/aoc-2022/02-week-2.md",title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15:00.000Z",formattedDate:"December 25, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:20.875,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"2nd week of Advent of Code '22 in Rust",description:"Surviving second week in Rust.",date:"2022-12-25T23:15",slug:"aoc-2022/2nd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"Sort the matrix diagonally",permalink:"/blog/leetcode/sort-diagonally"},nextItem:{title:"1st week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/1st-week"}},l={authorsImageUrls:[void 0]},s=[],f={toc:s},u="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,r.Z)({},f,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the second week of ","[",(0,o.kt)("em",{parentName:"p"},"Advent of Code"),"]"," in Rust."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ab2721d4.e0b371f9.js b/assets/js/ab2721d4.319c2058.js similarity index 81% rename from assets/js/ab2721d4.e0b371f9.js rename to assets/js/ab2721d4.319c2058.js index d89699b..a8b610d 100644 --- a/assets/js/ab2721d4.e0b371f9.js +++ b/assets/js/ab2721d4.319c2058.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7755],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),f=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=f(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=f(r),d=o,m=p["".concat(l,".").concat(d)]||p[d]||s[d]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var f=2;f{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>s,frontMatter:()=>a,metadata:()=>c,toc:()=>f});var n=r(7462),o=(r(7294),r(3905));const a={title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14",slug:"aoc-2022/4th-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/4th-week",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/04-week-4.md",source:"@site/blog/aoc-2022/04-week-4.md",title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14:00.000Z",formattedDate:"July 7, 2023",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:15.175,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14",slug:"aoc-2022/4th-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"How can Copr help with broken dependencies",permalink:"/blog/2023/08/02/copr"},nextItem:{title:"3rd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/3rd-week"}},l={authorsImageUrls:[void 0]},f=[],u={toc:f},p="wrapper";function s(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the fourth week of ","[",(0,o.kt)("em",{parentName:"p"},"Advent of Code"),"]"," in Rust."))}s.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7755],{3905:(e,t,r)=>{r.d(t,{Zo:()=>f,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},f=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,f=c(e,["components","mdxType","originalType","parentName"]),p=u(r),d=o,m=p["".concat(l,".").concat(d)]||p[d]||s[d]||a;return r?n.createElement(m,i(i({ref:t},f),{},{components:r})):n.createElement(m,i({ref:t},f))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var u=2;u{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>s,frontMatter:()=>a,metadata:()=>c,toc:()=>u});var n=r(7462),o=(r(7294),r(3905));const a={title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14",slug:"aoc-2022/4th-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/4th-week",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/04-week-4.md",source:"@site/blog/aoc-2022/04-week-4.md",title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14:00.000Z",formattedDate:"July 7, 2023",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:15.175,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"4th week of Advent of Code '22 in Rust",description:"Surviving fourth week in Rust.",date:"2023-07-07T15:14",slug:"aoc-2022/4th-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"How can Copr help with broken dependencies",permalink:"/blog/2023/08/02/copr"},nextItem:{title:"3rd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/3rd-week"}},l={authorsImageUrls:[void 0]},u=[],f={toc:u},p="wrapper";function s(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the fourth week of ","[",(0,o.kt)("em",{parentName:"p"},"Advent of Code"),"]"," in Rust."))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/af8b72a7.1e28998e.js b/assets/js/af8b72a7.7e44f77a.js similarity index 98% rename from assets/js/af8b72a7.1e28998e.js rename to assets/js/af8b72a7.7e44f77a.js index 803d7f1..01e8b59 100644 --- a/assets/js/af8b72a7.1e28998e.js +++ b/assets/js/af8b72a7.7e44f77a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[5658],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),m=p(r),d=o,f=m["".concat(l,".").concat(d)]||m[d]||u[d]||a;return r?n.createElement(f,i(i({ref:t},s),{},{components:r})):n.createElement(f,i({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[m]="string"==typeof e?e:o,i[1]=c;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const a={title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:new Date("2023-08-02T00:00:00.000Z"),authors:[{key:"mf",title:"a.k.a. your opinionated admin"}],tags:["\ud83c\udfed","red-hat","copr","admin","vps"]},i=void 0,c={permalink:"/blog/2023/08/02/copr",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/2023-08-02-copr.md",source:"@site/blog/2023-08-02-copr.md",title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:"2023-08-02T00:00:00.000Z",formattedDate:"August 2, 2023",tags:[{label:"\ud83c\udfed",permalink:"/blog/tags/\ud83c\udfed"},{label:"red-hat",permalink:"/blog/tags/red-hat"},{label:"copr",permalink:"/blog/tags/copr"},{label:"admin",permalink:"/blog/tags/admin"},{label:"vps",permalink:"/blog/tags/vps"}],readingTime:3.44,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. your opinionated admin",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:"2023-08-02T00:00:00.000Z",authors:[{key:"mf",title:"a.k.a. your opinionated admin"}],tags:["\ud83c\udfed","red-hat","copr","admin","vps"]},nextItem:{title:"4th week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/4th-week"}},l={authorsImageUrls:[void 0]},p=[],s={toc:p},m="wrapper";function u(e){let{components:t,...r}=e;return(0,o.kt)(m,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"When you decide to run Fedora on your VPS, you might get screwed over by using\nrandom repositories\u2026"))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[5658],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),m=p(r),d=o,f=m["".concat(l,".").concat(d)]||m[d]||u[d]||a;return r?n.createElement(f,i(i({ref:t},s),{},{components:r})):n.createElement(f,i({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[m]="string"==typeof e?e:o,i[1]=c;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>p});var n=r(7462),o=(r(7294),r(3905));const a={title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:new Date("2023-08-02T00:00:00.000Z"),authors:[{key:"mf",title:"a.k.a. your opinionated admin"}],tags:["\ud83c\udfed","red-hat","copr","admin","vps"]},i=void 0,c={permalink:"/blog/2023/08/02/copr",editUrl:"https://github.com/mfocko/blog/tree/main/blog/2023-08-02-copr.md",source:"@site/blog/2023-08-02-copr.md",title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:"2023-08-02T00:00:00.000Z",formattedDate:"August 2, 2023",tags:[{label:"\ud83c\udfed",permalink:"/blog/tags/\ud83c\udfed"},{label:"red-hat",permalink:"/blog/tags/red-hat"},{label:"copr",permalink:"/blog/tags/copr"},{label:"admin",permalink:"/blog/tags/admin"},{label:"vps",permalink:"/blog/tags/vps"}],readingTime:3.44,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. your opinionated admin",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:"2023-08-02T00:00:00.000Z",authors:[{key:"mf",title:"a.k.a. your opinionated admin"}],tags:["\ud83c\udfed","red-hat","copr","admin","vps"]},nextItem:{title:"4th week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/4th-week"}},l={authorsImageUrls:[void 0]},p=[],s={toc:p},m="wrapper";function u(e){let{components:t,...r}=e;return(0,o.kt)(m,(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"When you decide to run Fedora on your VPS, you might get screwed over by using\nrandom repositories\u2026"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b5a32f14.3c491fc9.js b/assets/js/b5a32f14.bd4170d8.js similarity index 99% rename from assets/js/b5a32f14.3c491fc9.js rename to assets/js/b5a32f14.bd4170d8.js index 5ba6cdb..6d2762b 100644 --- a/assets/js/b5a32f14.3c491fc9.js +++ b/assets/js/b5a32f14.bd4170d8.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2433],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=o.createContext({}),l=function(e){var t=o.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(p.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,p=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(p,".").concat(h)]||u[h]||c[h]||a;return n?o.createElement(m,i(i({ref:t},d),{},{components:n})):o.createElement(m,i({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const a={title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:new Date("2023-08-02T00:00:00.000Z"),authors:[{key:"mf",title:"a.k.a. your opinionated admin"}],tags:["\ud83c\udfed","red-hat","copr","admin","vps"]},i=void 0,s={permalink:"/blog/2023/08/02/copr",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/2023-08-02-copr.md",source:"@site/blog/2023-08-02-copr.md",title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:"2023-08-02T00:00:00.000Z",formattedDate:"August 2, 2023",tags:[{label:"\ud83c\udfed",permalink:"/blog/tags/\ud83c\udfed"},{label:"red-hat",permalink:"/blog/tags/red-hat"},{label:"copr",permalink:"/blog/tags/copr"},{label:"admin",permalink:"/blog/tags/admin"},{label:"vps",permalink:"/blog/tags/vps"}],readingTime:3.44,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. your opinionated admin",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:"2023-08-02T00:00:00.000Z",authors:[{key:"mf",title:"a.k.a. your opinionated admin"}],tags:["\ud83c\udfed","red-hat","copr","admin","vps"]},nextItem:{title:"4th week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/4th-week"}},p={authorsImageUrls:[void 0]},l=[{value:"How does Copr repositories work?",id:"how-does-copr-repositories-work",level:2},{value:"My issue",id:"my-issue",level:2},{value:"How can Copr help?",id:"how-can-copr-help",level:2},{value:"Conclusion",id:"conclusion",level:2}],d={toc:l},u="wrapper";function c(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"When you decide to run Fedora on your VPS, you might get screwed over by using\nrandom repositories\u2026"),(0,r.kt)("p",null,"When I \u201creserved\u201d my VPS",(0,r.kt)("sup",{parentName:"p",id:"fnref-1-d4045e"},(0,r.kt)("a",{parentName:"sup",href:"#fn-1-d4045e",className:"footnote-ref"},"1"))," back in June '20, I slapped Fedora on it without\nthinking. I bet 99% of people would say that I'm crazy for doing such thing",(0,r.kt)("sup",{parentName:"p",id:"fnref-2-d4045e"},(0,r.kt)("a",{parentName:"sup",href:"#fn-2-d4045e",className:"footnote-ref"},"2")),",\n",(0,r.kt)("strong",{parentName:"p"},"BUT")," I've been using Fedora on my PCs for some time already and it felt very\nstable and natural to just use, even for VPS."),(0,r.kt)("p",null,"One of the first things I've done was setting up a mail server. You may guess\nwhat's the fun part about having a mail server\u2026 Yes, it's all the spam you\nreceive and only then you realize how much \u201ccrap\u201d gets filtered on free mail\nservices. To battle this problem I chose to use\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/rspamd/rspamd"},"rspamd")," that had CentOS support, but someone\nhad a ",(0,r.kt)("a",{parentName:"p",href:"https://copr.fedorainfracloud.org/"},"Copr")," repository that I used to\ninstall it."),(0,r.kt)("h2",{id:"how-does-copr-repositories-work"},"How does Copr repositories work?"),(0,r.kt)("p",null,"If you have ever used Ubuntu, you might be familiar with the concept since it is\nvery close to ",(0,r.kt)("a",{parentName:"p",href:"https://help.ubuntu.com/community/PPA"},"PPAs"),"."),(0,r.kt)("p",null,"tl;dr of the whole process consists of"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"enabling the Copr repository, and"),(0,r.kt)("li",{parentName:"ol"},"installing the desired package.")),(0,r.kt)("p",null,"So in shell you would do"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"# dnf copr enable \u2039copr-repository\u203a\n# dnf install \u2039package-from-the-repository\u203a\n")),(0,r.kt)("p",null,"And\u2026 that's it! Nothing else needed! Simple, right? And literally same process\nas you would do for the PPA."),(0,r.kt)("admonition",{title:"AUR",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"On the other hand, if you are familiar with the archLinux, you definitely know\nAUR and what it can do for you. Copr repository is pretty similar, but the\npackages are prebuilt in Copr and Copr repositories can carry the required\ndependencies for said packages, which simplifies the distribution, and can even\nhelp with installing singular packages (when you just need the dependency, not\neverything).")),(0,r.kt)("h2",{id:"my-issue"},"My issue"),(0,r.kt)("p",null,"Now you might wonder how would I use it on my VPS. It's rather simple, once in\n6 months a new Fedora release comes out. And you need to upgrade to newer\nrelease\u2026 You don't need to do it right away and for such setup it probably isn't\neven recommended."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Fedora releases are supported for a year, i.e. they live 6 months till the next\nrelease and then another 6 months till another release."),(0,r.kt)("p",{parentName:"admonition"},"Some people prefer to run one version \u201cbehind\u201d. If you ever decide to run it on\nyour home server or in a similar setup, it might be a pretty good idea to\nfollow. I'm using the \u201clatest greatest\u201d, cause why not \ud83d\ude04"),(0,r.kt)("p",{parentName:"admonition"},"One way or another, you still need to bump the release every six months, unless\nyou'd bump 2 releases at once every year, which would be a decision, since, at\nleast I, cannot see any benefits in it\u2026 You don't go for \u201cstability\u201d, cause once\na year you switch to the latest release and then, before you bump, you use one\nyear old software, so you're not even using the latest.")),(0,r.kt)("p",null,"Fast-forward 2 years in the future, new Fedora release came out (October '22)\nand I was doing an upgrade. Dependencies of the rspamd have been updated and\nrspamd builds in Copr have failed and no one fixed it. Cool, so now I can\nupgrade, but can either ignore the dependencies or uninstall the rspamd\u2026"),(0,r.kt)("h2",{id:"how-can-copr-help"},"How can Copr help?"),(0,r.kt)("p",null,"I have managed to find\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/rspamd/rspamd/blob/master/rpm/rspamd.spec"},"specfile")," for the\nrspamd package that they use for CentOS. There were some files apart from the\nspecfile, so I had to make an SRPM locally and then\u2026 I just uploaded the SRPM\nto the Copr to\n",(0,r.kt)("a",{parentName:"p",href:"https://copr.fedorainfracloud.org/coprs/mfocko/rspamd/build/5046567/"},"build"),"\nan RPM."),(0,r.kt)("p",null,"I have switched the previous Copr repository for rspamd with my own and happily\nproceeded with the upgrade."),(0,r.kt)("h2",{id:"conclusion"},"Conclusion"),(0,r.kt)("p",null,"Copr is heavily used for testing builds on the upstream with\n",(0,r.kt)("a",{parentName:"p",href:"https://packit.dev"},"Packit"),". However, as you can see, it is possible to use it\n",(0,r.kt)("strong",{parentName:"p"},"very well")," for packaging your own stuff and avoiding issues (such as the one\nI have described above), if need be."),(0,r.kt)("div",{className:"footnotes"},(0,r.kt)("hr",{parentName:"div"}),(0,r.kt)("ol",{parentName:"div"},(0,r.kt)("li",{parentName:"ol",id:"fn-1-d4045e"},(0,r.kt)("a",{parentName:"li",href:"https://vpsfree.cz"},"vpsFree.cz"),(0,r.kt)("a",{parentName:"li",href:"#fnref-1-d4045e",className:"footnote-backref"},"\u21a9")),(0,r.kt)("li",{parentName:"ol",id:"fn-2-d4045e"},"Even though I've been running archLinux on some Raspberry Pi's and also\non one of my \u201chome servers\u201d, before getting the VPS. You could say I like\nto live on the edge\u2026",(0,r.kt)("a",{parentName:"li",href:"#fnref-2-d4045e",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2433],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=o.createContext({}),l=function(e){var t=o.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(p.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,p=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(p,".").concat(h)]||u[h]||c[h]||a;return n?o.createElement(m,i(i({ref:t},d),{},{components:n})):o.createElement(m,i({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var o=n(7462),r=(n(7294),n(3905));const a={title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:new Date("2023-08-02T00:00:00.000Z"),authors:[{key:"mf",title:"a.k.a. your opinionated admin"}],tags:["\ud83c\udfed","red-hat","copr","admin","vps"]},i=void 0,s={permalink:"/blog/2023/08/02/copr",editUrl:"https://github.com/mfocko/blog/tree/main/blog/2023-08-02-copr.md",source:"@site/blog/2023-08-02-copr.md",title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:"2023-08-02T00:00:00.000Z",formattedDate:"August 2, 2023",tags:[{label:"\ud83c\udfed",permalink:"/blog/tags/\ud83c\udfed"},{label:"red-hat",permalink:"/blog/tags/red-hat"},{label:"copr",permalink:"/blog/tags/copr"},{label:"admin",permalink:"/blog/tags/admin"},{label:"vps",permalink:"/blog/tags/vps"}],readingTime:3.44,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. your opinionated admin",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"How can Copr help with broken dependencies",description:"Copr comes to save you when maintainer doesn't care.",date:"2023-08-02T00:00:00.000Z",authors:[{key:"mf",title:"a.k.a. your opinionated admin"}],tags:["\ud83c\udfed","red-hat","copr","admin","vps"]},nextItem:{title:"4th week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/4th-week"}},p={authorsImageUrls:[void 0]},l=[{value:"How does Copr repositories work?",id:"how-does-copr-repositories-work",level:2},{value:"My issue",id:"my-issue",level:2},{value:"How can Copr help?",id:"how-can-copr-help",level:2},{value:"Conclusion",id:"conclusion",level:2}],d={toc:l},u="wrapper";function c(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"When you decide to run Fedora on your VPS, you might get screwed over by using\nrandom repositories\u2026"),(0,r.kt)("p",null,"When I \u201creserved\u201d my VPS",(0,r.kt)("sup",{parentName:"p",id:"fnref-1-d4045e"},(0,r.kt)("a",{parentName:"sup",href:"#fn-1-d4045e",className:"footnote-ref"},"1"))," back in June '20, I slapped Fedora on it without\nthinking. I bet 99% of people would say that I'm crazy for doing such thing",(0,r.kt)("sup",{parentName:"p",id:"fnref-2-d4045e"},(0,r.kt)("a",{parentName:"sup",href:"#fn-2-d4045e",className:"footnote-ref"},"2")),",\n",(0,r.kt)("strong",{parentName:"p"},"BUT")," I've been using Fedora on my PCs for some time already and it felt very\nstable and natural to just use, even for VPS."),(0,r.kt)("p",null,"One of the first things I've done was setting up a mail server. You may guess\nwhat's the fun part about having a mail server\u2026 Yes, it's all the spam you\nreceive and only then you realize how much \u201ccrap\u201d gets filtered on free mail\nservices. To battle this problem I chose to use\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/rspamd/rspamd"},"rspamd")," that had CentOS support, but someone\nhad a ",(0,r.kt)("a",{parentName:"p",href:"https://copr.fedorainfracloud.org/"},"Copr")," repository that I used to\ninstall it."),(0,r.kt)("h2",{id:"how-does-copr-repositories-work"},"How does Copr repositories work?"),(0,r.kt)("p",null,"If you have ever used Ubuntu, you might be familiar with the concept since it is\nvery close to ",(0,r.kt)("a",{parentName:"p",href:"https://help.ubuntu.com/community/PPA"},"PPAs"),"."),(0,r.kt)("p",null,"tl;dr of the whole process consists of"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"enabling the Copr repository, and"),(0,r.kt)("li",{parentName:"ol"},"installing the desired package.")),(0,r.kt)("p",null,"So in shell you would do"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"# dnf copr enable \u2039copr-repository\u203a\n# dnf install \u2039package-from-the-repository\u203a\n")),(0,r.kt)("p",null,"And\u2026 that's it! Nothing else needed! Simple, right? And literally same process\nas you would do for the PPA."),(0,r.kt)("admonition",{title:"AUR",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"On the other hand, if you are familiar with the archLinux, you definitely know\nAUR and what it can do for you. Copr repository is pretty similar, but the\npackages are prebuilt in Copr and Copr repositories can carry the required\ndependencies for said packages, which simplifies the distribution, and can even\nhelp with installing singular packages (when you just need the dependency, not\neverything).")),(0,r.kt)("h2",{id:"my-issue"},"My issue"),(0,r.kt)("p",null,"Now you might wonder how would I use it on my VPS. It's rather simple, once in\n6 months a new Fedora release comes out. And you need to upgrade to newer\nrelease\u2026 You don't need to do it right away and for such setup it probably isn't\neven recommended."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Fedora releases are supported for a year, i.e. they live 6 months till the next\nrelease and then another 6 months till another release."),(0,r.kt)("p",{parentName:"admonition"},"Some people prefer to run one version \u201cbehind\u201d. If you ever decide to run it on\nyour home server or in a similar setup, it might be a pretty good idea to\nfollow. I'm using the \u201clatest greatest\u201d, cause why not \ud83d\ude04"),(0,r.kt)("p",{parentName:"admonition"},"One way or another, you still need to bump the release every six months, unless\nyou'd bump 2 releases at once every year, which would be a decision, since, at\nleast I, cannot see any benefits in it\u2026 You don't go for \u201cstability\u201d, cause once\na year you switch to the latest release and then, before you bump, you use one\nyear old software, so you're not even using the latest.")),(0,r.kt)("p",null,"Fast-forward 2 years in the future, new Fedora release came out (October '22)\nand I was doing an upgrade. Dependencies of the rspamd have been updated and\nrspamd builds in Copr have failed and no one fixed it. Cool, so now I can\nupgrade, but can either ignore the dependencies or uninstall the rspamd\u2026"),(0,r.kt)("h2",{id:"how-can-copr-help"},"How can Copr help?"),(0,r.kt)("p",null,"I have managed to find\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/rspamd/rspamd/blob/master/rpm/rspamd.spec"},"specfile")," for the\nrspamd package that they use for CentOS. There were some files apart from the\nspecfile, so I had to make an SRPM locally and then\u2026 I just uploaded the SRPM\nto the Copr to\n",(0,r.kt)("a",{parentName:"p",href:"https://copr.fedorainfracloud.org/coprs/mfocko/rspamd/build/5046567/"},"build"),"\nan RPM."),(0,r.kt)("p",null,"I have switched the previous Copr repository for rspamd with my own and happily\nproceeded with the upgrade."),(0,r.kt)("h2",{id:"conclusion"},"Conclusion"),(0,r.kt)("p",null,"Copr is heavily used for testing builds on the upstream with\n",(0,r.kt)("a",{parentName:"p",href:"https://packit.dev"},"Packit"),". However, as you can see, it is possible to use it\n",(0,r.kt)("strong",{parentName:"p"},"very well")," for packaging your own stuff and avoiding issues (such as the one\nI have described above), if need be."),(0,r.kt)("div",{className:"footnotes"},(0,r.kt)("hr",{parentName:"div"}),(0,r.kt)("ol",{parentName:"div"},(0,r.kt)("li",{parentName:"ol",id:"fn-1-d4045e"},(0,r.kt)("a",{parentName:"li",href:"https://vpsfree.cz"},"vpsFree.cz"),(0,r.kt)("a",{parentName:"li",href:"#fnref-1-d4045e",className:"footnote-backref"},"\u21a9")),(0,r.kt)("li",{parentName:"ol",id:"fn-2-d4045e"},"Even though I've been running archLinux on some Raspberry Pi's and also\non one of my \u201chome servers\u201d, before getting the VPS. You could say I like\nto live on the edge\u2026",(0,r.kt)("a",{parentName:"li",href:"#fnref-2-d4045e",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b9b1ccdc.859f8a18.js b/assets/js/b9b1ccdc.11390f7f.js similarity index 99% rename from assets/js/b9b1ccdc.859f8a18.js rename to assets/js/b9b1ccdc.11390f7f.js index 3eb529c..869803a 100644 --- a/assets/js/b9b1ccdc.859f8a18.js +++ b/assets/js/b9b1ccdc.11390f7f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9044],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),m=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},s=function(e){var t=m(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,s=p(e,["components","mdxType","originalType","parentName"]),u=m(a),d=r,h=u["".concat(l,".").concat(d)]||u[d]||c[d]||o;return a?n.createElement(h,i(i({ref:t},s),{},{components:a})):n.createElement(h,i({ref:t},s))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[u]="string"==typeof e?e:r,i[1]=p;for(var m=2;m{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>p,toc:()=>m});var n=a(7462),r=(a(7294),a(3905));const o={slug:"cams",title:"Practice exam C",description:"Stalking cars\u2026\n",last_update:{date:new Date("2023-05-07T00:00:00.000Z")}},i="Watching Cams",p={unversionedId:"pexam/c-cams",id:"pexam/c-cams",title:"Practice exam C",description:"Stalking cars\u2026\n",source:"@site/pb071/pexam/c-cams.md",sourceDirName:"pexam",slug:"/pexam/cams",permalink:"/pb071/pexam/cams",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/pexam/c-cams.md",tags:[],version:"current",lastUpdatedAt:1683417600,formattedLastUpdatedAt:"May 7, 2023",frontMatter:{slug:"cams",title:"Practice exam C",description:"Stalking cars\u2026\n",last_update:{date:"2023-05-07T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Practice exam B",permalink:"/pb071/pexam/garbage_collect"},next:{title:"Submitting merge requests",permalink:"/pb071/mr"}},l={},m=[{value:"Format of the input file",id:"format-of-the-input-file",level:2},{value:"Examples",id:"examples",level:4},{value:"Format of the output",id:"format-of-the-output",level:2},{value:"Example usage",id:"example-usage",level:2},{value:"Requirements and notes",id:"requirements-and-notes",level:2}],s={toc:m},u="wrapper";function c(e){let{components:t,...a}=e;return(0,r.kt)(u,(0,n.Z)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"watching-cams"},"Watching Cams"),(0,r.kt)("admonition",{title:"Exam environment",type:"caution"},(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"During the exam you will be provided with a barebone ",(0,r.kt)("em",{parentName:"li"},"exam session")," on the\n",(0,r.kt)("em",{parentName:"li"},"faculty computers"),"."),(0,r.kt)("li",{parentName:"ul"},"In browser you are only allowed to have the following tabs open:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.cppreference.com"},"C documentation")),(0,r.kt)("li",{parentName:"ul"},"page containing the assignment"))),(0,r.kt)("li",{parentName:"ul"},"You ",(0,r.kt)("strong",{parentName:"li"},"are not")," allowed to use your own source code, e.g. prepared beforehand\nor from the seminars."),(0,r.kt)("li",{parentName:"ul"},"You have ",(0,r.kt)("strong",{parentName:"li"},"5 minutes")," to read through the assignment and ask any follow-up\nquestions should be there something unclear."),(0,r.kt)("li",{parentName:"ul"},"You have ",(0,r.kt)("strong",{parentName:"li"},"60 minutes")," to work on the assignment, afterward your work will be\ndiscussed with your seminar tutor."))),(0,r.kt)("p",null,"Your task is to write a program ",(0,r.kt)("inlineCode",{parentName:"p"},"cams")," that will be processing input from the\ncams that are capable of identifying license plates on the cars and then\nprint out summary based on the input data. Your contributions to the society are\nvery much appreciated and may (or may not) be used for (each or none) of the\nfollowing purposes",(0,r.kt)("sup",{parentName:"p",id:"fnref-1"},(0,r.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"stalking people leaving and coming back home,"),(0,r.kt)("li",{parentName:"ul"},"retroactively making people pay for the parking,"),(0,r.kt)("li",{parentName:"ul"},"providing evidence of people speeding on highways,"),(0,r.kt)("li",{parentName:"ul"},"tracking people that don't pay tolls, or"),(0,r.kt)("li",{parentName:"ul"},"convict employees leaving the work prematurely.")),(0,r.kt)("h2",{id:"format-of-the-input-file"},"Format of the input file"),(0,r.kt)("p",null,"Input for your program consists of the data from the cameras. You will be given\nthe data from the cameras as a path to a file and user should also be able to\nspecify ",(0,r.kt)("inlineCode",{parentName:"p"},"-")," (i.e. ",(0,r.kt)("inlineCode",{parentName:"p"},"stdin"),") as the path."),(0,r.kt)("p",null,"Each \u201cscan\u201d (i.e. reading) of the cameras consists of the following data:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"camera ID"),": non-negative integer identifying a camera")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"plate"),": string of unknown length that can consist of any characters apart\nfrom whitespace")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"timestamp"),": date and time of the scan as an unsigned integer (represented as\na UNIX time)"),(0,r.kt)("admonition",{parentName:"li",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"When programming on UN","*","X(-like) systems, you can assume that the ",(0,r.kt)("inlineCode",{parentName:"p"},"time_t"),"\nstructure from the system header ",(0,r.kt)("inlineCode",{parentName:"p"},"time.h")," ",(0,r.kt)("strong",{parentName:"p"},"is")," the ",(0,r.kt)("inlineCode",{parentName:"p"},"unsigned int")," that you\nare provided in the input file.")))),(0,r.kt)("p",null,"And they are compiled into one reading such as:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"camera_ID: plate timestamp\n")),(0,r.kt)("p",null,"There should be always ",(0,r.kt)("strong",{parentName:"p"},"at least one")," space in between each part of the\nreading. Readings are separated by the commas, which may, but don't have to, be\naccompanied by whitespace around."),(0,r.kt)("h4",{id:"examples"},"Examples"),(0,r.kt)("p",null,"Few examples of the data from the cameras follow"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"10: ABC-12-34 1664608712, 289: XYZ-98-76 1665416417,\n25: ABC-12-34 1633078256 , 42: TryToCatchMe 1671602419,\n11: EL9-987 1679541338 ,2 : Foo-666 1683170082,42: YourMum 1683170082,\n42: TryToCatchMe 1671602419 , 1234: TryToCatchMe 1671602419,\n19: ABC-12-34 1664659649, 69:YouShould-not-pLaCe-4ny-expectations%on^the(input 1680307994,\n9 : 9B9-161 1665416417 , 10: 1a1-999 1671602419,1:lmao 1633078256,\n16: ABC-12-34 1664609012\n")),(0,r.kt)("h2",{id:"format-of-the-output"},"Format of the output"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"All the examples consider using data from the example of the input.")),(0,r.kt)("p",null,"You are expected to print out the dates and cameras that has captured the\nlicense plate for each of them (in a sorted fashion)."),(0,r.kt)("p",null,"If there are multiple scans present and the timespan (i.e. time difference\nbetween the scans is bigger than 60 minutes, you should separate them by a\nnewline). For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"*** ABC-12-34 ***\n 25: Fri Oct 1 10:50:56 2021\n\n 10: Sat Oct 1 09:18:32 2022\n 16: Sat Oct 1 09:23:32 2022\n\n 19: Sat Oct 1 23:27:29 2022\n")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Since you are given the timestamp in a ",(0,r.kt)("inlineCode",{parentName:"p"},"time_t")," compatible type on UN","*","X, you\ncan safely use ",(0,r.kt)("inlineCode",{parentName:"p"},"ctime(3)")," for printing the timestamp as a ",(0,r.kt)("em",{parentName:"p"},"human readable")," time\nwhen outputting the date and time.")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"For a better readability you can include one more newline after the last line\nof the output.")),(0,r.kt)("h2",{id:"example-usage"},"Example usage"),(0,r.kt)("p",null,"You can also have a look at example usage of your program. We can run your\nprogram from the shell like"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ ./cams example_1.txt\n")),(0,r.kt)("p",null,"And it will produce an output:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"*** ABC-12-34 ***\n 25: Fri Oct 1 10:50:56 2021\n\n 10: Sat Oct 1 09:18:32 2022\n 16: Sat Oct 1 09:23:32 2022\n\n 19: Sat Oct 1 23:27:29 2022\n\n*** EL9-987 ***\n 11: Thu Mar 23 04:15:38 2023\n\n*** Foo-666 ***\n 2: Thu May 4 05:14:42 2023\n\n*** TryToCatchMe ***\n 42: Wed Dec 21 07:00:19 2022\n 42: Wed Dec 21 07:00:19 2022\n 1234: Wed Dec 21 07:00:19 2022\n\n*** XYZ-98-76 ***\n 289: Mon Oct 10 17:40:17 2022\n\n*** YouShould-not-pLaCe-4ny-expectations%on^the(input ***\n 69: Sat Apr 1 02:13:14 2023\n\n*** YourMum ***\n 42: Thu May 4 05:14:42 2023\n")),(0,r.kt)("h2",{id:"requirements-and-notes"},"Requirements and notes"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Define ",(0,r.kt)("strong",{parentName:"li"},"structures")," (and ",(0,r.kt)("strong",{parentName:"li"},"enumerations"),", if applicable) for the parsed\ninformation from the files."),(0,r.kt)("li",{parentName:"ul"},"For keeping the \u201crecords\u201d, use some ",(0,r.kt)("strong",{parentName:"li"},"dynamic")," data structure.",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Don't forget to consider pros and cons of using ",(0,r.kt)("em",{parentName:"li"},"specific")," data structures\nbefore going through implementing."))),(0,r.kt)("li",{parentName:"ul"},"You ",(0,r.kt)("strong",{parentName:"li"},"are not required")," to produce 1:1 output to the provided examples, they\nare just a hint to not waste your time tinkering with a user experience."),(0,r.kt)("li",{parentName:"ul"},"If any of the operations on the input files should fail,\n",(0,r.kt)("strong",{parentName:"li"},"you are expected to")," handle the situation ",(0,r.kt)("em",{parentName:"li"},"accordingly"),"."),(0,r.kt)("li",{parentName:"ul"},"Failures of any other common functions (e.g. functions used for memory\nmanagement) should be handled in ",(0,r.kt)("strong",{parentName:"li"},"the same way")," as they were in the\nhomeworks and seminars."),(0,r.kt)("li",{parentName:"ul"},"Your program ",(0,r.kt)("strong",{parentName:"li"},"must free")," all the resources before exiting.")),(0,r.kt)("div",{className:"footnotes"},(0,r.kt)("hr",{parentName:"div"}),(0,r.kt)("ol",{parentName:"div"},(0,r.kt)("li",{parentName:"ol",id:"fn-1"},"Subject to NDA.",(0,r.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9044],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),m=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},s=function(e){var t=m(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,s=p(e,["components","mdxType","originalType","parentName"]),u=m(a),d=r,h=u["".concat(l,".").concat(d)]||u[d]||c[d]||o;return a?n.createElement(h,i(i({ref:t},s),{},{components:a})):n.createElement(h,i({ref:t},s))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[u]="string"==typeof e?e:r,i[1]=p;for(var m=2;m{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>p,toc:()=>m});var n=a(7462),r=(a(7294),a(3905));const o={slug:"cams",title:"Practice exam C",description:"Stalking cars\u2026\n",last_update:{date:new Date("2023-05-07T00:00:00.000Z")}},i="Watching Cams",p={unversionedId:"pexam/c-cams",id:"pexam/c-cams",title:"Practice exam C",description:"Stalking cars\u2026\n",source:"@site/pb071/pexam/c-cams.md",sourceDirName:"pexam",slug:"/pexam/cams",permalink:"/pb071/pexam/cams",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/pexam/c-cams.md",tags:[],version:"current",lastUpdatedAt:1683417600,formattedLastUpdatedAt:"May 7, 2023",frontMatter:{slug:"cams",title:"Practice exam C",description:"Stalking cars\u2026\n",last_update:{date:"2023-05-07T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Practice exam B",permalink:"/pb071/pexam/garbage_collect"},next:{title:"Submitting merge requests",permalink:"/pb071/mr"}},l={},m=[{value:"Format of the input file",id:"format-of-the-input-file",level:2},{value:"Examples",id:"examples",level:4},{value:"Format of the output",id:"format-of-the-output",level:2},{value:"Example usage",id:"example-usage",level:2},{value:"Requirements and notes",id:"requirements-and-notes",level:2}],s={toc:m},u="wrapper";function c(e){let{components:t,...a}=e;return(0,r.kt)(u,(0,n.Z)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"watching-cams"},"Watching Cams"),(0,r.kt)("admonition",{title:"Exam environment",type:"caution"},(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"During the exam you will be provided with a barebone ",(0,r.kt)("em",{parentName:"li"},"exam session")," on the\n",(0,r.kt)("em",{parentName:"li"},"faculty computers"),"."),(0,r.kt)("li",{parentName:"ul"},"In browser you are only allowed to have the following tabs open:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.cppreference.com"},"C documentation")),(0,r.kt)("li",{parentName:"ul"},"page containing the assignment"))),(0,r.kt)("li",{parentName:"ul"},"You ",(0,r.kt)("strong",{parentName:"li"},"are not")," allowed to use your own source code, e.g. prepared beforehand\nor from the seminars."),(0,r.kt)("li",{parentName:"ul"},"You have ",(0,r.kt)("strong",{parentName:"li"},"5 minutes")," to read through the assignment and ask any follow-up\nquestions should be there something unclear."),(0,r.kt)("li",{parentName:"ul"},"You have ",(0,r.kt)("strong",{parentName:"li"},"60 minutes")," to work on the assignment, afterward your work will be\ndiscussed with your seminar tutor."))),(0,r.kt)("p",null,"Your task is to write a program ",(0,r.kt)("inlineCode",{parentName:"p"},"cams")," that will be processing input from the\ncams that are capable of identifying license plates on the cars and then\nprint out summary based on the input data. Your contributions to the society are\nvery much appreciated and may (or may not) be used for (each or none) of the\nfollowing purposes",(0,r.kt)("sup",{parentName:"p",id:"fnref-1"},(0,r.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"stalking people leaving and coming back home,"),(0,r.kt)("li",{parentName:"ul"},"retroactively making people pay for the parking,"),(0,r.kt)("li",{parentName:"ul"},"providing evidence of people speeding on highways,"),(0,r.kt)("li",{parentName:"ul"},"tracking people that don't pay tolls, or"),(0,r.kt)("li",{parentName:"ul"},"convict employees leaving the work prematurely.")),(0,r.kt)("h2",{id:"format-of-the-input-file"},"Format of the input file"),(0,r.kt)("p",null,"Input for your program consists of the data from the cameras. You will be given\nthe data from the cameras as a path to a file and user should also be able to\nspecify ",(0,r.kt)("inlineCode",{parentName:"p"},"-")," (i.e. ",(0,r.kt)("inlineCode",{parentName:"p"},"stdin"),") as the path."),(0,r.kt)("p",null,"Each \u201cscan\u201d (i.e. reading) of the cameras consists of the following data:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"camera ID"),": non-negative integer identifying a camera")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"plate"),": string of unknown length that can consist of any characters apart\nfrom whitespace")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"timestamp"),": date and time of the scan as an unsigned integer (represented as\na UNIX time)"),(0,r.kt)("admonition",{parentName:"li",type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"When programming on UN","*","X(-like) systems, you can assume that the ",(0,r.kt)("inlineCode",{parentName:"p"},"time_t"),"\nstructure from the system header ",(0,r.kt)("inlineCode",{parentName:"p"},"time.h")," ",(0,r.kt)("strong",{parentName:"p"},"is")," the ",(0,r.kt)("inlineCode",{parentName:"p"},"unsigned int")," that you\nare provided in the input file.")))),(0,r.kt)("p",null,"And they are compiled into one reading such as:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"camera_ID: plate timestamp\n")),(0,r.kt)("p",null,"There should be always ",(0,r.kt)("strong",{parentName:"p"},"at least one")," space in between each part of the\nreading. Readings are separated by the commas, which may, but don't have to, be\naccompanied by whitespace around."),(0,r.kt)("h4",{id:"examples"},"Examples"),(0,r.kt)("p",null,"Few examples of the data from the cameras follow"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"10: ABC-12-34 1664608712, 289: XYZ-98-76 1665416417,\n25: ABC-12-34 1633078256 , 42: TryToCatchMe 1671602419,\n11: EL9-987 1679541338 ,2 : Foo-666 1683170082,42: YourMum 1683170082,\n42: TryToCatchMe 1671602419 , 1234: TryToCatchMe 1671602419,\n19: ABC-12-34 1664659649, 69:YouShould-not-pLaCe-4ny-expectations%on^the(input 1680307994,\n9 : 9B9-161 1665416417 , 10: 1a1-999 1671602419,1:lmao 1633078256,\n16: ABC-12-34 1664609012\n")),(0,r.kt)("h2",{id:"format-of-the-output"},"Format of the output"),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"All the examples consider using data from the example of the input.")),(0,r.kt)("p",null,"You are expected to print out the dates and cameras that has captured the\nlicense plate for each of them (in a sorted fashion)."),(0,r.kt)("p",null,"If there are multiple scans present and the timespan (i.e. time difference\nbetween the scans is bigger than 60 minutes, you should separate them by a\nnewline). For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"*** ABC-12-34 ***\n 25: Fri Oct 1 10:50:56 2021\n\n 10: Sat Oct 1 09:18:32 2022\n 16: Sat Oct 1 09:23:32 2022\n\n 19: Sat Oct 1 23:27:29 2022\n")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Since you are given the timestamp in a ",(0,r.kt)("inlineCode",{parentName:"p"},"time_t")," compatible type on UN","*","X, you\ncan safely use ",(0,r.kt)("inlineCode",{parentName:"p"},"ctime(3)")," for printing the timestamp as a ",(0,r.kt)("em",{parentName:"p"},"human readable")," time\nwhen outputting the date and time.")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"For a better readability you can include one more newline after the last line\nof the output.")),(0,r.kt)("h2",{id:"example-usage"},"Example usage"),(0,r.kt)("p",null,"You can also have a look at example usage of your program. We can run your\nprogram from the shell like"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ ./cams example_1.txt\n")),(0,r.kt)("p",null,"And it will produce an output:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"*** ABC-12-34 ***\n 25: Fri Oct 1 10:50:56 2021\n\n 10: Sat Oct 1 09:18:32 2022\n 16: Sat Oct 1 09:23:32 2022\n\n 19: Sat Oct 1 23:27:29 2022\n\n*** EL9-987 ***\n 11: Thu Mar 23 04:15:38 2023\n\n*** Foo-666 ***\n 2: Thu May 4 05:14:42 2023\n\n*** TryToCatchMe ***\n 42: Wed Dec 21 07:00:19 2022\n 42: Wed Dec 21 07:00:19 2022\n 1234: Wed Dec 21 07:00:19 2022\n\n*** XYZ-98-76 ***\n 289: Mon Oct 10 17:40:17 2022\n\n*** YouShould-not-pLaCe-4ny-expectations%on^the(input ***\n 69: Sat Apr 1 02:13:14 2023\n\n*** YourMum ***\n 42: Thu May 4 05:14:42 2023\n")),(0,r.kt)("h2",{id:"requirements-and-notes"},"Requirements and notes"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Define ",(0,r.kt)("strong",{parentName:"li"},"structures")," (and ",(0,r.kt)("strong",{parentName:"li"},"enumerations"),", if applicable) for the parsed\ninformation from the files."),(0,r.kt)("li",{parentName:"ul"},"For keeping the \u201crecords\u201d, use some ",(0,r.kt)("strong",{parentName:"li"},"dynamic")," data structure.",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Don't forget to consider pros and cons of using ",(0,r.kt)("em",{parentName:"li"},"specific")," data structures\nbefore going through implementing."))),(0,r.kt)("li",{parentName:"ul"},"You ",(0,r.kt)("strong",{parentName:"li"},"are not required")," to produce 1:1 output to the provided examples, they\nare just a hint to not waste your time tinkering with a user experience."),(0,r.kt)("li",{parentName:"ul"},"If any of the operations on the input files should fail,\n",(0,r.kt)("strong",{parentName:"li"},"you are expected to")," handle the situation ",(0,r.kt)("em",{parentName:"li"},"accordingly"),"."),(0,r.kt)("li",{parentName:"ul"},"Failures of any other common functions (e.g. functions used for memory\nmanagement) should be handled in ",(0,r.kt)("strong",{parentName:"li"},"the same way")," as they were in the\nhomeworks and seminars."),(0,r.kt)("li",{parentName:"ul"},"Your program ",(0,r.kt)("strong",{parentName:"li"},"must free")," all the resources before exiting.")),(0,r.kt)("div",{className:"footnotes"},(0,r.kt)("hr",{parentName:"div"}),(0,r.kt)("ol",{parentName:"div"},(0,r.kt)("li",{parentName:"ol",id:"fn-1"},"Subject to NDA.",(0,r.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/bb882650.671a659f.js b/assets/js/bb882650.2bca4416.js similarity index 68% rename from assets/js/bb882650.671a659f.js rename to assets/js/bb882650.2bca4416.js index 798c168..0df9fe6 100644 --- a/assets/js/bb882650.671a659f.js +++ b/assets/js/bb882650.2bca4416.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[8091],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),f=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=f(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=f(r),p=o,m=d["".concat(c,".").concat(p)]||d[p]||s[p]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=p;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var f=2;f{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>s,frontMatter:()=>a,metadata:()=>l,toc:()=>f});var n=r(7462),o=(r(7294),r(3905));const a={title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00",slug:"aoc-2022/3rd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,l={permalink:"/blog/aoc-2022/3rd-week",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/03-week-3.md",source:"@site/blog/aoc-2022/03-week-3.md",title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00:00.000Z",formattedDate:"July 6, 2023",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:11.565,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00",slug:"aoc-2022/3rd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"4th week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/4th-week"},nextItem:{title:"Sort the matrix diagonally",permalink:"/blog/leetcode/sort-diagonally"}},c={authorsImageUrls:[void 0]},f=[],u={toc:f},d="wrapper";function s(e){let{components:t,...r}=e;return(0,o.kt)(d,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the third week of ","[",(0,o.kt)("em",{parentName:"p"},"Advent of Code"),"]"," in Rust."))}s.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[8091],{3905:(e,t,r)=>{r.d(t,{Zo:()=>f,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},f=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,f=c(e,["components","mdxType","originalType","parentName"]),d=u(r),p=o,m=d["".concat(l,".").concat(p)]||d[p]||s[p]||a;return r?n.createElement(m,i(i({ref:t},f),{},{components:r})):n.createElement(m,i({ref:t},f))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=p;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[d]="string"==typeof e?e:o,i[1]=c;for(var u=2;u{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>s,frontMatter:()=>a,metadata:()=>c,toc:()=>u});var n=r(7462),o=(r(7294),r(3905));const a={title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00",slug:"aoc-2022/3rd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/3rd-week",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/03-week-3.md",source:"@site/blog/aoc-2022/03-week-3.md",title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00:00.000Z",formattedDate:"July 6, 2023",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:11.565,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00",slug:"aoc-2022/3rd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"4th week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/4th-week"},nextItem:{title:"Sort the matrix diagonally",permalink:"/blog/leetcode/sort-diagonally"}},l={authorsImageUrls:[void 0]},u=[],f={toc:u},d="wrapper";function s(e){let{components:t,...r}=e;return(0,o.kt)(d,(0,n.Z)({},f,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the third week of ","[",(0,o.kt)("em",{parentName:"p"},"Advent of Code"),"]"," in Rust."))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/cfa2b263.c19c407b.js b/assets/js/cfa2b263.0d6e56da.js similarity index 99% rename from assets/js/cfa2b263.c19c407b.js rename to assets/js/cfa2b263.0d6e56da.js index bfdac66..598161c 100644 --- a/assets/js/cfa2b263.c19c407b.js +++ b/assets/js/cfa2b263.0d6e56da.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3086],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),d=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=d(n),u=i,h=m["".concat(l,".").concat(u)]||m[u]||c[u]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:i,r[1]=s;for(var d=2;d{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const o={title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15",slug:"leetcode/sort-diagonally",authors:"mf",tags:["cpp","leetcode","iterators"],hide_table_of_contents:!1},r=void 0,s={permalink:"/blog/leetcode/sort-diagonally",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/leetcode/sort-matrix-diagonally.md",source:"@site/blog/leetcode/sort-matrix-diagonally.md",title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15:00.000Z",formattedDate:"March 4, 2023",tags:[{label:"cpp",permalink:"/blog/tags/cpp"},{label:"leetcode",permalink:"/blog/tags/leetcode"},{label:"iterators",permalink:"/blog/tags/iterators"}],readingTime:16.99,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15",slug:"leetcode/sort-diagonally",authors:"mf",tags:["cpp","leetcode","iterators"],hide_table_of_contents:!1},prevItem:{title:"3rd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/3rd-week"},nextItem:{title:"2nd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/2nd-week"}},l={authorsImageUrls:[void 0]},d=[{value:"Problem description",id:"problem-description",level:2},{value:"Example",id:"example",level:3},{value:"Skeleton and initial adjustments",id:"skeleton-and-initial-adjustments",level:2},{value:"Na\xefve solution",id:"na\xefve-solution",level:2},{value:"Implementing the diagonals",id:"implementing-the-diagonals",level:2},{value:"Iterating over diagonals",id:"iterating-over-diagonals",level:3},{value:"Implementing the iterator over diagonals",id:"implementing-the-iterator-over-diagonals",level:3},{value:"Implementing the diagonal itself",id:"implementing-the-diagonal-itself",level:2},{value:"Implementing diagonal_iter",id:"implementing-diagonal_iter",level:3}],p={toc:d},m="wrapper";function c(e){let{components:t,...n}=e;return(0,i.kt)(m,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Let's try to solve one of the LeetCode challenges in easy and hard mode at the\nsame time."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Link to the problem: ",(0,i.kt)("a",{parentName:"li",href:"https://leetcode.com/problems/sort-the-matrix-diagonally/"},"https://leetcode.com/problems/sort-the-matrix-diagonally/"))),(0,i.kt)("h2",{id:"problem-description"},"Problem description"),(0,i.kt)("p",null,"A ",(0,i.kt)("strong",{parentName:"p"},"matrix diagonal")," is a diagonal line of cells starting from some cell in\neither the topmost row or leftmost column and going in the bottom-right direction\nuntil reaching the matrix's end. For example, the ",(0,i.kt)("strong",{parentName:"p"},"matrix diagonal")," starting\nfrom ",(0,i.kt)("inlineCode",{parentName:"p"},"mat[2][0]"),", where ",(0,i.kt)("inlineCode",{parentName:"p"},"mat")," is a ",(0,i.kt)("inlineCode",{parentName:"p"},"6 x 3")," matrix, includes cells ",(0,i.kt)("inlineCode",{parentName:"p"},"mat[2][0]"),",\n",(0,i.kt)("inlineCode",{parentName:"p"},"mat[3][1]"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"mat[4][2]"),"."),(0,i.kt)("p",null,"Given an ",(0,i.kt)("inlineCode",{parentName:"p"},"m x n")," matrix ",(0,i.kt)("inlineCode",{parentName:"p"},"mat")," of integers, sort each matrix diagonal in ascending\norder and return the resulting matrix."),(0,i.kt)("h3",{id:"example"},"Example"),(0,i.kt)("p",null,(0,i.kt)("img",{parentName:"p",src:"https://assets.leetcode.com/uploads/2020/01/21/1482_example_1_2.png",alt:"Image describing the problem"})),(0,i.kt)("h2",{id:"skeleton-and-initial-adjustments"},"Skeleton and initial adjustments"),(0,i.kt)("p",null,"We are given the following skeleton for the C++ and the given challenge:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class Solution {\npublic:\n vector> diagonalSort(vector>& mat) {\n \n }\n};\n")),(0,i.kt)("p",null,"The task is to sort the passed matrix diagonally and then return it. First of all,\nI don't like to solve this in a web browser, so we'll need to adjust it accordingly\nfor running it locally. We'll start by including the ",(0,i.kt)("inlineCode",{parentName:"p"},"vector")," header and using\nfully-qualified namespaces",(0,i.kt)("sup",{parentName:"p",id:"fnref-1-b611be"},(0,i.kt)("a",{parentName:"sup",href:"#fn-1-b611be",className:"footnote-ref"},"1"))," and also adding few tests:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"#include \n#include \n\nusing matrix = std::vector>;\n\nclass Solution {\npublic:\n matrix diagonalSort(matrix& mat)\n {\n }\n};\n\nstatic void test_case_1()\n{\n // Input: mat = [[3,3,1,1],[2,2,1,2],[1,1,1,2]]\n // Output: [[1,1,1,1],[1,2,2,2],[1,2,3,3]]\n\n Solution s;\n assert((s.diagonalSort(std::vector { std::vector { 3, 3, 1, 1 },\n std::vector { 2, 2, 1, 2 },\n std::vector { 1, 1, 1, 2 } })\n == std::vector { std::vector { 1, 1, 1, 1 },\n std::vector { 1, 2, 2, 2 },\n std::vector { 1, 2, 3, 3 } }));\n}\n\nstatic void test_case_2()\n{\n // Input: mat =\n // [[11,25,66,1,69,7],[23,55,17,45,15,52],[75,31,36,44,58,8],[22,27,33,25,68,4],[84,28,14,11,5,50]]\n // Output:\n // [[5,17,4,1,52,7],[11,11,25,45,8,69],[14,23,25,44,58,15],[22,27,31,36,50,66],[84,28,75,33,55,68]]\n\n Solution s;\n assert((s.diagonalSort(std::vector { std::vector { 11, 25, 66, 1, 69, 7 },\n std::vector { 23, 55, 17, 45, 15, 52 },\n std::vector { 75, 31, 36, 44, 58, 8 },\n std::vector { 22, 27, 33, 25, 68, 4 },\n std::vector { 84, 28, 14, 11, 5, 50 } })\n == std::vector { std::vector { 5, 17, 4, 1, 52, 7 },\n std::vector { 11, 11, 25, 45, 8, 69 },\n std::vector { 14, 23, 25, 44, 58, 15 },\n std::vector { 22, 27, 31, 36, 50, 66 },\n std::vector { 84, 28, 75, 33, 55, 68 } }));\n}\n\nint main()\n{\n test_case_1();\n test_case_2();\n\n return 0;\n}\n")),(0,i.kt)("p",null,"We need to return the matrix, but we're given a reference to the input matrix. We\ncan easily abuse the C++ here and just switch the reference to value, this way\nthe matrix will be copied when passed to the function, we can sort the copy and\njust return it back. And we also get yelled by the compiler for the fact that the\nmethod doesn't return anything yet, so to make it \u201cshut up\u201d we will just return\nthe input for now:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"- matrix diagonalSort(matrix& mat)\n+ matrix diagonalSort(matrix mat)\n {\n+ return mat;\n }\n")),(0,i.kt)("p",null,"Now, we get the copy and we're good to go."),(0,i.kt)("h2",{id:"na\xefve-solution"},"Na\xefve solution"),(0,i.kt)("p",null,"As you may know, C++ offers a plethora of functions that can be used to your\nadvantage, given that you know how to \u201cbend\u201d the data structures accordingly."),(0,i.kt)("p",null,"What does that mean for us? Well, we have an ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort"),", we can use it, right?\nLet's have a look at it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"template< class RandomIt >\nvoid sort( RandomIt first, RandomIt last );\n")),(0,i.kt)("p",null,"This overload is more than we need. What does it do? It just sorts the elements\nin the range ",(0,i.kt)("inlineCode",{parentName:"p"},"[first, last)")," using ",(0,i.kt)("inlineCode",{parentName:"p"},"operator<")," on them. We can't sort the whole\nmatrix using this, but\u2026 we can sort just \xbbone\xab diagonal without doing much work\non our end."),(0,i.kt)("p",null,"What is the ",(0,i.kt)("inlineCode",{parentName:"p"},"RandomIt")," type though? If we look more into the documentation, we\ncan easily find the requirements for it and also learn that it's a ",(0,i.kt)("em",{parentName:"p"},"random access"),"\n",(0,i.kt)("em",{parentName:"p"},"iterator")," and allows swapping its values at the same time."),(0,i.kt)("admonition",{title:"Random access iterator",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"What is the ",(0,i.kt)("em",{parentName:"p"},"random access iterator")," though? We can find it in a documentation\nand see the following description:"),(0,i.kt)("blockquote",{parentName:"admonition"},(0,i.kt)("p",{parentName:"blockquote"},"A ",(0,i.kt)("strong",{parentName:"p"},"LegacyRandomAccessIterator")," is a ",(0,i.kt)("a",{parentName:"p",href:"https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator"},"LegacyBidirectionalIterator"),"\nthat can be moved to point to any element in constant time.")),(0,i.kt)("p",{parentName:"admonition"},"After that we can see all the requirements for it being listed. I don't feel like\nreading them right now, so we will just use it and see where the compilation blows\nup, i.e. \u201c",(0,i.kt)("em",{parentName:"p"},"compiler-assisted development"),"\u201d",(0,i.kt)("sup",{parentName:"p",id:"fnref-2-b611be"},(0,i.kt)("a",{parentName:"sup",href:"#fn-2-b611be",className:"footnote-ref"},"2"))," if you will ;)")),(0,i.kt)("p",null,"Now we know that we can use ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort")," to sort the diagonal itself, but we also\nneed to get the diagonals somehow. I'm rather lazy, so I'll just delegate it to\nsomeone else",(0,i.kt)("sup",{parentName:"p",id:"fnref-3-b611be"},(0,i.kt)("a",{parentName:"sup",href:"#fn-3-b611be",className:"footnote-ref"},"3")),". And that way we get"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"matrix diagonalSort(matrix mat)\n{\n // we iterate over the diagonals\n for (auto d : diagonals(mat)) {\n // and we sort each diagonal\n std::sort(d.begin(), d.end());\n }\n\n // we take the matrix by copy, so we can sort in-situ and return the copy\n // that we sorted\n return mat;\n}\n")),(0,i.kt)("p",null,"This solution looks very simple, doesn't it? Well, cause it is.\nLet's try compiling it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"matrix-sort.cpp:11:23: error: use of undeclared identifier 'diagonals' [clang-diagnostic-error]\n for (auto d : diagonals(mat)) {\n ^\nFound compiler error(s).\nmake: *** [makefile:14: tidy] Error 1\n")),(0,i.kt)("p",null,"OK, seems about right. We haven't implemented the ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," yet. And based on\nwhat we've written so far, we need a function or a class ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," that will\ngive us the diagonals we need."),(0,i.kt)("h2",{id:"implementing-the-diagonals"},"Implementing the ",(0,i.kt)("inlineCode",{parentName:"h2"},"diagonals")),(0,i.kt)("p",null,"Cool, so we need the function that will let us go through each and every diagonal\nin our matrix. We use the ",(0,i.kt)("em",{parentName:"p"},"for-range")," loop, so whatever we get back from the\n",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," must support ",(0,i.kt)("inlineCode",{parentName:"p"},".begin()")," and ",(0,i.kt)("inlineCode",{parentName:"p"},".end()"),". Since I am a masochist, we will\ndo such functionality for a matrix of any type, not just the ",(0,i.kt)("inlineCode",{parentName:"p"},"int")," from the challenge."),(0,i.kt)("p",null,"As I said, we need to be able to"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"construct the object"),(0,i.kt)("li",{parentName:"ul"},"get the beginning"),(0,i.kt)("li",{parentName:"ul"},"get the end (the \u201csentinel\u201d)")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"template \nclass diagonals {\n using matrix_t = std::vector>;\n\n matrix_t& _matrix;\n\npublic:\n diagonals(matrix_t& m)\n : _matrix(m)\n {\n }\n diagonals_iter begin()\n {\n /* TODO */\n }\n diagonals_iter end()\n {\n /* TODO */\n }\n};\n")),(0,i.kt)("p",null,"Now we have a ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," that we can use to go through the diagonals. We haven't\nimplemented the core of it yet. Let's go through what we have for now."),(0,i.kt)("p",null,"We have a templated class with templated ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," that is used as a placeholder for any\ntype we would store in the matrix. Because I'm lazy, I have defined the ",(0,i.kt)("inlineCode",{parentName:"p"},"matrix_t"),"\ntype that is a \u201cshortcut\u201d for ",(0,i.kt)("inlineCode",{parentName:"p"},"std::vector>"),", so I don't have to\ntype it out all the time. Of course, we need to store the matrix, we are given,\nas a private attribute. And then just have the constructor and the 2 methods we\nneed for the ",(0,i.kt)("em",{parentName:"p"},"for-range"),"."),(0,i.kt)("h3",{id:"iterating-over-diagonals"},"Iterating over diagonals"),(0,i.kt)("p",null,"Now that we have an object that will allow us to iterate through the diagonals,\nwe need to implement the iterating itself. We need to go through all of them, so\nwe have multiple options how to do so. I have decided to start from the \u201cmain\u201d\ndiagonal that starts at ",(0,i.kt)("inlineCode",{parentName:"p"},"(0, 0)")," index and then proceed with the diagonals starting\nin the first row, followed by the rest of the diagonals in the first column."),(0,i.kt)("p",null,"We need to be able to tell that we've iterated through all of them, and also we\nneed to know which diagonal is next. For that purpose we will pass the indices\nof the first cell on the diagonal. That way we can always tell how to move forward."),(0,i.kt)("p",null,"We will start by updating the ",(0,i.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"end")," to reflect our choice accordingly."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"diagonals_iter begin() { return diagonals_iter { _matrix, 0, 0 }; }\ndiagonals_iter end() { return diagonals_iter { _matrix, 0, _matrix.size() }; }\n")),(0,i.kt)("p",null,"For the ",(0,i.kt)("inlineCode",{parentName:"p"},"begin")," we return the first diagonal that starts at ",(0,i.kt)("inlineCode",{parentName:"p"},"(0, 0)"),". And because\nwe have decided to do the diagonals in the first column at the end, the first\ndiagonal that is not a valid one is the one at ",(0,i.kt)("inlineCode",{parentName:"p"},"(0, height)"),". Apart from the\nindices, we also need to pass reference to the matrix itself."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"You may have noticed that we also include the diagonals that have length 1,\nspecifically the ones at ",(0,i.kt)("inlineCode",{parentName:"p"},"(0, height - 1)")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"(width - 1, 0)"),". We are implementing\nan iterator that ",(0,i.kt)("strong",{parentName:"p"},"should not")," care about the way it's being used. Therefore, we\ndon't care about the fact they don't need to be sorted.")),(0,i.kt)("p",null,"Cool, let's leave the iterator itself to someone else, right?",(0,i.kt)("sup",{parentName:"p",id:"fnref-4-b611be"},(0,i.kt)("a",{parentName:"sup",href:"#fn-4-b611be",className:"footnote-ref"},"4"))),(0,i.kt)("h3",{id:"implementing-the-iterator-over-diagonals"},"Implementing the iterator over diagonals"),(0,i.kt)("p",null,"We can start with a simple skeleton based on the information that we pass from\nthe ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals"),". Also to utilize the ",(0,i.kt)("inlineCode",{parentName:"p"},"matrix_t")," and also contain implementation\ndetails hidden away, we will put this code into the ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," class."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class diagonals_iter {\n matrix_t& m;\n std::size_t x;\n std::size_t y;\n\npublic:\n diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)\n : m(matrix)\n , x(x)\n , y(y)\n {\n }\n};\n")),(0,i.kt)("p",null,"In this case we will be implementing a \u201csimple\u201d forward iterator, so we don't\nneed to implement a lot. Notably it will be:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"inequality operator (we need to know when we reach the end and have nothing to\niterate over)"),(0,i.kt)("li",{parentName:"ul"},"preincrementation operator (we need to be able to move around the iterable)"),(0,i.kt)("li",{parentName:"ul"},"dereference operator (we need to be able to retrieve the objects we iterate\nover)")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class diagonals_iter {\n matrix_t& m;\n std::size_t x;\n std::size_t y;\n\npublic:\n diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)\n : m(matrix)\n , x(x)\n , y(y)\n {\n }\n\n bool operator!=(const diagonals_iter& rhs) const\n {\n // iterators are not equal if they reference different matrices, or\n // their positions differ\n return m != rhs.m || x != rhs.x || y != rhs.y;\n }\n\n diagonals_iter& operator++()\n {\n if (y != 0) {\n // iterating through diagonals down the first column\n y++;\n return *this;\n }\n\n // iterating the diagonals along the first row\n x++;\n if (x == m.front().size()) {\n // switching to diagonals in the first column\n x = 0;\n y++;\n }\n\n return *this;\n }\n\n diagonal operator*() const { return diagonal { m, x, y }; }\n};\n")),(0,i.kt)("p",null,"Let's go one-by-one. Inequality operator is rather simple, just compare iterator's\nattributes field-by-field. If you think about it, checking inequality of two 2D\nvectors may be a bit inefficient, therefore, we can swap around and check it as\na last thing."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"- return m != rhs.m || x != rhs.x || y != rhs.y;\n+ return x != rhs.x || y != rhs.y || m != rhs.m;\n")),(0,i.kt)("p",null,"Preincrementation is where the magic happens. If you have a better look, you can\nsee two branches of this operation:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"When ",(0,i.kt)("inlineCode",{parentName:"li"},"y != 0")," (we're iterating over the diagonals in the first column)\nIn this case, we just bump the row and we're done."),(0,i.kt)("li",{parentName:"ol"},"When ",(0,i.kt)("inlineCode",{parentName:"li"},"y == 0")," (we're iterating over the diagonals in the first row)\nIn this case, we bump the column and check if we haven't gotten out of bounds,\ni.e. the end of the first row. If we get out of the bounds, we're continuing\nwith the second diagonal in the first column.")),(0,i.kt)("p",null,"Dereferencing the iterator must \u201cyield\u201d something. In our case it will be the\ndiagonal that we want to sort. For sorting we need just the iterators that can\nmove around said diagonal. The simplest thing, we can do, is to delegate it to\nsomething else. In our case it will be a class called ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonal"),"."),(0,i.kt)("h2",{id:"implementing-the-diagonal-itself"},"Implementing the ",(0,i.kt)("inlineCode",{parentName:"h2"},"diagonal")," itself"),(0,i.kt)("p",null,"After implementing the iterator over diagonals, we know that all we need to describe\na diagonal is the matrix itself and the \u201cstart\u201d of the diagonal (row and column).\nAnd we also know that the diagonal must provide some iterators for the ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort"),"\nfunction. We can start with the following skeleton:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"template \nclass diagonal {\n using matrix_t = std::vector>;\n\n matrix_t& matrix;\n std::size_t x;\n std::size_t y;\n\npublic:\n diagonal(matrix_t& matrix, std::size_t x, std::size_t y)\n : matrix(matrix)\n , x(x)\n , y(y)\n {\n }\n\n diagonal_iter begin() const { return diagonal_iter { matrix, x, y }; }\n\n diagonal_iter end() const\n {\n auto max_x = matrix[y].size();\n auto max_y = matrix.size();\n\n // we need to find the distance in which we get out of bounds (either in\n // column or row)\n auto steps = std::min(max_x - x, max_y - y);\n\n return diagonal_iter { matrix, x + steps, y + steps };\n }\n};\n")),(0,i.kt)("p",null,"Initialization is rather simple, we just \u201ckeep\u201d the stuff we get, ",(0,i.kt)("inlineCode",{parentName:"p"},"begin")," is the\nsimplest, we just delegate."),(0,i.kt)("p",null,"In case of the ",(0,i.kt)("inlineCode",{parentName:"p"},"end"),", it gets more complicated. We need to know where is the \u201cend\u201d\nof the diagonal. Since ",(0,i.kt)("inlineCode",{parentName:"p"},"end")," should point to the first element \u201cafter\u201d the iterable,\nwe know that it's the first position of the iterator where either ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," becomes\n",(0,i.kt)("inlineCode",{parentName:"p"},"matrix.size()")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," becomes ",(0,i.kt)("inlineCode",{parentName:"p"},"matrix[y].size()"),". Also we are moving along diagonal,\nduh, therefore we can deduce the first \u201cposition\u201d afterwards by minimal amount of\nsteps to get out of the any column or row, hence ",(0,i.kt)("inlineCode",{parentName:"p"},"std::min(max_x - x, max_y - y)"),".\nFinal position is then computed simply by adding the steps to the beginning of\nthe diagonal."),(0,i.kt)("p",null,"Now we just need to finish the iterator for the diagonal itself and we're done."),(0,i.kt)("h3",{id:"implementing-diagonal_iter"},"Implementing ",(0,i.kt)("inlineCode",{parentName:"h3"},"diagonal_iter")),(0,i.kt)("p",null,"This part is the hardest from all we need to do. It's because of the requirements\nof the ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort")," that requires us to implement a ",(0,i.kt)("em",{parentName:"p"},"random access iterator"),". I have\nbriefly described it above, and \u201cin a nutshell\u201d it means that we need to implement\nan iterator that can move in constant time along the diagonal in any amount of\nsteps."),(0,i.kt)("p",null,"Let's go through all of the functionality that our iterator needs to support to\nbe used in ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort"),". We need the usual operations like:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"equality/inequality"),(0,i.kt)("li",{parentName:"ul"},"incrementation"),(0,i.kt)("li",{parentName:"ul"},"dereferencing")),(0,i.kt)("p",null,"We will also add all the types that our iterator uses with the category of the\niterator, i.e. what interface it supports:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class diagonal_iter {\n // we need to keep reference to the matrix itself\n matrix_t& m;\n\n // we need to be able to tell our current position\n std::size_t x;\n std::size_t y;\n\npublic:\n using difference_type = std::ptrdiff_t;\n using value_type = T;\n using pointer = T*;\n using reference = T&;\n using iterator_category = std::random_access_iterator_tag;\n\n diagonal_iter(matrix_t& matrix,\n std::size_t x,\n std::size_t y)\n : m(matrix)\n , x(x)\n , y(y)\n {\n }\n\n bool operator==(const diagonal_iter& rhs) const\n {\n return x == rhs.x && y == rhs.y && m == rhs.m;\n }\n\n diagonal_iter& operator++()\n {\n // we are moving along the diagonal, so we increment both \u2039x\u203a and \u2039y\u203a at\n // the same time\n x++;\n y++;\n return *this;\n }\n\n reference operator*() const { return m[y][x]; }\n};\n")),(0,i.kt)("p",null,"This is pretty similar to the previous iterator, but now we need to implement the\nremaining requirements of the ",(0,i.kt)("em",{parentName:"p"},"random access iterator"),". Let's see what those are:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"decrementation - cause we need to be able to move backwards too, since ",(0,i.kt)("em",{parentName:"li"},"random "),(0,i.kt)("em",{parentName:"li"},"access iterator")," extends the interface of ",(0,i.kt)("em",{parentName:"li"},"bidirectional iterator")),(0,i.kt)("li",{parentName:"ul"},"moving the iterator in either direction by steps given as an integer"),(0,i.kt)("li",{parentName:"ul"},"being able to tell the distance between two iterators"),(0,i.kt)("li",{parentName:"ul"},"define an ordering on the iterators")),(0,i.kt)("p",null,"Let's fill them in:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class diagonal_iter {\n // we need to keep reference to the matrix itself\n matrix_t& m;\n\n // we need to be able to tell our current position\n std::size_t x;\n std::size_t y;\n\npublic:\n using difference_type = std::ptrdiff_t;\n using value_type = T;\n using pointer = T*;\n using reference = T&;\n using iterator_category = std::random_access_iterator_tag;\n\n diagonal_iter(matrix_t& matrix,\n std::size_t x,\n std::size_t y)\n : m(matrix)\n , x(x)\n , y(y)\n {\n }\n\n bool operator==(const diagonal_iter& rhs) const\n {\n return x == rhs.x && y == rhs.y && m == rhs.m;\n }\n\n diagonal_iter& operator++()\n {\n // we are moving along the diagonal, so we increment both \u2039x\u203a and \u2039y\u203a at\n // the same time\n x++;\n y++;\n return *this;\n }\n\n reference operator*() const { return m[y][x]; }\n\n // exactly opposite to the incrementation\n diagonal_iter operator--()\n {\n x--;\n y--;\n return *this;\n }\n\n // moving \u2039n\u203a steps back is same as calling decrementation \u2039n\u203a-times, so we\n // can just return a new iterator and subtract \u2039n\u203a from both coordinates in\n // the matrix\n diagonal_iter operator-(difference_type n) const\n {\n return diagonal_iter { m, x - n, y - n };\n }\n\n // here we assume that we are given two iterators on the same diagonal\n difference_type operator-(const diagonal_iter& rhs) const\n {\n assert(m == rhs.m);\n return x - rhs.x;\n }\n\n // counterpart of moving \u2039n\u203a steps backwards\n diagonal_iter operator+(difference_type n) const\n {\n return diagonal_iter { m, x + n, y + n };\n }\n\n // we compare the coordinates, and also assume that those 2 iterators are\n // lying on the same diagonal\n bool operator<(const diagonal_iter& rhs) const\n {\n assert(m == rhs.m);\n return x < rhs.x && y < rhs.y;\n }\n};\n")),(0,i.kt)("p",null,"At this point we could probably try and compile it, right? If we do so, we will\nget yelled at by a compiler for the following reasons:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type 'diagonal::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\n __last = __next;\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1817:11: note: in instantiation of function template specialization 'std::__unguarded_linear_insert::diagonal_iter, __gnu_cxx::__ops::_Val_less_iter>' requested here\n std::__unguarded_linear_insert(__i,\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1849:9: note: in instantiation of function template specialization 'std::__insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__insertion_sort(__first, __first + int(_S_threshold), __comp);\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization 'std::__final_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__final_insertion_sort(__first, __last, __comp);\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\n ^\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort::diagonal_iter>' requested here\n std::sort(d.begin(), d.end());\n ^\nmatrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal::matrix_t &' (aka 'vector> &')\n matrix_t& m;\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1830:2: error: no matching function for call to '__unguarded_linear_insert' [clang-diagnostic-error]\n std::__unguarded_linear_insert(__i,\n ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1850:9: note: in instantiation of function template specialization 'std::__unguarded_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__unguarded_insertion_sort(__first + int(_S_threshold), __last,\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization 'std::__final_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__final_insertion_sort(__first, __last, __comp);\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\n ^\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort::diagonal_iter>' requested here\n std::sort(d.begin(), d.end());\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1782:5: note: candidate template ignored: substitution failure [with _RandomAccessIterator = diagonal::diagonal_iter, _Compare = __gnu_cxx::__ops::_Val_less_iter]\n __unguarded_linear_insert(_RandomAccessIterator __last,\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1923:11: error: object of type 'diagonal::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\n __last = __cut;\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1937:9: note: in instantiation of function template specialization 'std::__introsort_loop::diagonal_iter, long, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__introsort_loop(__first, __last,\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\n ^\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort::diagonal_iter>' requested here\n std::sort(d.begin(), d.end());\n ^\nmatrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal::matrix_t &' (aka 'vector> &')\n matrix_t& m;\n ^\n")),(0,i.kt)("p",null,"That's a lot of noise, isn't it? Let's focus on the important parts:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type 'diagonal::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\n\u2026\nmatrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal::matrix_t &' (aka 'vector> &')\n matrix_t& m;\n ^\n")),(0,i.kt)("p",null,"Ah! We have a reference in our iterator, and this prevents us from having a copy\nassignment operator (that is used \u201csomewhere\u201d in the sorting algorithm). Well\u2026\nLet's just wrap it!"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"# we need to keep a different type than reference\n- matrix_t& m;\n+ std::reference_wrapper m;\n\n# in comparison we need to get the reference out of the wrapper first\n- return x == rhs.x && y == rhs.y && m == rhs.m;\n+ return x == rhs.x && y == rhs.y && m.get() == rhs.m.get();\n\n# same when we return a reference to the \u201ccell\u201d in the matrix\n- reference operator*() const { return m[y][x]; }\n+ reference operator*() const { return m.get()[y][x]; }\n\n# and finally in the assertions that we set for the \u201cdistance\u201d and \u201cless than\u201d\n- assert(m == rhs.m);\n+ assert(m.get() == rhs.m.get());\n")),(0,i.kt)("p",null,"We're done now! We have written an iterator over diagonals for a 2D ",(0,i.kt)("inlineCode",{parentName:"p"},"vector"),". You can have a look at the final result ",(0,i.kt)("a",{parentName:"p",href:"pathname:///files/blog/leetcode/sort-matrix-diagonally/matrix-sort.cpp"},"here"),"."),(0,i.kt)("div",{className:"footnotes"},(0,i.kt)("hr",{parentName:"div"}),(0,i.kt)("ol",{parentName:"div"},(0,i.kt)("li",{parentName:"ol",id:"fn-1-b611be"},"just because I'm used to it and don't care about your opinion ;)",(0,i.kt)("a",{parentName:"li",href:"#fnref-1-b611be",className:"footnote-backref"},"\u21a9")),(0,i.kt)("li",{parentName:"ol",id:"fn-2-b611be"},"exercise at your own risk",(0,i.kt)("a",{parentName:"li",href:"#fnref-2-b611be",className:"footnote-backref"},"\u21a9")),(0,i.kt)("li",{parentName:"ol",id:"fn-3-b611be"},"me in 5 minutes in fact, but don't make me scared",(0,i.kt)("a",{parentName:"li",href:"#fnref-3-b611be",className:"footnote-backref"},"\u21a9")),(0,i.kt)("li",{parentName:"ol",id:"fn-4-b611be"},"me in the next section\u2026",(0,i.kt)("a",{parentName:"li",href:"#fnref-4-b611be",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3086],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),d=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=d(n),u=i,h=m["".concat(l,".").concat(u)]||m[u]||c[u]||o;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:i,r[1]=s;for(var d=2;d{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));const o={title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15",slug:"leetcode/sort-diagonally",authors:"mf",tags:["cpp","leetcode","iterators"],hide_table_of_contents:!1},r=void 0,s={permalink:"/blog/leetcode/sort-diagonally",editUrl:"https://github.com/mfocko/blog/tree/main/blog/leetcode/sort-matrix-diagonally.md",source:"@site/blog/leetcode/sort-matrix-diagonally.md",title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15:00.000Z",formattedDate:"March 4, 2023",tags:[{label:"cpp",permalink:"/blog/tags/cpp"},{label:"leetcode",permalink:"/blog/tags/leetcode"},{label:"iterators",permalink:"/blog/tags/iterators"}],readingTime:16.99,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"Sort the matrix diagonally",description:"Compiler assisted development.",date:"2023-03-04T23:15",slug:"leetcode/sort-diagonally",authors:"mf",tags:["cpp","leetcode","iterators"],hide_table_of_contents:!1},prevItem:{title:"3rd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/3rd-week"},nextItem:{title:"2nd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/2nd-week"}},l={authorsImageUrls:[void 0]},d=[{value:"Problem description",id:"problem-description",level:2},{value:"Example",id:"example",level:3},{value:"Skeleton and initial adjustments",id:"skeleton-and-initial-adjustments",level:2},{value:"Na\xefve solution",id:"na\xefve-solution",level:2},{value:"Implementing the diagonals",id:"implementing-the-diagonals",level:2},{value:"Iterating over diagonals",id:"iterating-over-diagonals",level:3},{value:"Implementing the iterator over diagonals",id:"implementing-the-iterator-over-diagonals",level:3},{value:"Implementing the diagonal itself",id:"implementing-the-diagonal-itself",level:2},{value:"Implementing diagonal_iter",id:"implementing-diagonal_iter",level:3}],p={toc:d},m="wrapper";function c(e){let{components:t,...n}=e;return(0,i.kt)(m,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Let's try to solve one of the LeetCode challenges in easy and hard mode at the\nsame time."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Link to the problem: ",(0,i.kt)("a",{parentName:"li",href:"https://leetcode.com/problems/sort-the-matrix-diagonally/"},"https://leetcode.com/problems/sort-the-matrix-diagonally/"))),(0,i.kt)("h2",{id:"problem-description"},"Problem description"),(0,i.kt)("p",null,"A ",(0,i.kt)("strong",{parentName:"p"},"matrix diagonal")," is a diagonal line of cells starting from some cell in\neither the topmost row or leftmost column and going in the bottom-right direction\nuntil reaching the matrix's end. For example, the ",(0,i.kt)("strong",{parentName:"p"},"matrix diagonal")," starting\nfrom ",(0,i.kt)("inlineCode",{parentName:"p"},"mat[2][0]"),", where ",(0,i.kt)("inlineCode",{parentName:"p"},"mat")," is a ",(0,i.kt)("inlineCode",{parentName:"p"},"6 x 3")," matrix, includes cells ",(0,i.kt)("inlineCode",{parentName:"p"},"mat[2][0]"),",\n",(0,i.kt)("inlineCode",{parentName:"p"},"mat[3][1]"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"mat[4][2]"),"."),(0,i.kt)("p",null,"Given an ",(0,i.kt)("inlineCode",{parentName:"p"},"m x n")," matrix ",(0,i.kt)("inlineCode",{parentName:"p"},"mat")," of integers, sort each matrix diagonal in ascending\norder and return the resulting matrix."),(0,i.kt)("h3",{id:"example"},"Example"),(0,i.kt)("p",null,(0,i.kt)("img",{parentName:"p",src:"https://assets.leetcode.com/uploads/2020/01/21/1482_example_1_2.png",alt:"Image describing the problem"})),(0,i.kt)("h2",{id:"skeleton-and-initial-adjustments"},"Skeleton and initial adjustments"),(0,i.kt)("p",null,"We are given the following skeleton for the C++ and the given challenge:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class Solution {\npublic:\n vector> diagonalSort(vector>& mat) {\n \n }\n};\n")),(0,i.kt)("p",null,"The task is to sort the passed matrix diagonally and then return it. First of all,\nI don't like to solve this in a web browser, so we'll need to adjust it accordingly\nfor running it locally. We'll start by including the ",(0,i.kt)("inlineCode",{parentName:"p"},"vector")," header and using\nfully-qualified namespaces",(0,i.kt)("sup",{parentName:"p",id:"fnref-1-b611be"},(0,i.kt)("a",{parentName:"sup",href:"#fn-1-b611be",className:"footnote-ref"},"1"))," and also adding few tests:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"#include \n#include \n\nusing matrix = std::vector>;\n\nclass Solution {\npublic:\n matrix diagonalSort(matrix& mat)\n {\n }\n};\n\nstatic void test_case_1()\n{\n // Input: mat = [[3,3,1,1],[2,2,1,2],[1,1,1,2]]\n // Output: [[1,1,1,1],[1,2,2,2],[1,2,3,3]]\n\n Solution s;\n assert((s.diagonalSort(std::vector { std::vector { 3, 3, 1, 1 },\n std::vector { 2, 2, 1, 2 },\n std::vector { 1, 1, 1, 2 } })\n == std::vector { std::vector { 1, 1, 1, 1 },\n std::vector { 1, 2, 2, 2 },\n std::vector { 1, 2, 3, 3 } }));\n}\n\nstatic void test_case_2()\n{\n // Input: mat =\n // [[11,25,66,1,69,7],[23,55,17,45,15,52],[75,31,36,44,58,8],[22,27,33,25,68,4],[84,28,14,11,5,50]]\n // Output:\n // [[5,17,4,1,52,7],[11,11,25,45,8,69],[14,23,25,44,58,15],[22,27,31,36,50,66],[84,28,75,33,55,68]]\n\n Solution s;\n assert((s.diagonalSort(std::vector { std::vector { 11, 25, 66, 1, 69, 7 },\n std::vector { 23, 55, 17, 45, 15, 52 },\n std::vector { 75, 31, 36, 44, 58, 8 },\n std::vector { 22, 27, 33, 25, 68, 4 },\n std::vector { 84, 28, 14, 11, 5, 50 } })\n == std::vector { std::vector { 5, 17, 4, 1, 52, 7 },\n std::vector { 11, 11, 25, 45, 8, 69 },\n std::vector { 14, 23, 25, 44, 58, 15 },\n std::vector { 22, 27, 31, 36, 50, 66 },\n std::vector { 84, 28, 75, 33, 55, 68 } }));\n}\n\nint main()\n{\n test_case_1();\n test_case_2();\n\n return 0;\n}\n")),(0,i.kt)("p",null,"We need to return the matrix, but we're given a reference to the input matrix. We\ncan easily abuse the C++ here and just switch the reference to value, this way\nthe matrix will be copied when passed to the function, we can sort the copy and\njust return it back. And we also get yelled by the compiler for the fact that the\nmethod doesn't return anything yet, so to make it \u201cshut up\u201d we will just return\nthe input for now:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"- matrix diagonalSort(matrix& mat)\n+ matrix diagonalSort(matrix mat)\n {\n+ return mat;\n }\n")),(0,i.kt)("p",null,"Now, we get the copy and we're good to go."),(0,i.kt)("h2",{id:"na\xefve-solution"},"Na\xefve solution"),(0,i.kt)("p",null,"As you may know, C++ offers a plethora of functions that can be used to your\nadvantage, given that you know how to \u201cbend\u201d the data structures accordingly."),(0,i.kt)("p",null,"What does that mean for us? Well, we have an ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort"),", we can use it, right?\nLet's have a look at it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"template< class RandomIt >\nvoid sort( RandomIt first, RandomIt last );\n")),(0,i.kt)("p",null,"This overload is more than we need. What does it do? It just sorts the elements\nin the range ",(0,i.kt)("inlineCode",{parentName:"p"},"[first, last)")," using ",(0,i.kt)("inlineCode",{parentName:"p"},"operator<")," on them. We can't sort the whole\nmatrix using this, but\u2026 we can sort just \xbbone\xab diagonal without doing much work\non our end."),(0,i.kt)("p",null,"What is the ",(0,i.kt)("inlineCode",{parentName:"p"},"RandomIt")," type though? If we look more into the documentation, we\ncan easily find the requirements for it and also learn that it's a ",(0,i.kt)("em",{parentName:"p"},"random access"),"\n",(0,i.kt)("em",{parentName:"p"},"iterator")," and allows swapping its values at the same time."),(0,i.kt)("admonition",{title:"Random access iterator",type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"What is the ",(0,i.kt)("em",{parentName:"p"},"random access iterator")," though? We can find it in a documentation\nand see the following description:"),(0,i.kt)("blockquote",{parentName:"admonition"},(0,i.kt)("p",{parentName:"blockquote"},"A ",(0,i.kt)("strong",{parentName:"p"},"LegacyRandomAccessIterator")," is a ",(0,i.kt)("a",{parentName:"p",href:"https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator"},"LegacyBidirectionalIterator"),"\nthat can be moved to point to any element in constant time.")),(0,i.kt)("p",{parentName:"admonition"},"After that we can see all the requirements for it being listed. I don't feel like\nreading them right now, so we will just use it and see where the compilation blows\nup, i.e. \u201c",(0,i.kt)("em",{parentName:"p"},"compiler-assisted development"),"\u201d",(0,i.kt)("sup",{parentName:"p",id:"fnref-2-b611be"},(0,i.kt)("a",{parentName:"sup",href:"#fn-2-b611be",className:"footnote-ref"},"2"))," if you will ;)")),(0,i.kt)("p",null,"Now we know that we can use ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort")," to sort the diagonal itself, but we also\nneed to get the diagonals somehow. I'm rather lazy, so I'll just delegate it to\nsomeone else",(0,i.kt)("sup",{parentName:"p",id:"fnref-3-b611be"},(0,i.kt)("a",{parentName:"sup",href:"#fn-3-b611be",className:"footnote-ref"},"3")),". And that way we get"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"matrix diagonalSort(matrix mat)\n{\n // we iterate over the diagonals\n for (auto d : diagonals(mat)) {\n // and we sort each diagonal\n std::sort(d.begin(), d.end());\n }\n\n // we take the matrix by copy, so we can sort in-situ and return the copy\n // that we sorted\n return mat;\n}\n")),(0,i.kt)("p",null,"This solution looks very simple, doesn't it? Well, cause it is.\nLet's try compiling it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"matrix-sort.cpp:11:23: error: use of undeclared identifier 'diagonals' [clang-diagnostic-error]\n for (auto d : diagonals(mat)) {\n ^\nFound compiler error(s).\nmake: *** [makefile:14: tidy] Error 1\n")),(0,i.kt)("p",null,"OK, seems about right. We haven't implemented the ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," yet. And based on\nwhat we've written so far, we need a function or a class ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," that will\ngive us the diagonals we need."),(0,i.kt)("h2",{id:"implementing-the-diagonals"},"Implementing the ",(0,i.kt)("inlineCode",{parentName:"h2"},"diagonals")),(0,i.kt)("p",null,"Cool, so we need the function that will let us go through each and every diagonal\nin our matrix. We use the ",(0,i.kt)("em",{parentName:"p"},"for-range")," loop, so whatever we get back from the\n",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," must support ",(0,i.kt)("inlineCode",{parentName:"p"},".begin()")," and ",(0,i.kt)("inlineCode",{parentName:"p"},".end()"),". Since I am a masochist, we will\ndo such functionality for a matrix of any type, not just the ",(0,i.kt)("inlineCode",{parentName:"p"},"int")," from the challenge."),(0,i.kt)("p",null,"As I said, we need to be able to"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"construct the object"),(0,i.kt)("li",{parentName:"ul"},"get the beginning"),(0,i.kt)("li",{parentName:"ul"},"get the end (the \u201csentinel\u201d)")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"template \nclass diagonals {\n using matrix_t = std::vector>;\n\n matrix_t& _matrix;\n\npublic:\n diagonals(matrix_t& m)\n : _matrix(m)\n {\n }\n diagonals_iter begin()\n {\n /* TODO */\n }\n diagonals_iter end()\n {\n /* TODO */\n }\n};\n")),(0,i.kt)("p",null,"Now we have a ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," that we can use to go through the diagonals. We haven't\nimplemented the core of it yet. Let's go through what we have for now."),(0,i.kt)("p",null,"We have a templated class with templated ",(0,i.kt)("inlineCode",{parentName:"p"},"T")," that is used as a placeholder for any\ntype we would store in the matrix. Because I'm lazy, I have defined the ",(0,i.kt)("inlineCode",{parentName:"p"},"matrix_t"),"\ntype that is a \u201cshortcut\u201d for ",(0,i.kt)("inlineCode",{parentName:"p"},"std::vector>"),", so I don't have to\ntype it out all the time. Of course, we need to store the matrix, we are given,\nas a private attribute. And then just have the constructor and the 2 methods we\nneed for the ",(0,i.kt)("em",{parentName:"p"},"for-range"),"."),(0,i.kt)("h3",{id:"iterating-over-diagonals"},"Iterating over diagonals"),(0,i.kt)("p",null,"Now that we have an object that will allow us to iterate through the diagonals,\nwe need to implement the iterating itself. We need to go through all of them, so\nwe have multiple options how to do so. I have decided to start from the \u201cmain\u201d\ndiagonal that starts at ",(0,i.kt)("inlineCode",{parentName:"p"},"(0, 0)")," index and then proceed with the diagonals starting\nin the first row, followed by the rest of the diagonals in the first column."),(0,i.kt)("p",null,"We need to be able to tell that we've iterated through all of them, and also we\nneed to know which diagonal is next. For that purpose we will pass the indices\nof the first cell on the diagonal. That way we can always tell how to move forward."),(0,i.kt)("p",null,"We will start by updating the ",(0,i.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"end")," to reflect our choice accordingly."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"diagonals_iter begin() { return diagonals_iter { _matrix, 0, 0 }; }\ndiagonals_iter end() { return diagonals_iter { _matrix, 0, _matrix.size() }; }\n")),(0,i.kt)("p",null,"For the ",(0,i.kt)("inlineCode",{parentName:"p"},"begin")," we return the first diagonal that starts at ",(0,i.kt)("inlineCode",{parentName:"p"},"(0, 0)"),". And because\nwe have decided to do the diagonals in the first column at the end, the first\ndiagonal that is not a valid one is the one at ",(0,i.kt)("inlineCode",{parentName:"p"},"(0, height)"),". Apart from the\nindices, we also need to pass reference to the matrix itself."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"You may have noticed that we also include the diagonals that have length 1,\nspecifically the ones at ",(0,i.kt)("inlineCode",{parentName:"p"},"(0, height - 1)")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"(width - 1, 0)"),". We are implementing\nan iterator that ",(0,i.kt)("strong",{parentName:"p"},"should not")," care about the way it's being used. Therefore, we\ndon't care about the fact they don't need to be sorted.")),(0,i.kt)("p",null,"Cool, let's leave the iterator itself to someone else, right?",(0,i.kt)("sup",{parentName:"p",id:"fnref-4-b611be"},(0,i.kt)("a",{parentName:"sup",href:"#fn-4-b611be",className:"footnote-ref"},"4"))),(0,i.kt)("h3",{id:"implementing-the-iterator-over-diagonals"},"Implementing the iterator over diagonals"),(0,i.kt)("p",null,"We can start with a simple skeleton based on the information that we pass from\nthe ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals"),". Also to utilize the ",(0,i.kt)("inlineCode",{parentName:"p"},"matrix_t")," and also contain implementation\ndetails hidden away, we will put this code into the ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonals")," class."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class diagonals_iter {\n matrix_t& m;\n std::size_t x;\n std::size_t y;\n\npublic:\n diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)\n : m(matrix)\n , x(x)\n , y(y)\n {\n }\n};\n")),(0,i.kt)("p",null,"In this case we will be implementing a \u201csimple\u201d forward iterator, so we don't\nneed to implement a lot. Notably it will be:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"inequality operator (we need to know when we reach the end and have nothing to\niterate over)"),(0,i.kt)("li",{parentName:"ul"},"preincrementation operator (we need to be able to move around the iterable)"),(0,i.kt)("li",{parentName:"ul"},"dereference operator (we need to be able to retrieve the objects we iterate\nover)")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class diagonals_iter {\n matrix_t& m;\n std::size_t x;\n std::size_t y;\n\npublic:\n diagonals_iter(matrix_t& matrix, std::size_t x, std::size_t y)\n : m(matrix)\n , x(x)\n , y(y)\n {\n }\n\n bool operator!=(const diagonals_iter& rhs) const\n {\n // iterators are not equal if they reference different matrices, or\n // their positions differ\n return m != rhs.m || x != rhs.x || y != rhs.y;\n }\n\n diagonals_iter& operator++()\n {\n if (y != 0) {\n // iterating through diagonals down the first column\n y++;\n return *this;\n }\n\n // iterating the diagonals along the first row\n x++;\n if (x == m.front().size()) {\n // switching to diagonals in the first column\n x = 0;\n y++;\n }\n\n return *this;\n }\n\n diagonal operator*() const { return diagonal { m, x, y }; }\n};\n")),(0,i.kt)("p",null,"Let's go one-by-one. Inequality operator is rather simple, just compare iterator's\nattributes field-by-field. If you think about it, checking inequality of two 2D\nvectors may be a bit inefficient, therefore, we can swap around and check it as\na last thing."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"- return m != rhs.m || x != rhs.x || y != rhs.y;\n+ return x != rhs.x || y != rhs.y || m != rhs.m;\n")),(0,i.kt)("p",null,"Preincrementation is where the magic happens. If you have a better look, you can\nsee two branches of this operation:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"When ",(0,i.kt)("inlineCode",{parentName:"li"},"y != 0")," (we're iterating over the diagonals in the first column)\nIn this case, we just bump the row and we're done."),(0,i.kt)("li",{parentName:"ol"},"When ",(0,i.kt)("inlineCode",{parentName:"li"},"y == 0")," (we're iterating over the diagonals in the first row)\nIn this case, we bump the column and check if we haven't gotten out of bounds,\ni.e. the end of the first row. If we get out of the bounds, we're continuing\nwith the second diagonal in the first column.")),(0,i.kt)("p",null,"Dereferencing the iterator must \u201cyield\u201d something. In our case it will be the\ndiagonal that we want to sort. For sorting we need just the iterators that can\nmove around said diagonal. The simplest thing, we can do, is to delegate it to\nsomething else. In our case it will be a class called ",(0,i.kt)("inlineCode",{parentName:"p"},"diagonal"),"."),(0,i.kt)("h2",{id:"implementing-the-diagonal-itself"},"Implementing the ",(0,i.kt)("inlineCode",{parentName:"h2"},"diagonal")," itself"),(0,i.kt)("p",null,"After implementing the iterator over diagonals, we know that all we need to describe\na diagonal is the matrix itself and the \u201cstart\u201d of the diagonal (row and column).\nAnd we also know that the diagonal must provide some iterators for the ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort"),"\nfunction. We can start with the following skeleton:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"template \nclass diagonal {\n using matrix_t = std::vector>;\n\n matrix_t& matrix;\n std::size_t x;\n std::size_t y;\n\npublic:\n diagonal(matrix_t& matrix, std::size_t x, std::size_t y)\n : matrix(matrix)\n , x(x)\n , y(y)\n {\n }\n\n diagonal_iter begin() const { return diagonal_iter { matrix, x, y }; }\n\n diagonal_iter end() const\n {\n auto max_x = matrix[y].size();\n auto max_y = matrix.size();\n\n // we need to find the distance in which we get out of bounds (either in\n // column or row)\n auto steps = std::min(max_x - x, max_y - y);\n\n return diagonal_iter { matrix, x + steps, y + steps };\n }\n};\n")),(0,i.kt)("p",null,"Initialization is rather simple, we just \u201ckeep\u201d the stuff we get, ",(0,i.kt)("inlineCode",{parentName:"p"},"begin")," is the\nsimplest, we just delegate."),(0,i.kt)("p",null,"In case of the ",(0,i.kt)("inlineCode",{parentName:"p"},"end"),", it gets more complicated. We need to know where is the \u201cend\u201d\nof the diagonal. Since ",(0,i.kt)("inlineCode",{parentName:"p"},"end")," should point to the first element \u201cafter\u201d the iterable,\nwe know that it's the first position of the iterator where either ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," becomes\n",(0,i.kt)("inlineCode",{parentName:"p"},"matrix.size()")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," becomes ",(0,i.kt)("inlineCode",{parentName:"p"},"matrix[y].size()"),". Also we are moving along diagonal,\nduh, therefore we can deduce the first \u201cposition\u201d afterwards by minimal amount of\nsteps to get out of the any column or row, hence ",(0,i.kt)("inlineCode",{parentName:"p"},"std::min(max_x - x, max_y - y)"),".\nFinal position is then computed simply by adding the steps to the beginning of\nthe diagonal."),(0,i.kt)("p",null,"Now we just need to finish the iterator for the diagonal itself and we're done."),(0,i.kt)("h3",{id:"implementing-diagonal_iter"},"Implementing ",(0,i.kt)("inlineCode",{parentName:"h3"},"diagonal_iter")),(0,i.kt)("p",null,"This part is the hardest from all we need to do. It's because of the requirements\nof the ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort")," that requires us to implement a ",(0,i.kt)("em",{parentName:"p"},"random access iterator"),". I have\nbriefly described it above, and \u201cin a nutshell\u201d it means that we need to implement\nan iterator that can move in constant time along the diagonal in any amount of\nsteps."),(0,i.kt)("p",null,"Let's go through all of the functionality that our iterator needs to support to\nbe used in ",(0,i.kt)("inlineCode",{parentName:"p"},"std::sort"),". We need the usual operations like:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"equality/inequality"),(0,i.kt)("li",{parentName:"ul"},"incrementation"),(0,i.kt)("li",{parentName:"ul"},"dereferencing")),(0,i.kt)("p",null,"We will also add all the types that our iterator uses with the category of the\niterator, i.e. what interface it supports:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class diagonal_iter {\n // we need to keep reference to the matrix itself\n matrix_t& m;\n\n // we need to be able to tell our current position\n std::size_t x;\n std::size_t y;\n\npublic:\n using difference_type = std::ptrdiff_t;\n using value_type = T;\n using pointer = T*;\n using reference = T&;\n using iterator_category = std::random_access_iterator_tag;\n\n diagonal_iter(matrix_t& matrix,\n std::size_t x,\n std::size_t y)\n : m(matrix)\n , x(x)\n , y(y)\n {\n }\n\n bool operator==(const diagonal_iter& rhs) const\n {\n return x == rhs.x && y == rhs.y && m == rhs.m;\n }\n\n diagonal_iter& operator++()\n {\n // we are moving along the diagonal, so we increment both \u2039x\u203a and \u2039y\u203a at\n // the same time\n x++;\n y++;\n return *this;\n }\n\n reference operator*() const { return m[y][x]; }\n};\n")),(0,i.kt)("p",null,"This is pretty similar to the previous iterator, but now we need to implement the\nremaining requirements of the ",(0,i.kt)("em",{parentName:"p"},"random access iterator"),". Let's see what those are:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"decrementation - cause we need to be able to move backwards too, since ",(0,i.kt)("em",{parentName:"li"},"random "),(0,i.kt)("em",{parentName:"li"},"access iterator")," extends the interface of ",(0,i.kt)("em",{parentName:"li"},"bidirectional iterator")),(0,i.kt)("li",{parentName:"ul"},"moving the iterator in either direction by steps given as an integer"),(0,i.kt)("li",{parentName:"ul"},"being able to tell the distance between two iterators"),(0,i.kt)("li",{parentName:"ul"},"define an ordering on the iterators")),(0,i.kt)("p",null,"Let's fill them in:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp"},"class diagonal_iter {\n // we need to keep reference to the matrix itself\n matrix_t& m;\n\n // we need to be able to tell our current position\n std::size_t x;\n std::size_t y;\n\npublic:\n using difference_type = std::ptrdiff_t;\n using value_type = T;\n using pointer = T*;\n using reference = T&;\n using iterator_category = std::random_access_iterator_tag;\n\n diagonal_iter(matrix_t& matrix,\n std::size_t x,\n std::size_t y)\n : m(matrix)\n , x(x)\n , y(y)\n {\n }\n\n bool operator==(const diagonal_iter& rhs) const\n {\n return x == rhs.x && y == rhs.y && m == rhs.m;\n }\n\n diagonal_iter& operator++()\n {\n // we are moving along the diagonal, so we increment both \u2039x\u203a and \u2039y\u203a at\n // the same time\n x++;\n y++;\n return *this;\n }\n\n reference operator*() const { return m[y][x]; }\n\n // exactly opposite to the incrementation\n diagonal_iter operator--()\n {\n x--;\n y--;\n return *this;\n }\n\n // moving \u2039n\u203a steps back is same as calling decrementation \u2039n\u203a-times, so we\n // can just return a new iterator and subtract \u2039n\u203a from both coordinates in\n // the matrix\n diagonal_iter operator-(difference_type n) const\n {\n return diagonal_iter { m, x - n, y - n };\n }\n\n // here we assume that we are given two iterators on the same diagonal\n difference_type operator-(const diagonal_iter& rhs) const\n {\n assert(m == rhs.m);\n return x - rhs.x;\n }\n\n // counterpart of moving \u2039n\u203a steps backwards\n diagonal_iter operator+(difference_type n) const\n {\n return diagonal_iter { m, x + n, y + n };\n }\n\n // we compare the coordinates, and also assume that those 2 iterators are\n // lying on the same diagonal\n bool operator<(const diagonal_iter& rhs) const\n {\n assert(m == rhs.m);\n return x < rhs.x && y < rhs.y;\n }\n};\n")),(0,i.kt)("p",null,"At this point we could probably try and compile it, right? If we do so, we will\nget yelled at by a compiler for the following reasons:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type 'diagonal::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\n __last = __next;\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1817:11: note: in instantiation of function template specialization 'std::__unguarded_linear_insert::diagonal_iter, __gnu_cxx::__ops::_Val_less_iter>' requested here\n std::__unguarded_linear_insert(__i,\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1849:9: note: in instantiation of function template specialization 'std::__insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__insertion_sort(__first, __first + int(_S_threshold), __comp);\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization 'std::__final_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__final_insertion_sort(__first, __last, __comp);\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\n ^\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort::diagonal_iter>' requested here\n std::sort(d.begin(), d.end());\n ^\nmatrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal::matrix_t &' (aka 'vector> &')\n matrix_t& m;\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1830:2: error: no matching function for call to '__unguarded_linear_insert' [clang-diagnostic-error]\n std::__unguarded_linear_insert(__i,\n ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1850:9: note: in instantiation of function template specialization 'std::__unguarded_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__unguarded_insertion_sort(__first + int(_S_threshold), __last,\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization 'std::__final_insertion_sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__final_insertion_sort(__first, __last, __comp);\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\n ^\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort::diagonal_iter>' requested here\n std::sort(d.begin(), d.end());\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1782:5: note: candidate template ignored: substitution failure [with _RandomAccessIterator = diagonal::diagonal_iter, _Compare = __gnu_cxx::__ops::_Val_less_iter]\n __unguarded_linear_insert(_RandomAccessIterator __last,\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1923:11: error: object of type 'diagonal::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\n __last = __cut;\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1937:9: note: in instantiation of function template specialization 'std::__introsort_loop::diagonal_iter, long, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__introsort_loop(__first, __last,\n ^\n/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here\n std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());\n ^\nmatrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort::diagonal_iter>' requested here\n std::sort(d.begin(), d.end());\n ^\nmatrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal::matrix_t &' (aka 'vector> &')\n matrix_t& m;\n ^\n")),(0,i.kt)("p",null,"That's a lot of noise, isn't it? Let's focus on the important parts:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type 'diagonal::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]\n\u2026\nmatrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal::matrix_t &' (aka 'vector> &')\n matrix_t& m;\n ^\n")),(0,i.kt)("p",null,"Ah! We have a reference in our iterator, and this prevents us from having a copy\nassignment operator (that is used \u201csomewhere\u201d in the sorting algorithm). Well\u2026\nLet's just wrap it!"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-diff"},"# we need to keep a different type than reference\n- matrix_t& m;\n+ std::reference_wrapper m;\n\n# in comparison we need to get the reference out of the wrapper first\n- return x == rhs.x && y == rhs.y && m == rhs.m;\n+ return x == rhs.x && y == rhs.y && m.get() == rhs.m.get();\n\n# same when we return a reference to the \u201ccell\u201d in the matrix\n- reference operator*() const { return m[y][x]; }\n+ reference operator*() const { return m.get()[y][x]; }\n\n# and finally in the assertions that we set for the \u201cdistance\u201d and \u201cless than\u201d\n- assert(m == rhs.m);\n+ assert(m.get() == rhs.m.get());\n")),(0,i.kt)("p",null,"We're done now! We have written an iterator over diagonals for a 2D ",(0,i.kt)("inlineCode",{parentName:"p"},"vector"),". You can have a look at the final result ",(0,i.kt)("a",{parentName:"p",href:"pathname:///files/blog/leetcode/sort-matrix-diagonally/matrix-sort.cpp"},"here"),"."),(0,i.kt)("div",{className:"footnotes"},(0,i.kt)("hr",{parentName:"div"}),(0,i.kt)("ol",{parentName:"div"},(0,i.kt)("li",{parentName:"ol",id:"fn-1-b611be"},"just because I'm used to it and don't care about your opinion ;)",(0,i.kt)("a",{parentName:"li",href:"#fnref-1-b611be",className:"footnote-backref"},"\u21a9")),(0,i.kt)("li",{parentName:"ol",id:"fn-2-b611be"},"exercise at your own risk",(0,i.kt)("a",{parentName:"li",href:"#fnref-2-b611be",className:"footnote-backref"},"\u21a9")),(0,i.kt)("li",{parentName:"ol",id:"fn-3-b611be"},"me in 5 minutes in fact, but don't make me scared",(0,i.kt)("a",{parentName:"li",href:"#fnref-3-b611be",className:"footnote-backref"},"\u21a9")),(0,i.kt)("li",{parentName:"ol",id:"fn-4-b611be"},"me in the next section\u2026",(0,i.kt)("a",{parentName:"li",href:"#fnref-4-b611be",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d7f7fb17.fd985da7.js b/assets/js/d7f7fb17.d47054f6.js similarity index 98% rename from assets/js/d7f7fb17.fd985da7.js rename to assets/js/d7f7fb17.d47054f6.js index d1205bd..dc29e52 100644 --- a/assets/js/d7f7fb17.fd985da7.js +++ b/assets/js/d7f7fb17.d47054f6.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1171],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=o.createContext({}),f=function(e){var t=o.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=f(e.components);return o.createElement(l.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=f(r),d=n,m=s["".concat(l,".").concat(d)]||s[d]||u[d]||a;return r?o.createElement(m,i(i({ref:t},p),{},{components:r})):o.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[s]="string"==typeof e?e:n,i[1]=c;for(var f=2;f{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>f});var o=r(7462),n=(r(7294),r(3905));const a={title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45",slug:"aoc-2022/intro",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/intro",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/00-intro.md",source:"@site/blog/aoc-2022/00-intro.md",title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45:00.000Z",formattedDate:"December 14, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:8.665,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45",slug:"aoc-2022/intro",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"1st week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/1st-week"}},l={authorsImageUrls:[void 0]},f=[],p={toc:f},s="wrapper";function u(e){let{components:t,...r}=e;return(0,n.kt)(s,(0,o.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Let's talk about the preparations for this year's ","[",(0,n.kt)("em",{parentName:"p"},"Advent of Code"),"]","."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1171],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var o=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=o.createContext({}),f=function(e){var t=o.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=f(e.components);return o.createElement(l.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=f(r),d=n,m=s["".concat(l,".").concat(d)]||s[d]||u[d]||a;return r?o.createElement(m,i(i({ref:t},p),{},{components:r})):o.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[s]="string"==typeof e?e:n,i[1]=c;for(var f=2;f{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>f});var o=r(7462),n=(r(7294),r(3905));const a={title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45",slug:"aoc-2022/intro",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},i=void 0,c={permalink:"/blog/aoc-2022/intro",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/00-intro.md",source:"@site/blog/aoc-2022/00-intro.md",title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45:00.000Z",formattedDate:"December 14, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:8.665,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"Advent of Code '22 in Rust",description:"Preparing for Advent of Code '22.",date:"2022-12-14T21:45",slug:"aoc-2022/intro",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"1st week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/1st-week"}},l={authorsImageUrls:[void 0]},f=[],p={toc:f},s="wrapper";function u(e){let{components:t,...r}=e;return(0,n.kt)(s,(0,o.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Let's talk about the preparations for this year's ","[",(0,n.kt)("em",{parentName:"p"},"Advent of Code"),"]","."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/dff2ebad.0c0a899d.js b/assets/js/dff2ebad.f70dfd2d.js similarity index 99% rename from assets/js/dff2ebad.0c0a899d.js rename to assets/js/dff2ebad.f70dfd2d.js index 451cd7c..06bbafa 100644 --- a/assets/js/dff2ebad.0c0a899d.js +++ b/assets/js/dff2ebad.f70dfd2d.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[146],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),m=p(n),u=o,h=m["".concat(s,".").concat(u)]||m[u]||d[u]||i;return n?a.createElement(h,l(l({ref:t},c),{},{components:n})):a.createElement(h,l({ref:t},c))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,l=new Array(i);l[0]=u;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[m]="string"==typeof e?e:o,l[1]=r;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>r,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15",slug:"aoc-2022/1st-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},l=void 0,r={permalink:"/blog/aoc-2022/1st-week",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/01-week-1.md",source:"@site/blog/aoc-2022/01-week-1.md",title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15:00.000Z",formattedDate:"December 15, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:12.4,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15",slug:"aoc-2022/1st-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"2nd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/2nd-week"},nextItem:{title:"Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/intro"}},s={authorsImageUrls:[void 0]},p=[{value:"Day 1: Calorie Counting",id:"day-1-calorie-counting",level:2},{value:"Solution",id:"solution",level:3},{value:"Day 2: Rock Paper Scissors",id:"day-2-rock-paper-scissors",level:2},{value:"Solution",id:"solution-1",level:3},{value:"Day 3: Rucksack Reorganization",id:"day-3-rucksack-reorganization",level:2},{value:"Solution",id:"solution-2",level:3},{value:"Day 4: Camp Cleanup",id:"day-4-camp-cleanup",level:2},{value:"Solution",id:"solution-3",level:3},{value:"Day 5: Supply Stacks",id:"day-5-supply-stacks",level:2},{value:"Solution",id:"solution-4",level:3},{value:"Day 6: Tuning Trouble",id:"day-6-tuning-trouble",level:2},{value:"Solution",id:"solution-5",level:3},{value:"Day 7: No Space Left On Device",id:"day-7-no-space-left-on-device",level:2},{value:"Solution",id:"solution-6",level:3},{value:"Post Mortem",id:"post-mortem",level:2},{value:"Rc<T> vs Rc<RefCell<T>>",id:"rct-vs-rcrefcellt",level:3}],c={toc:p},m="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the first week of ",(0,o.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,o.kt)("em",{parentName:"a"},"Advent of Code"))," in Rust."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"If you wish to have a look at the solutions, you can follow them on my ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.com/mfocko/advent-of-code-2022"},"GitLab"),".\nMore specifically in the ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.com/mfocko/advent-of-code-2022/-/tree/main/src/bin"},(0,o.kt)("inlineCode",{parentName:"a"},"/src/bin/")),".")),(0,o.kt)("p",null,"I will try to summarize my experience with using Rust for the AoC. Trying it out\nages ago, I believe it will be ",(0,o.kt)("em",{parentName:"p"},"pain and suffering"),", but we will see. For each\nday I will also try to give a tl;dr of the problem, so that you can better imagine\nthe relation to my woes or \ud83d\udc4d moments."),(0,o.kt)("h2",{id:"day-1-calorie-counting"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/1"},"Day 1: Calorie Counting")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"As the name suggests, we get the calories of the food contained in the elves\nbackpacks and we want to choose the elf that has the most food ;)")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"Wakey wakey!")),(0,o.kt)("p",null,"Programming in Rust at 6am definitely hits. I've also forgotten to mention how I\nhandle samples. With each puzzle you usually get a sample input and expected\noutput. You can use them to verify that your solution works, or usually doesn't."),(0,o.kt)("p",null,"At first I've decided to put asserts into my ",(0,o.kt)("inlineCode",{parentName:"p"},"main"),", something like"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'assert_eq!(part_1(&sample), 24000);\ninfo!("Part 1: {}", part_1(&input));\n\nassert_eq!(part_2(&sample), 45000);\ninfo!("Part 2: {}", part_2(&input));\n')),(0,o.kt)("p",null,"However, once you get further, the sample input may take some time to run itself.\nSo in the end, I have decided to turn them into unit tests:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn test_part_1() {\n let sample = parse_input("samples/day01.txt");\n assert_eq!(part_1(&sample), 24000);\n }\n\n #[test]\n fn test_part_2() {\n let sample = parse_input("samples/day01.txt");\n assert_eq!(part_2(&sample), 45000);\n }\n}\n')),(0,o.kt)("p",null,"And later on I have noticed, it's hard to tell the difference between the days,\nso I further renamed the ",(0,o.kt)("inlineCode",{parentName:"p"},"mod")," from generic ",(0,o.kt)("inlineCode",{parentName:"p"},"tests")," to reflect the days."),(0,o.kt)("p",null,"Also after finishing the first day puzzle, I have installed an ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/mozilla/sccache"},(0,o.kt)("inlineCode",{parentName:"a"},"sccache"))," to\ncache the builds, so that the build time is lower, cause it was kinda unbearable."),(0,o.kt)("h3",{id:"solution"},"Solution"),(0,o.kt)("p",null,"Well, it's a pretty simple problem. You just take the input, sum the calories and\nfind the biggest one. However, if we try to generalize to more than the biggest\none, the fun appears. We have few options:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"keep all the calories, sort them, take what we need"),(0,o.kt)("li",{parentName:"ul"},"keep all the calories and use max heap"),(0,o.kt)("li",{parentName:"ul"},"use min heap and maintain at most N calories that we need")),(0,o.kt)("h2",{id:"day-2-rock-paper-scissors"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/2"},"Day 2: Rock Paper Scissors")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"You want to know what score did you achieve while playing ",(0,o.kt)("em",{parentName:"p"},"Rock Paper Scissors"),".\nAnd then you want to be strategic about it.")),(0,o.kt)("p",null,"Apart from the technical details of the puzzle, it went relatively smooth."),(0,o.kt)("h3",{id:"solution-1"},"Solution"),(0,o.kt)("p",null,"I took relatively na\xefve approach and then tried to simplify it."),(0,o.kt)("h2",{id:"day-3-rucksack-reorganization"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/3"},"Day 3: Rucksack Reorganization")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Let's go reorganize elves' backpacks! Each backpacks has 2 compartments and you\nwant to find the common item among those compartments. Each of them has priority,\nyou care only about the sum.")),(0,o.kt)("p",null,"This is the day where I started to fight the compiler and neither of us decided\nto give up. Let's dive into it \\o/"),(0,o.kt)("admonition",{title:"Fun fact",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Fighting the compiler took me 30 minutes.")),(0,o.kt)("p",null,"We need to find a common item among 2 collections, that's an easy task, right?\nWe can construct 2 sets and find an intersection:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let top: HashSet = [1, 2, 3].iter().collect();\nlet bottom: HashSet = [3, 4, 5].iter().collect();\n")),(0,o.kt)("p",null,"Now, the first issue that we encounter is caused by the fact that we are using\na slice (the ",(0,o.kt)("inlineCode",{parentName:"p"},"[\u2026]"),"), iterator of that returns ",(0,o.kt)("strong",{parentName:"p"},"references")," to the numbers.\nAnd we get immediately yelled at by the compiler, because the numbers are discarded\nafter running the ",(0,o.kt)("inlineCode",{parentName:"p"},".collect"),". To fix this, we can use ",(0,o.kt)("inlineCode",{parentName:"p"},".into_iter"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let top: HashSet = [1, 2, 3].into_iter().collect();\nlet bottom: HashSet = [3, 4, 5].into_iter().collect();\n")),(0,o.kt)("p",null,"This way the numbers will get copied instead of referenced. OK, let's find the\nintersection of those 2 collections:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'println!("Common elements: {:?}", top.intersection(&bottom));\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Common elements: [3]\n")),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Notice that we need to do ",(0,o.kt)("inlineCode",{parentName:"p"},"&bottom"),". It explicitly specifies that ",(0,o.kt)("inlineCode",{parentName:"p"},".intersection"),"\n",(0,o.kt)("strong",{parentName:"p"},"borrows")," the ",(0,o.kt)("inlineCode",{parentName:"p"},"bottom"),", i.e. takes an immutable reference to it.")),(0,o.kt)("p",null,"That's what we want, right? Looks like it! \\o/"),(0,o.kt)("p",null,"Next part wants us to find the common element among all of the backpacks. OK, so\nthat should be fairly easy, we have an intersection and we want to find intersection\nover all of them."),(0,o.kt)("p",null,"Let's have a look at the type of the ",(0,o.kt)("inlineCode",{parentName:"p"},".intersection")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn intersection<'a>(\n\xa0\xa0\xa0\xa0&'a self,\n\xa0\xa0\xa0\xa0other: &'a HashSet\n) -> Intersection<'a, T, S>\n")),(0,o.kt)("p",null,"OK\u2026 Huh\u2026 But we have an example there!"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let intersection: HashSet<_> = a.intersection(&b).collect();\n")),(0,o.kt)("p",null,"Cool, that's all we need."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'let top: HashSet = [1, 2, 3, 4].into_iter().collect();\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\n\nlet intersection: HashSet<_> = top.intersection(&bottom).collect();\nprintln!("Intersection: {:?}", intersection);\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Intersection: {3, 4}\n")),(0,o.kt)("p",null,"Cool, so let's do the intersection with the ",(0,o.kt)("inlineCode",{parentName:"p"},"top_2"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'let top: HashSet = [1, 2, 3, 4].into_iter().collect();\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\n\nlet intersection: HashSet<_> = top.intersection(&bottom).collect();\nlet intersection: HashSet<_> = intersection.intersection(&top_2).collect();\nprintln!("Intersection: {:?}", intersection);\n')),(0,o.kt)("p",null,"And we get yelled at by the compiler:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"error[E0308]: mismatched types\n --\x3e src/main.rs:10:58\n |\n10 | let intersection: HashSet<_> = intersection.intersection(&top_2).collect();\n | ------------ ^^^^^^ expected `&i32`, found `i32`\n | |\n | arguments to this function are incorrect\n |\n = note: expected reference `&HashSet<&i32>`\n found reference `&HashSet`\n")),(0,o.kt)("p",null,"/o\\ What the hell is going on here? Well, the funny thing is, that this operation\ndoesn't return the elements themselves, but the references to them and when we pass\nthe third set, it has just the values themselves, without any references."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"It may seem as a very weird decision, but in fact it makes some sense\u2026 It allows\nyou to do intersection of items that may not be possible to copy. Overall this is\na \u201ctax\u201d for having a borrow checker ",(0,o.kt)("del",{parentName:"p"},"drilling your ass")," having your back and\nmaking sure you're not doing something naughty that may cause an ",(0,o.kt)("strong",{parentName:"p"},"undefined"),"\n",(0,o.kt)("strong",{parentName:"p"},"behavior"),".")),(0,o.kt)("p",null,"To resolve this we need to get an iterator that ",(0,o.kt)("strong",{parentName:"p"},"clones")," the elements:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'let top: HashSet = [1, 2, 3, 4].into_iter().collect();\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\n\nlet intersection: HashSet<_> = top.intersection(&bottom).cloned().collect();\nlet intersection: HashSet<_> = intersection.intersection(&top_2).cloned().collect();\nlet intersection: HashSet<_> = intersection.intersection(&bottom_2).cloned().collect();\nprintln!("Intersection: {:?}", intersection);\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Intersection: {4}\n")),(0,o.kt)("h3",{id:"solution-2"},"Solution"),(0,o.kt)("p",null,"The approach is pretty simple, if you omit the ",(0,o.kt)("em",{parentName:"p"},"1on1 with the compiler"),". You just\nhave some fun with the set operations :)"),(0,o.kt)("h2",{id:"day-4-camp-cleanup"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/4"},"Day 4: Camp Cleanup")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Elves are cleaning up the camp and they got overlapping sections to clean up.\nFind how many overlap and can take the day off.")),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html"},(0,o.kt)("inlineCode",{parentName:"a"},"RangeInclusive"))," is your friend not an enemy :)"),(0,o.kt)("h3",{id:"solution-3"},"Solution"),(0,o.kt)("p",null,"Relatively easy, you just need to parse the input and know what you want. Rust's\n",(0,o.kt)("inlineCode",{parentName:"p"},"RangeInclusive")," type helped a lot, cause it took care of all abstractions."),(0,o.kt)("h2",{id:"day-5-supply-stacks"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/5"},"Day 5: Supply Stacks")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Let's play with stacks of crates.")),(0,o.kt)("p",null,"Very easy problem with very annoying input. You can judge yourself:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," [D] \n[N] [C] \n[Z] [M] [P]\n 1 2 3 \n\nmove 1 from 2 to 1\nmove 3 from 1 to 3\nmove 2 from 2 to 1\nmove 1 from 1 to 2\n")),(0,o.kt)("p",null,"Good luck transforming that into something reasonable :)"),(0,o.kt)("admonition",{title:"Fun fact",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Took me 40 minutes to parse this reasonably, including fighting the compiler.")),(0,o.kt)("h3",{id:"solution-4"},"Solution"),(0,o.kt)("p",null,"For the initial solution I went with a manual solution (as in ",(0,o.kt)("em",{parentName:"p"},"I have done all"),"\n",(0,o.kt)("em",{parentName:"p"},"the work"),". Later on I have decided to explore the ",(0,o.kt)("inlineCode",{parentName:"p"},"std")," and interface of the\n",(0,o.kt)("inlineCode",{parentName:"p"},"std::vec::Vec")," and found ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/vec/struct.Vec.html#method.split_off"},(0,o.kt)("inlineCode",{parentName:"a"},"split_off"))," which takes an index and splits (duh)\nthe vector:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let mut vec = vec![1, 2, 3];\nlet vec2 = vec.split_off(1);\nassert_eq!(vec, [1]);\nassert_eq!(vec2, [2, 3]);\n")),(0,o.kt)("p",null,"This helped me simplify my solution a lot and also get rid of some ",(0,o.kt)("em",{parentName:"p"},"edge cases"),"."),(0,o.kt)("h2",{id:"day-6-tuning-trouble"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/6"},"Day 6: Tuning Trouble")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Finding start of the message in a very weird protocol. Start of the message is\ndenoted by ",(0,o.kt)("span",{parentName:"p",className:"math math-inline"},(0,o.kt)("span",{parentName:"span",className:"katex"},(0,o.kt)("span",{parentName:"span",className:"katex-mathml"},(0,o.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,o.kt)("semantics",{parentName:"math"},(0,o.kt)("mrow",{parentName:"semantics"},(0,o.kt)("mi",{parentName:"mrow"},"N")),(0,o.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,o.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,o.kt)("span",{parentName:"span",className:"base"},(0,o.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,o.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," unique consecutive characters.")),(0,o.kt)("h3",{id:"solution-5"},"Solution"),(0,o.kt)("p",null,"A lot of different approaches, knowing that we are dealing with input consisting\nsolely of ASCII letters, I bit the bullet and went with sliding window and\nconstructing sets from that window, checking if the set is as big as the window."),(0,o.kt)("p",null,"One possible optimization could consist of keeping a bit-vector (i.e. ",(0,o.kt)("inlineCode",{parentName:"p"},"usize"),"\nvariable) of encountered characters and updating it as we go. However this has\na different issue and that is removal of the characters from the left side of the\nwindow. We don't know if the same character is not included later on."),(0,o.kt)("p",null,"Other option is to do similar thing, but keeping the frequencies of the letters,\nand again knowing we have only ASCII letters we can optimize by having a vector\nof 26 elements that keeps count for each lowercase letter."),(0,o.kt)("h2",{id:"day-7-no-space-left-on-device"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/7"},"Day 7: No Space Left On Device")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Let's simulate ",(0,o.kt)("a",{parentName:"p",href:"https://www.man7.org/linux/man-pages/man1/du.1.html"},(0,o.kt)("inlineCode",{parentName:"a"},"du"))," to get some stats about our file system and then pinpoint\ndirectories that take a lot of space and should be deleted.")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"I was waiting for this moment, and yet it got me!\n",(0,o.kt)("em",{parentName:"p"},"imagine me swearing for hours"))),(0,o.kt)("h3",{id:"solution-6"},"Solution"),(0,o.kt)("p",null,"We need to \u201c",(0,o.kt)("em",{parentName:"p"},"build"),"\u201d a file system from the input that is given in a following form:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ cd /\n$ ls\ndir a\n14848514 b.txt\n8504156 c.dat\ndir d\n$ cd a\n$ ls\ndir e\n29116 f\n2557 g\n62596 h.lst\n$ cd e\n$ ls\n584 i\n$ cd ..\n$ cd ..\n$ cd d\n$ ls\n4060174 j\n8033020 d.log\n5626152 d.ext\n7214296 k\n")),(0,o.kt)("p",null,"There are few ways in which you can achieve this and also you can assume some\npreconditions, but why would we do that, right? :)"),(0,o.kt)("p",null,"You can \u201cslap\u201d this in either ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/collections/struct.HashMap.html"},(0,o.kt)("inlineCode",{parentName:"a"},"HashMap"))," or ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/collections/struct.BTreeMap.html"},(0,o.kt)("inlineCode",{parentName:"a"},"BTreeMap"))," and call it a day.\nAnd that would be boring\u2026"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"BTreeMap")," is quite fitting for this, don't you think?")),(0,o.kt)("p",null,"I always wanted to try allocation on heap in Rust, so I chose to implement a tree.\nI fought with the ",(0,o.kt)("inlineCode",{parentName:"p"},"Box")," for some time and was losing\u2026"),(0,o.kt)("p",null,"Then I looked up some implementations of trees or linked lists and decided to try\n",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),". And I got my ",(0,o.kt)("em",{parentName:"p"},"ass whopped")," by the compiler once again. /o\\"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"Box")," represents a dynamically allocated memory on heap. It is a single pointer,\nyou can imagine this as ",(0,o.kt)("inlineCode",{parentName:"p"},"std::unique_ptr")," in C++."),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," represents a dynamically allocated memory on heap. On top of that it is\n",(0,o.kt)("em",{parentName:"p"},"reference counted")," (that's what the ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," stands for). You can imagine this as\n",(0,o.kt)("inlineCode",{parentName:"p"},"std::shared_ptr")," in C++."),(0,o.kt)("p",{parentName:"admonition"},"Now the fun stuff. Neither of them lets you ",(0,o.kt)("strong",{parentName:"p"},"mutate")," the contents of the memory."),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"Cell")," allows you to mutate the memory. Can be used reasonably with types that\ncan be copied, because the memory safety is guaranteed by copying the contents\nwhen there is more than one ",(0,o.kt)("strong",{parentName:"p"},"mutable")," reference to the memory."),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"RefCell")," is similar to the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cell"),", but the borrowing rules (how many mutable\nreferences are present) are checked dynamically."),(0,o.kt)("p",{parentName:"admonition"},"So in the end, if you want something like ",(0,o.kt)("inlineCode",{parentName:"p"},"std::shared_ptr")," in Rust, you want\nto have ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),".")),(0,o.kt)("p",null,"So, how are we going to represent the file system then? We will use an enumeration,\nhehe, which is an algebraic data type that can store some stuff in itself \ud83d\ude29"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"type FileHandle = Rc>;\n\n#[derive(Debug)]\nenum AocFile {\n File(usize),\n Directory(BTreeMap),\n}\n")),(0,o.kt)("p",null,"Let's go over it! ",(0,o.kt)("inlineCode",{parentName:"p"},"FileHandle")," represents dynamically allocated ",(0,o.kt)("inlineCode",{parentName:"p"},"AocFile"),", not\nmuch to discuss. What does the ",(0,o.kt)("inlineCode",{parentName:"p"},"#[derive(Debug)]")," do though? It lets us to print\nout the value of that enumeration, it's derived, so it's not as good as if we had\nimplemented it ourselves, but it's good enough for debugging, hence the name."),(0,o.kt)("p",null,"Now to the fun part! ",(0,o.kt)("inlineCode",{parentName:"p"},"AocFile")," value can be represented in two ways:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"File(usize)"),", e.g. ",(0,o.kt)("inlineCode",{parentName:"li"},"AocFile::File(123)")," and we can pattern match it, if we\nneed to"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Directory(BTreeMap)")," will represent the directory and will\ncontain map matching the name of the files (or directories) within to their\nrespective file handles")),(0,o.kt)("p",null,"I will omit the details about constructing this file system, cause there are a lot\nof technicalities introduced by the nature of the input. However if you are\ninterested, you can have a look at my solution."),(0,o.kt)("p",null,"We need to find small enough directories and also find the smallest directory that\nwill free enough space. Now the question is, how could we do that. And there are\nmultiple ways I will describe."),(0,o.kt)("p",null,"I have chosen to implement ",(0,o.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Catamorphism#Tree_fold"},(0,o.kt)("em",{parentName:"a"},"tree catamorphism"))," \ud83d\ude29. It is basically a fold\nover a tree data structure. We descent down into the leaves and propagate computed\nresults all the way to the root. You can also notice that this approach is very\nsimilar to ",(0,o.kt)("em",{parentName:"p"},"dynamic programming"),", we find overlapping sections of the computation\nand try to minimize the additional work (in this case: we need to know sizes of\nour descendants, but we have already been there)."),(0,o.kt)("p",null,"Another approach that has been suggested to me few days later is running DFS on\nthe graph. And, funnily enough, we would still need to combine what we found in\nthe branches where we descent. So in the end, it would work very similarly to my\nsolution."),(0,o.kt)("p",null,"One of the more exotic options would be precomputing the required information at\nthe same time as parsing. That could be done by adding additional fields to the\nnodes which would allow storing such information and updating it as we construct\nthe file system."),(0,o.kt)("h2",{id:"post-mortem"},"Post Mortem"),(0,o.kt)("p",null,"Things that have been brought up in the discussion later on."),(0,o.kt)("h3",{id:"rct-vs-rcrefcellt"},(0,o.kt)("inlineCode",{parentName:"h3"},"Rc")," vs ",(0,o.kt)("inlineCode",{parentName:"h3"},"Rc>")),(0,o.kt)("p",null,"It has been brought up that I have a contradicting statement regarding the\ndynamically allocated memory. Specifically:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"You can imagine ",(0,o.kt)("inlineCode",{parentName:"li"},"Rc")," as an ",(0,o.kt)("inlineCode",{parentName:"li"},"std::shared_ptr")," (in C++)"),(0,o.kt)("li",{parentName:"ul"},"When you want an equivalent of ",(0,o.kt)("inlineCode",{parentName:"li"},"std::shared_ptr"),", you want to use\n",(0,o.kt)("inlineCode",{parentName:"li"},"Rc>"))),(0,o.kt)("p",null,"Now, in Rust it is a bit more complicated, because the type that represents the\n\u201cshared pointer\u201d is ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc"),". What ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell")," does is making sure that there is\nonly one \u201cowner\u201d of a mutable reference at a time (and dynamically, as opposed\nto the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cell"),")."),(0,o.kt)("p",null,"Therefore to be precise and correct about the equivalents of ",(0,o.kt)("inlineCode",{parentName:"p"},"std::shared_ptr"),"\nin Rust, we can say that"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Rc")," is an equivalent of a ",(0,o.kt)("inlineCode",{parentName:"li"},"const std::shared_ptr"),","),(0,o.kt)("li",{parentName:"ul"},"and ",(0,o.kt)("inlineCode",{parentName:"li"},"Rc>")," is an equivalent of a ",(0,o.kt)("inlineCode",{parentName:"li"},"std::shared_ptr"),".")),(0,o.kt)("p",null,"You can easily see that they only differ in the mutability. (And even that is not\nas simple as it seems, because there is also ",(0,o.kt)("inlineCode",{parentName:"p"},"Cell"),")"))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[146],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),m=p(n),u=o,h=m["".concat(s,".").concat(u)]||m[u]||d[u]||i;return n?a.createElement(h,l(l({ref:t},c),{},{components:n})):a.createElement(h,l({ref:t},c))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,l=new Array(i);l[0]=u;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[m]="string"==typeof e?e:o,l[1]=r;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>r,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15",slug:"aoc-2022/1st-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},l=void 0,r={permalink:"/blog/aoc-2022/1st-week",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/01-week-1.md",source:"@site/blog/aoc-2022/01-week-1.md",title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15:00.000Z",formattedDate:"December 15, 2022",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:12.4,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"1st week of Advent of Code '22 in Rust",description:"Surviving first week in Rust.",date:"2022-12-15T01:15",slug:"aoc-2022/1st-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"2nd week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/2nd-week"},nextItem:{title:"Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/intro"}},s={authorsImageUrls:[void 0]},p=[{value:"Day 1: Calorie Counting",id:"day-1-calorie-counting",level:2},{value:"Solution",id:"solution",level:3},{value:"Day 2: Rock Paper Scissors",id:"day-2-rock-paper-scissors",level:2},{value:"Solution",id:"solution-1",level:3},{value:"Day 3: Rucksack Reorganization",id:"day-3-rucksack-reorganization",level:2},{value:"Solution",id:"solution-2",level:3},{value:"Day 4: Camp Cleanup",id:"day-4-camp-cleanup",level:2},{value:"Solution",id:"solution-3",level:3},{value:"Day 5: Supply Stacks",id:"day-5-supply-stacks",level:2},{value:"Solution",id:"solution-4",level:3},{value:"Day 6: Tuning Trouble",id:"day-6-tuning-trouble",level:2},{value:"Solution",id:"solution-5",level:3},{value:"Day 7: No Space Left On Device",id:"day-7-no-space-left-on-device",level:2},{value:"Solution",id:"solution-6",level:3},{value:"Post Mortem",id:"post-mortem",level:2},{value:"Rc<T> vs Rc<RefCell<T>>",id:"rct-vs-rcrefcellt",level:3}],c={toc:p},m="wrapper";function d(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the first week of ",(0,o.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,o.kt)("em",{parentName:"a"},"Advent of Code"))," in Rust."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"If you wish to have a look at the solutions, you can follow them on my ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.com/mfocko/advent-of-code-2022"},"GitLab"),".\nMore specifically in the ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.com/mfocko/advent-of-code-2022/-/tree/main/src/bin"},(0,o.kt)("inlineCode",{parentName:"a"},"/src/bin/")),".")),(0,o.kt)("p",null,"I will try to summarize my experience with using Rust for the AoC. Trying it out\nages ago, I believe it will be ",(0,o.kt)("em",{parentName:"p"},"pain and suffering"),", but we will see. For each\nday I will also try to give a tl;dr of the problem, so that you can better imagine\nthe relation to my woes or \ud83d\udc4d moments."),(0,o.kt)("h2",{id:"day-1-calorie-counting"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/1"},"Day 1: Calorie Counting")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"As the name suggests, we get the calories of the food contained in the elves\nbackpacks and we want to choose the elf that has the most food ;)")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"Wakey wakey!")),(0,o.kt)("p",null,"Programming in Rust at 6am definitely hits. I've also forgotten to mention how I\nhandle samples. With each puzzle you usually get a sample input and expected\noutput. You can use them to verify that your solution works, or usually doesn't."),(0,o.kt)("p",null,"At first I've decided to put asserts into my ",(0,o.kt)("inlineCode",{parentName:"p"},"main"),", something like"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'assert_eq!(part_1(&sample), 24000);\ninfo!("Part 1: {}", part_1(&input));\n\nassert_eq!(part_2(&sample), 45000);\ninfo!("Part 2: {}", part_2(&input));\n')),(0,o.kt)("p",null,"However, once you get further, the sample input may take some time to run itself.\nSo in the end, I have decided to turn them into unit tests:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn test_part_1() {\n let sample = parse_input("samples/day01.txt");\n assert_eq!(part_1(&sample), 24000);\n }\n\n #[test]\n fn test_part_2() {\n let sample = parse_input("samples/day01.txt");\n assert_eq!(part_2(&sample), 45000);\n }\n}\n')),(0,o.kt)("p",null,"And later on I have noticed, it's hard to tell the difference between the days,\nso I further renamed the ",(0,o.kt)("inlineCode",{parentName:"p"},"mod")," from generic ",(0,o.kt)("inlineCode",{parentName:"p"},"tests")," to reflect the days."),(0,o.kt)("p",null,"Also after finishing the first day puzzle, I have installed an ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/mozilla/sccache"},(0,o.kt)("inlineCode",{parentName:"a"},"sccache"))," to\ncache the builds, so that the build time is lower, cause it was kinda unbearable."),(0,o.kt)("h3",{id:"solution"},"Solution"),(0,o.kt)("p",null,"Well, it's a pretty simple problem. You just take the input, sum the calories and\nfind the biggest one. However, if we try to generalize to more than the biggest\none, the fun appears. We have few options:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"keep all the calories, sort them, take what we need"),(0,o.kt)("li",{parentName:"ul"},"keep all the calories and use max heap"),(0,o.kt)("li",{parentName:"ul"},"use min heap and maintain at most N calories that we need")),(0,o.kt)("h2",{id:"day-2-rock-paper-scissors"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/2"},"Day 2: Rock Paper Scissors")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"You want to know what score did you achieve while playing ",(0,o.kt)("em",{parentName:"p"},"Rock Paper Scissors"),".\nAnd then you want to be strategic about it.")),(0,o.kt)("p",null,"Apart from the technical details of the puzzle, it went relatively smooth."),(0,o.kt)("h3",{id:"solution-1"},"Solution"),(0,o.kt)("p",null,"I took relatively na\xefve approach and then tried to simplify it."),(0,o.kt)("h2",{id:"day-3-rucksack-reorganization"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/3"},"Day 3: Rucksack Reorganization")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Let's go reorganize elves' backpacks! Each backpacks has 2 compartments and you\nwant to find the common item among those compartments. Each of them has priority,\nyou care only about the sum.")),(0,o.kt)("p",null,"This is the day where I started to fight the compiler and neither of us decided\nto give up. Let's dive into it \\o/"),(0,o.kt)("admonition",{title:"Fun fact",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Fighting the compiler took me 30 minutes.")),(0,o.kt)("p",null,"We need to find a common item among 2 collections, that's an easy task, right?\nWe can construct 2 sets and find an intersection:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let top: HashSet = [1, 2, 3].iter().collect();\nlet bottom: HashSet = [3, 4, 5].iter().collect();\n")),(0,o.kt)("p",null,"Now, the first issue that we encounter is caused by the fact that we are using\na slice (the ",(0,o.kt)("inlineCode",{parentName:"p"},"[\u2026]"),"), iterator of that returns ",(0,o.kt)("strong",{parentName:"p"},"references")," to the numbers.\nAnd we get immediately yelled at by the compiler, because the numbers are discarded\nafter running the ",(0,o.kt)("inlineCode",{parentName:"p"},".collect"),". To fix this, we can use ",(0,o.kt)("inlineCode",{parentName:"p"},".into_iter"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let top: HashSet = [1, 2, 3].into_iter().collect();\nlet bottom: HashSet = [3, 4, 5].into_iter().collect();\n")),(0,o.kt)("p",null,"This way the numbers will get copied instead of referenced. OK, let's find the\nintersection of those 2 collections:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'println!("Common elements: {:?}", top.intersection(&bottom));\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Common elements: [3]\n")),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Notice that we need to do ",(0,o.kt)("inlineCode",{parentName:"p"},"&bottom"),". It explicitly specifies that ",(0,o.kt)("inlineCode",{parentName:"p"},".intersection"),"\n",(0,o.kt)("strong",{parentName:"p"},"borrows")," the ",(0,o.kt)("inlineCode",{parentName:"p"},"bottom"),", i.e. takes an immutable reference to it.")),(0,o.kt)("p",null,"That's what we want, right? Looks like it! \\o/"),(0,o.kt)("p",null,"Next part wants us to find the common element among all of the backpacks. OK, so\nthat should be fairly easy, we have an intersection and we want to find intersection\nover all of them."),(0,o.kt)("p",null,"Let's have a look at the type of the ",(0,o.kt)("inlineCode",{parentName:"p"},".intersection")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn intersection<'a>(\n\xa0\xa0\xa0\xa0&'a self,\n\xa0\xa0\xa0\xa0other: &'a HashSet\n) -> Intersection<'a, T, S>\n")),(0,o.kt)("p",null,"OK\u2026 Huh\u2026 But we have an example there!"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let intersection: HashSet<_> = a.intersection(&b).collect();\n")),(0,o.kt)("p",null,"Cool, that's all we need."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'let top: HashSet = [1, 2, 3, 4].into_iter().collect();\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\n\nlet intersection: HashSet<_> = top.intersection(&bottom).collect();\nprintln!("Intersection: {:?}", intersection);\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Intersection: {3, 4}\n")),(0,o.kt)("p",null,"Cool, so let's do the intersection with the ",(0,o.kt)("inlineCode",{parentName:"p"},"top_2"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'let top: HashSet = [1, 2, 3, 4].into_iter().collect();\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\n\nlet intersection: HashSet<_> = top.intersection(&bottom).collect();\nlet intersection: HashSet<_> = intersection.intersection(&top_2).collect();\nprintln!("Intersection: {:?}", intersection);\n')),(0,o.kt)("p",null,"And we get yelled at by the compiler:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"error[E0308]: mismatched types\n --\x3e src/main.rs:10:58\n |\n10 | let intersection: HashSet<_> = intersection.intersection(&top_2).collect();\n | ------------ ^^^^^^ expected `&i32`, found `i32`\n | |\n | arguments to this function are incorrect\n |\n = note: expected reference `&HashSet<&i32>`\n found reference `&HashSet`\n")),(0,o.kt)("p",null,"/o\\ What the hell is going on here? Well, the funny thing is, that this operation\ndoesn't return the elements themselves, but the references to them and when we pass\nthe third set, it has just the values themselves, without any references."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"It may seem as a very weird decision, but in fact it makes some sense\u2026 It allows\nyou to do intersection of items that may not be possible to copy. Overall this is\na \u201ctax\u201d for having a borrow checker ",(0,o.kt)("del",{parentName:"p"},"drilling your ass")," having your back and\nmaking sure you're not doing something naughty that may cause an ",(0,o.kt)("strong",{parentName:"p"},"undefined"),"\n",(0,o.kt)("strong",{parentName:"p"},"behavior"),".")),(0,o.kt)("p",null,"To resolve this we need to get an iterator that ",(0,o.kt)("strong",{parentName:"p"},"clones")," the elements:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'let top: HashSet = [1, 2, 3, 4].into_iter().collect();\nlet bottom: HashSet = [3, 4, 5, 6].into_iter().collect();\nlet top_2: HashSet = [2, 3, 4, 5, 6].into_iter().collect();\nlet bottom_2: HashSet = [4, 5, 6].into_iter().collect();\n\nlet intersection: HashSet<_> = top.intersection(&bottom).cloned().collect();\nlet intersection: HashSet<_> = intersection.intersection(&top_2).cloned().collect();\nlet intersection: HashSet<_> = intersection.intersection(&bottom_2).cloned().collect();\nprintln!("Intersection: {:?}", intersection);\n')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Intersection: {4}\n")),(0,o.kt)("h3",{id:"solution-2"},"Solution"),(0,o.kt)("p",null,"The approach is pretty simple, if you omit the ",(0,o.kt)("em",{parentName:"p"},"1on1 with the compiler"),". You just\nhave some fun with the set operations :)"),(0,o.kt)("h2",{id:"day-4-camp-cleanup"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/4"},"Day 4: Camp Cleanup")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Elves are cleaning up the camp and they got overlapping sections to clean up.\nFind how many overlap and can take the day off.")),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html"},(0,o.kt)("inlineCode",{parentName:"a"},"RangeInclusive"))," is your friend not an enemy :)"),(0,o.kt)("h3",{id:"solution-3"},"Solution"),(0,o.kt)("p",null,"Relatively easy, you just need to parse the input and know what you want. Rust's\n",(0,o.kt)("inlineCode",{parentName:"p"},"RangeInclusive")," type helped a lot, cause it took care of all abstractions."),(0,o.kt)("h2",{id:"day-5-supply-stacks"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/5"},"Day 5: Supply Stacks")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Let's play with stacks of crates.")),(0,o.kt)("p",null,"Very easy problem with very annoying input. You can judge yourself:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," [D] \n[N] [C] \n[Z] [M] [P]\n 1 2 3 \n\nmove 1 from 2 to 1\nmove 3 from 1 to 3\nmove 2 from 2 to 1\nmove 1 from 1 to 2\n")),(0,o.kt)("p",null,"Good luck transforming that into something reasonable :)"),(0,o.kt)("admonition",{title:"Fun fact",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Took me 40 minutes to parse this reasonably, including fighting the compiler.")),(0,o.kt)("h3",{id:"solution-4"},"Solution"),(0,o.kt)("p",null,"For the initial solution I went with a manual solution (as in ",(0,o.kt)("em",{parentName:"p"},"I have done all"),"\n",(0,o.kt)("em",{parentName:"p"},"the work"),". Later on I have decided to explore the ",(0,o.kt)("inlineCode",{parentName:"p"},"std")," and interface of the\n",(0,o.kt)("inlineCode",{parentName:"p"},"std::vec::Vec")," and found ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/vec/struct.Vec.html#method.split_off"},(0,o.kt)("inlineCode",{parentName:"a"},"split_off"))," which takes an index and splits (duh)\nthe vector:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let mut vec = vec![1, 2, 3];\nlet vec2 = vec.split_off(1);\nassert_eq!(vec, [1]);\nassert_eq!(vec2, [2, 3]);\n")),(0,o.kt)("p",null,"This helped me simplify my solution a lot and also get rid of some ",(0,o.kt)("em",{parentName:"p"},"edge cases"),"."),(0,o.kt)("h2",{id:"day-6-tuning-trouble"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/6"},"Day 6: Tuning Trouble")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Finding start of the message in a very weird protocol. Start of the message is\ndenoted by ",(0,o.kt)("span",{parentName:"p",className:"math math-inline"},(0,o.kt)("span",{parentName:"span",className:"katex"},(0,o.kt)("span",{parentName:"span",className:"katex-mathml"},(0,o.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,o.kt)("semantics",{parentName:"math"},(0,o.kt)("mrow",{parentName:"semantics"},(0,o.kt)("mi",{parentName:"mrow"},"N")),(0,o.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,o.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,o.kt)("span",{parentName:"span",className:"base"},(0,o.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,o.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," unique consecutive characters.")),(0,o.kt)("h3",{id:"solution-5"},"Solution"),(0,o.kt)("p",null,"A lot of different approaches, knowing that we are dealing with input consisting\nsolely of ASCII letters, I bit the bullet and went with sliding window and\nconstructing sets from that window, checking if the set is as big as the window."),(0,o.kt)("p",null,"One possible optimization could consist of keeping a bit-vector (i.e. ",(0,o.kt)("inlineCode",{parentName:"p"},"usize"),"\nvariable) of encountered characters and updating it as we go. However this has\na different issue and that is removal of the characters from the left side of the\nwindow. We don't know if the same character is not included later on."),(0,o.kt)("p",null,"Other option is to do similar thing, but keeping the frequencies of the letters,\nand again knowing we have only ASCII letters we can optimize by having a vector\nof 26 elements that keeps count for each lowercase letter."),(0,o.kt)("h2",{id:"day-7-no-space-left-on-device"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/7"},"Day 7: No Space Left On Device")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Let's simulate ",(0,o.kt)("a",{parentName:"p",href:"https://www.man7.org/linux/man-pages/man1/du.1.html"},(0,o.kt)("inlineCode",{parentName:"a"},"du"))," to get some stats about our file system and then pinpoint\ndirectories that take a lot of space and should be deleted.")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"I was waiting for this moment, and yet it got me!\n",(0,o.kt)("em",{parentName:"p"},"imagine me swearing for hours"))),(0,o.kt)("h3",{id:"solution-6"},"Solution"),(0,o.kt)("p",null,"We need to \u201c",(0,o.kt)("em",{parentName:"p"},"build"),"\u201d a file system from the input that is given in a following form:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"$ cd /\n$ ls\ndir a\n14848514 b.txt\n8504156 c.dat\ndir d\n$ cd a\n$ ls\ndir e\n29116 f\n2557 g\n62596 h.lst\n$ cd e\n$ ls\n584 i\n$ cd ..\n$ cd ..\n$ cd d\n$ ls\n4060174 j\n8033020 d.log\n5626152 d.ext\n7214296 k\n")),(0,o.kt)("p",null,"There are few ways in which you can achieve this and also you can assume some\npreconditions, but why would we do that, right? :)"),(0,o.kt)("p",null,"You can \u201cslap\u201d this in either ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/collections/struct.HashMap.html"},(0,o.kt)("inlineCode",{parentName:"a"},"HashMap"))," or ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/collections/struct.BTreeMap.html"},(0,o.kt)("inlineCode",{parentName:"a"},"BTreeMap"))," and call it a day.\nAnd that would be boring\u2026"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"BTreeMap")," is quite fitting for this, don't you think?")),(0,o.kt)("p",null,"I always wanted to try allocation on heap in Rust, so I chose to implement a tree.\nI fought with the ",(0,o.kt)("inlineCode",{parentName:"p"},"Box")," for some time and was losing\u2026"),(0,o.kt)("p",null,"Then I looked up some implementations of trees or linked lists and decided to try\n",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),". And I got my ",(0,o.kt)("em",{parentName:"p"},"ass whopped")," by the compiler once again. /o\\"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"Box")," represents a dynamically allocated memory on heap. It is a single pointer,\nyou can imagine this as ",(0,o.kt)("inlineCode",{parentName:"p"},"std::unique_ptr")," in C++."),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," represents a dynamically allocated memory on heap. On top of that it is\n",(0,o.kt)("em",{parentName:"p"},"reference counted")," (that's what the ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," stands for). You can imagine this as\n",(0,o.kt)("inlineCode",{parentName:"p"},"std::shared_ptr")," in C++."),(0,o.kt)("p",{parentName:"admonition"},"Now the fun stuff. Neither of them lets you ",(0,o.kt)("strong",{parentName:"p"},"mutate")," the contents of the memory."),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"Cell")," allows you to mutate the memory. Can be used reasonably with types that\ncan be copied, because the memory safety is guaranteed by copying the contents\nwhen there is more than one ",(0,o.kt)("strong",{parentName:"p"},"mutable")," reference to the memory."),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"RefCell")," is similar to the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cell"),", but the borrowing rules (how many mutable\nreferences are present) are checked dynamically."),(0,o.kt)("p",{parentName:"admonition"},"So in the end, if you want something like ",(0,o.kt)("inlineCode",{parentName:"p"},"std::shared_ptr")," in Rust, you want\nto have ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),".")),(0,o.kt)("p",null,"So, how are we going to represent the file system then? We will use an enumeration,\nhehe, which is an algebraic data type that can store some stuff in itself \ud83d\ude29"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"type FileHandle = Rc>;\n\n#[derive(Debug)]\nenum AocFile {\n File(usize),\n Directory(BTreeMap),\n}\n")),(0,o.kt)("p",null,"Let's go over it! ",(0,o.kt)("inlineCode",{parentName:"p"},"FileHandle")," represents dynamically allocated ",(0,o.kt)("inlineCode",{parentName:"p"},"AocFile"),", not\nmuch to discuss. What does the ",(0,o.kt)("inlineCode",{parentName:"p"},"#[derive(Debug)]")," do though? It lets us to print\nout the value of that enumeration, it's derived, so it's not as good as if we had\nimplemented it ourselves, but it's good enough for debugging, hence the name."),(0,o.kt)("p",null,"Now to the fun part! ",(0,o.kt)("inlineCode",{parentName:"p"},"AocFile")," value can be represented in two ways:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"File(usize)"),", e.g. ",(0,o.kt)("inlineCode",{parentName:"li"},"AocFile::File(123)")," and we can pattern match it, if we\nneed to"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Directory(BTreeMap)")," will represent the directory and will\ncontain map matching the name of the files (or directories) within to their\nrespective file handles")),(0,o.kt)("p",null,"I will omit the details about constructing this file system, cause there are a lot\nof technicalities introduced by the nature of the input. However if you are\ninterested, you can have a look at my solution."),(0,o.kt)("p",null,"We need to find small enough directories and also find the smallest directory that\nwill free enough space. Now the question is, how could we do that. And there are\nmultiple ways I will describe."),(0,o.kt)("p",null,"I have chosen to implement ",(0,o.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Catamorphism#Tree_fold"},(0,o.kt)("em",{parentName:"a"},"tree catamorphism"))," \ud83d\ude29. It is basically a fold\nover a tree data structure. We descent down into the leaves and propagate computed\nresults all the way to the root. You can also notice that this approach is very\nsimilar to ",(0,o.kt)("em",{parentName:"p"},"dynamic programming"),", we find overlapping sections of the computation\nand try to minimize the additional work (in this case: we need to know sizes of\nour descendants, but we have already been there)."),(0,o.kt)("p",null,"Another approach that has been suggested to me few days later is running DFS on\nthe graph. And, funnily enough, we would still need to combine what we found in\nthe branches where we descent. So in the end, it would work very similarly to my\nsolution."),(0,o.kt)("p",null,"One of the more exotic options would be precomputing the required information at\nthe same time as parsing. That could be done by adding additional fields to the\nnodes which would allow storing such information and updating it as we construct\nthe file system."),(0,o.kt)("h2",{id:"post-mortem"},"Post Mortem"),(0,o.kt)("p",null,"Things that have been brought up in the discussion later on."),(0,o.kt)("h3",{id:"rct-vs-rcrefcellt"},(0,o.kt)("inlineCode",{parentName:"h3"},"Rc")," vs ",(0,o.kt)("inlineCode",{parentName:"h3"},"Rc>")),(0,o.kt)("p",null,"It has been brought up that I have a contradicting statement regarding the\ndynamically allocated memory. Specifically:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"You can imagine ",(0,o.kt)("inlineCode",{parentName:"li"},"Rc")," as an ",(0,o.kt)("inlineCode",{parentName:"li"},"std::shared_ptr")," (in C++)"),(0,o.kt)("li",{parentName:"ul"},"When you want an equivalent of ",(0,o.kt)("inlineCode",{parentName:"li"},"std::shared_ptr"),", you want to use\n",(0,o.kt)("inlineCode",{parentName:"li"},"Rc>"))),(0,o.kt)("p",null,"Now, in Rust it is a bit more complicated, because the type that represents the\n\u201cshared pointer\u201d is ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc"),". What ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell")," does is making sure that there is\nonly one \u201cowner\u201d of a mutable reference at a time (and dynamically, as opposed\nto the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cell"),")."),(0,o.kt)("p",null,"Therefore to be precise and correct about the equivalents of ",(0,o.kt)("inlineCode",{parentName:"p"},"std::shared_ptr"),"\nin Rust, we can say that"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Rc")," is an equivalent of a ",(0,o.kt)("inlineCode",{parentName:"li"},"const std::shared_ptr"),","),(0,o.kt)("li",{parentName:"ul"},"and ",(0,o.kt)("inlineCode",{parentName:"li"},"Rc>")," is an equivalent of a ",(0,o.kt)("inlineCode",{parentName:"li"},"std::shared_ptr"),".")),(0,o.kt)("p",null,"You can easily see that they only differ in the mutability. (And even that is not\nas simple as it seems, because there is also ",(0,o.kt)("inlineCode",{parentName:"p"},"Cell"),")"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f48be158.eaa96907.js b/assets/js/f48be158.6dc62990.js similarity index 99% rename from assets/js/f48be158.eaa96907.js rename to assets/js/f48be158.6dc62990.js index cc4fa37..c2d7f96 100644 --- a/assets/js/f48be158.eaa96907.js +++ b/assets/js/f48be158.6dc62990.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[4064],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>c});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=u(n),h=o,c=d["".concat(s,".").concat(h)]||d[h]||m[h]||i;return n?a.createElement(c,r(r({ref:t},p),{},{components:n})):a.createElement(c,r({ref:t},p))}));function c(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:o,r[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=n(7462),o=(n(7294),n(3905));const i={title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00",slug:"aoc-2022/3rd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},r=void 0,l={permalink:"/blog/aoc-2022/3rd-week",editUrl:"https://gitlab.com/mfocko/blog/tree/main/blog/aoc-2022/03-week-3.md",source:"@site/blog/aoc-2022/03-week-3.md",title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00:00.000Z",formattedDate:"July 6, 2023",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:11.565,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00",slug:"aoc-2022/3rd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"4th week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/4th-week"},nextItem:{title:"Sort the matrix diagonally",permalink:"/blog/leetcode/sort-diagonally"}},s={authorsImageUrls:[void 0]},u=[{value:"Day 15: Beacon Exclusion Zone",id:"day-15-beacon-exclusion-zone",level:2},{value:"Solution",id:"solution",level:3},{value:"Day 16: Proboscidea Volcanium",id:"day-16-proboscidea-volcanium",level:2},{value:"Solution",id:"solution-1",level:3},{value:"Indexing in graph",id:"indexing-in-graph",level:4},{value:"Cartesian product",id:"cartesian-product",level:4},{value:"\u201cImplementing\u201d an iterator",id:"implementing-an-iterator",level:4},{value:"Day 17: Pyroclastic Flow",id:"day-17-pyroclastic-flow",level:2},{value:"Solution",id:"solution-2",level:3},{value:"Collision detection",id:"collision-detection",level:4},{value:"Infinite iterator",id:"infinite-iterator",level:4},{value:"Day 18: Boiling Boulders",id:"day-18-boiling-boulders",level:2},{value:"Solution",id:"solution-3",level:3},{value:"Day 19: Not Enough Minerals",id:"day-19-not-enough-minerals",level:2},{value:"Solution",id:"solution-4",level:3},{value:"Day 20: Grove Positioning System",id:"day-20-grove-positioning-system",level:2},{value:"Solution",id:"solution-5",level:3},{value:".borrow_mut()",id:"borrow_mut",level:4},{value:".borrow_mut() on Rc<RefCell<T>>",id:"borrow_mut-on-rcrefcellt",level:5},{value:"BorrowMut trait",id:"borrowmut-trait",level:5},{value:"Conflict",id:"conflict",level:5},{value:"Day 21: Monkey Math",id:"day-21-monkey-math",level:2},{value:"Solution",id:"solution-6",level:3},{value:"Default trait",id:"default-trait",level:4},{value:"Abusing negation",id:"abusing-negation",level:4}],p={toc:u},d="wrapper";function m(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the third week of ",(0,o.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,o.kt)("em",{parentName:"a"},"Advent of Code"))," in Rust."),(0,o.kt)("h2",{id:"day-15-beacon-exclusion-zone"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/15"},"Day 15: Beacon Exclusion Zone")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Triangulating a distress beacon based on the information from the sensors.")),(0,o.kt)("h3",{id:"solution"},"Solution"),(0,o.kt)("p",null,"Relatively easy thing to implement, no major Rust issues hit."),(0,o.kt)("h2",{id:"day-16-proboscidea-volcanium"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/16"},"Day 16: Proboscidea Volcanium")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Finding a max flow in a graph given some time constraints.")),(0,o.kt)("h3",{id:"solution-1"},"Solution"),(0,o.kt)("p",null,"I have used some interesting things to implement this and make it easier for me."),(0,o.kt)("h4",{id:"indexing-in-graph"},"Indexing in graph"),(0,o.kt)("p",null,"I have come across a situation where I needed to keep more information regarding\nthe graph\u2026 In that case you can, of course, create a structure and keep it in,\nbut once you have multiple members in the structure it gets harder to work with\nsince you need to address the fields in the structure. When you work with graph,\nyou frequently need to access the vertices and in this case it felt a lot easier\nto implement the indexing in a graph, rather than explicitly access the\nunderlying data structure."),(0,o.kt)("p",null,"Here you can see a rather short snippet from the solution that allows you to\n\u201cindex\u201d the graph:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"impl Index<&str> for Graph {\n type Output = Vertex;\n\n fn index(&self, index: &str) -> &Self::Output {\n &self.g[index]\n }\n}\n")),(0,o.kt)("h4",{id:"cartesian-product"},"Cartesian product"),(0,o.kt)("p",null,"During the implementation I had to utilize Floyd-Warshall algorithm for finding\nthe shortest path between pairs of vertices and utilized the ",(0,o.kt)("inlineCode",{parentName:"p"},"iproduct!")," macro\nfrom the ",(0,o.kt)("a",{parentName:"p",href:"https://crates.io/crates/itertools"},(0,o.kt)("inlineCode",{parentName:"a"},"itertools")),". It is a very useful higher-order function that allows\nyou to keep the nesting of the loops at a minimum level while still maintaining\nthe same functionality."),(0,o.kt)("h4",{id:"implementing-an-iterator"},"\u201cImplementing\u201d an iterator"),(0,o.kt)("p",null,"For the second part, you get to split the work between 2 actors. That way you\ncan achieve higher efficiency of the whole process that you're planning, but it\nalso makes it harder to evaluate algorithmically, since you need to check the\ndifferent ways the work can be split."),(0,o.kt)("p",null,"Being affected by ",(0,o.kt)("em",{parentName:"p"},"functional programming brain damage"),"\u2122\ufe0f, I have chosen to\ndo this part by function that returns an iterator over the possible ways:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"fn pairings(\n valves: &BTreeSet,\n) -> impl Iterator, BTreeSet)> + '_ {\n let mapping = valves.iter().collect_vec();\n\n let max_mask = 1 << (valves.len() - 1);\n\n (0..max_mask).map(move |mask| {\n let mut elephant = BTreeSet::new();\n let mut human = BTreeSet::new();\n\n for (i, &v) in mapping.iter().enumerate() {\n if (mask & (1 << i)) == 0 {\n human.insert(v.clone());\n } else {\n elephant.insert(v.clone());\n }\n }\n\n (human, elephant)\n })\n}\n")),(0,o.kt)("h2",{id:"day-17-pyroclastic-flow"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/17"},"Day 17: Pyroclastic Flow")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Simulating an autonomous Tetris where pieces get affected by a series of jets of\nhot gas.")),(0,o.kt)("h3",{id:"solution-2"},"Solution"),(0,o.kt)("p",null,"Similarly to the previous day I have created some iterators \ud83d\ude04"),(0,o.kt)("h4",{id:"collision-detection"},"Collision detection"),(0,o.kt)("p",null,"Once you need to check for collisions it is very helpful to be able to just\niterate through the positions that can actually collide with the wall or other\npiece."),(0,o.kt)("p",null,"To get the desired behaviour, you can just compose few smaller functions:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"fn occupied(shape: &[Vec]) -> impl Iterator + '_ {\n shape.iter().enumerate().flat_map(|(y, row)| {\n row.iter().enumerate().filter_map(move |(x, c)| {\n if c == &'#' {\n Some(Vector2D::new(x as isize, y as isize))\n } else {\n None\n }\n })\n })\n}\n")),(0,o.kt)("p",null,"In the end, we get relative positions which we can adjust later when given the\nspecific positions from iterator. You can see some interesting parts in this:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},".enumerate()")," allows us to get both the indices (coordinates) and the line\nor, later on, the character itself,"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},".flat_map()")," flattens the iterator, i.e. when we return another iterator,\nthey just get chained instead of iterating over iterators (which sounds pretty\ndisturbing, doesn't it?),"),(0,o.kt)("li",{parentName:"ul"},"and finally ",(0,o.kt)("inlineCode",{parentName:"li"},".filter_map()")," which is pretty similar to the \u201cbasic\u201d ",(0,o.kt)("inlineCode",{parentName:"li"},".map()"),"\nwith a one, key, difference that it expects the items of an iterator to be\nmapped to an ",(0,o.kt)("inlineCode",{parentName:"li"},"Option")," from which it ignores nothing (as in ",(0,o.kt)("inlineCode",{parentName:"li"},"None")," \ud83d\ude09)\nand also unwraps the values from ",(0,o.kt)("inlineCode",{parentName:"li"},"Some(\u2026)"),".")),(0,o.kt)("h4",{id:"infinite-iterator"},"Infinite iterator"),(0,o.kt)("p",null,"In the solution we cycle through both Tetris-like shapes that fall down and the\njets that move our pieces around. Initially I have implemented my own infinite\niterator that just yields the indices. It is a very simple, yet powerful, piece\nof code:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"struct InfiniteIndex {\n size: usize,\n i: usize,\n}\n\nimpl InfiniteIndex {\n fn new(size: usize) -> InfiniteIndex {\n InfiniteIndex { size, i: size - 1 }\n }\n}\n\nimpl Iterator for InfiniteIndex {\n type Item = usize;\n\n fn next(&mut self) -> Option {\n self.i = (self.i + 1) % self.size;\n Some(self.i)\n }\n}\n")),(0,o.kt)("p",null,"However when I'm looking at the code now, it doesn't really make much sense\u2026\nGuess what, we can use a built-in function that is implemented on iterators for\nthat! The function is called ",(0,o.kt)("inlineCode",{parentName:"p"},".cycle()")),(0,o.kt)("p",null,"On the other hand, I am not going to switch to that function, since it would\nintroduce an another myriad of issues caused by the fact that I create iterators\nright away in the constructor of my structure and the iterators would borrow\nboth the jets and shapes which would introduce a lifetime dependency into the\nstructure."),(0,o.kt)("h2",{id:"day-18-boiling-boulders"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/18"},"Day 18: Boiling Boulders")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Let's compute a surface area of some obsidian approximated via coordinates of\ncubes.")),(0,o.kt)("h3",{id:"solution-3"},"Solution"),(0,o.kt)("p",null,"This day is kinda interesting, because it shows how easily you can complicate the\nproblem and also how much can you screw yourself over with the optimization and\n\u201csmart\u201d approach."),(0,o.kt)("p",null,"For the first part you need to find the surface area of an obsidian that is\napproximated by cubes. Now, that is a very easy thing to do, just keep the track\nof already added cubes, and check if the newly added cube touches any face of any\nother cube. Simple, and with a ",(0,o.kt)("inlineCode",{parentName:"p"},"BTreeSet")," relatively efficient way to do it."),(0,o.kt)("p",null,"However the second part lets you on a secret that there may be some surface area\nfrom the \u201cinside\u201d too and you want to know only the one from the outside of the\nobsidian. I have seen some solutions later, but if you check your data, you might\nnotice that the bounding box of all the cubes isn't that big at all. Therefore I\nchose to pre-construct the box beforehand, fill in the cubes and then just run a\nBFS turning all the lava on the outside into the air. Now you just need to check\ncubes and count how many of their faces touch the air."),(0,o.kt)("h2",{id:"day-19-not-enough-minerals"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/19"},"Day 19: Not Enough Minerals")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Finding out the best strategy for building robots to collect geodes.")),(0,o.kt)("h3",{id:"solution-4"},"Solution"),(0,o.kt)("p",null,"Not much interesting stuff to mention apart from the suggestion to never believe\nthat the default implementation given by ",(0,o.kt)("inlineCode",{parentName:"p"},"derive")," macro is what you want, it\ndoesn't have to be. \ud83d\ude04"),(0,o.kt)("h2",{id:"day-20-grove-positioning-system"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/20"},"Day 20: Grove Positioning System")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Shuffling around the ",(0,o.kt)("em",{parentName:"p"},"circular linked list")," to find the coordinates.")),(0,o.kt)("p",null,"Now, small rant for this day is in place. They've never mentioned that coordinates\ncan repeat and therefore the values are non-unique. This is something that did\nnot happen in the given sample, but was present in the user input. It took \xbba lot\xab\nto realize that this is the issue."),(0,o.kt)("h3",{id:"solution-5"},"Solution"),(0,o.kt)("p",null,"I have tried implementing a circular linked list for this\u2026 and I have failed\nmiserably. To be fair, I still have no clue why. It was \u201cfun\u201d to play around with\nthe ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),". In the end I failed on ",(0,o.kt)("em",{parentName:"p"},"wrong answer"),". I have also encountered\na rather interesting issue with ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," method being used on ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),"."),(0,o.kt)("h4",{id:"borrow_mut"},(0,o.kt)("inlineCode",{parentName:"h4"},".borrow_mut()")),(0,o.kt)("p",null,"Consider the following snippet of the code (taken from the documentation):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'use std::cell::{RefCell, RefMut};\nuse std::collections::HashMap;\nuse std::rc::Rc;\n// use std::borrow::BorrowMut;\n\nfn main() {\n let shared_map: Rc> = Rc::new(RefCell::new(HashMap::new()));\n // Create a new block to limit the scope of the dynamic borrow\n {\n let mut map: RefMut<_> = shared_map.borrow_mut();\n map.insert("africa", 92388);\n map.insert("kyoto", 11837);\n map.insert("piccadilly", 11826);\n map.insert("marbles", 38);\n }\n\n // Note that if we had not let the previous borrow of the cache fall out\n // of scope then the subsequent borrow would cause a dynamic thread panic.\n // This is the major hazard of using `RefCell`.\n let total: i32 = shared_map.borrow().values().sum();\n println!("{total}");\n}\n')),(0,o.kt)("p",null,"We allocate a hash map on the heap and then in the inner block, we borrow it as\na mutable reference, so that we can use it."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"It is a very primitive example for ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>")," and mutable borrow.")),(0,o.kt)("p",null,"If you uncomment the 4th line with ",(0,o.kt)("inlineCode",{parentName:"p"},"use std::borrow::BorrowMut;"),", you cannot\ncompile the code anymore, because of"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," Compiling playground v0.0.1 (/playground)\nerror[E0308]: mismatched types\n --\x3e src/main.rs:10:34\n |\n10 | let mut map: RefMut<_> = shared_map.borrow_mut();\n | --------- ^^^^^^^^^^^^^^^^^^^^^^^ expected struct `RefMut`, found mutable reference\n | |\n | expected due to this\n |\n = note: expected struct `RefMut<'_, _>`\n found mutable reference `&mut Rc>>`\n\nerror[E0599]: no method named `insert` found for struct `RefMut<'_, _>` in the current scope\n --\x3e src/main.rs:11:13\n |\n11 | map.insert(\"africa\", 92388);\n | ^^^^^^ method not found in `RefMut<'_, _>`\n\nerror[E0599]: no method named `insert` found for struct `RefMut<'_, _>` in the current scope\n --\x3e src/main.rs:12:13\n |\n12 | map.insert(\"kyoto\", 11837);\n | ^^^^^^ method not found in `RefMut<'_, _>`\n\nerror[E0599]: no method named `insert` found for struct `RefMut<'_, _>` in the current scope\n --\x3e src/main.rs:13:13\n |\n13 | map.insert(\"piccadilly\", 11826);\n | ^^^^^^ method not found in `RefMut<'_, _>`\n\nerror[E0599]: no method named `insert` found for struct `RefMut<'_, _>` in the current scope\n --\x3e src/main.rs:14:13\n |\n14 | map.insert(\"marbles\", 38);\n | ^^^^^^ method not found in `RefMut<'_, _>`\n\nSome errors have detailed explanations: E0308, E0599.\nFor more information about an error, try `rustc --explain E0308`.\nerror: could not compile `playground` due to 5 previous errors\n")),(0,o.kt)("p",null,"It might seem ",(0,o.kt)("strong",{parentName:"p"},"a bit")," ridiculous. However, I got to a point where the compiler\nsuggested ",(0,o.kt)("inlineCode",{parentName:"p"},"use std::borrow::BorrowMut;")," and it resulted in breaking parts of the\ncode that worked previously. I think it may be a good idea to go over what is\nhappening here."),(0,o.kt)("h5",{id:"borrow_mut-on-rcrefcellt"},(0,o.kt)("inlineCode",{parentName:"h5"},".borrow_mut()")," on ",(0,o.kt)("inlineCode",{parentName:"h5"},"Rc>")),(0,o.kt)("p",null,"Let's consider a variable ",(0,o.kt)("inlineCode",{parentName:"p"},"x")," of type ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),". What happens when you\ncall ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," on it? We can look at the ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," type, and\u2026 hang on! There is\nneither ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," method or ",(0,o.kt)("inlineCode",{parentName:"p"},"BorrowMut")," trait implemented. How can we do it\nthen?"),(0,o.kt)("p",null,"Let's go further and we can see that ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell")," implements a ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()"),"\nmethod. OK, but how can we call it on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc"),"? Easily! ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," implements\n",(0,o.kt)("inlineCode",{parentName:"p"},"Deref")," and therefore you can call methods on ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," objects as if they were\n",(0,o.kt)("inlineCode",{parentName:"p"},"T")," objects. If we read on ",(0,o.kt)("em",{parentName:"p"},(0,o.kt)("inlineCode",{parentName:"em"},"Deref")," coercion"),", we can see the following:"),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"If ",(0,o.kt)("inlineCode",{parentName:"p"},"T")," implements ",(0,o.kt)("inlineCode",{parentName:"p"},"Deref"),", \u2026:"),(0,o.kt)("ul",{parentName:"blockquote"},(0,o.kt)("li",{parentName:"ul"},"\u2026"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"T")," implicitly implements all the (immutable) methods of the type ",(0,o.kt)("inlineCode",{parentName:"li"},"U"),"."))),(0,o.kt)("p",null,"What is the requirement for the ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," on ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell"),"? Well, it needs\n",(0,o.kt)("inlineCode",{parentName:"p"},"&self"),", so the ",(0,o.kt)("inlineCode",{parentName:"p"},"Deref")," implements the ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," for the ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),"."),(0,o.kt)("h5",{id:"borrowmut-trait"},(0,o.kt)("inlineCode",{parentName:"h5"},"BorrowMut")," trait"),(0,o.kt)("p",null,"I have not been able to find a lot on this trait. My guess is that it provides a\nmethod instead of a syntactic sugar (",(0,o.kt)("inlineCode",{parentName:"p"},"&mut x"),") for the mutable borrow. And also\nit provides default implementations for the types:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"impl BorrowMut for String\n\nimpl BorrowMut for &mut T\nwhere\n T: ?Sized,\n\nimpl BorrowMut for T\nwhere\n T: ?Sized,\n\nimpl BorrowMut<[T]> for Vec\nwhere\n A: Allocator,\n\nimpl BorrowMut for Box\nwhere\n A: Allocator,\n T: ?Sized,\n\nimpl BorrowMut<[T]> for [T; N]\n")),(0,o.kt)("h5",{id:"conflict"},"Conflict"),(0,o.kt)("p",null,"Now the question is why did it break the code\u2026 My first take was that the type\n",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>")," has some ",(0,o.kt)("em",{parentName:"p"},"specialized")," implementation of the ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," and\nthe ",(0,o.kt)("inlineCode",{parentName:"p"},"use")," overrides it with the default, which is true ",(0,o.kt)("strong",{parentName:"p"},"in a sense"),". However\nthere is no ",(0,o.kt)("em",{parentName:"p"},"specialized")," implementation. Let's have a look at the trait and the\ntype signature on the ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"// trait\npub trait BorrowMut: Borrow\nwhere\n Borrowed: ?Sized,\n{\n fn borrow_mut(&mut self) -> &mut Borrowed;\n}\n\n// \u2039RefCell.borrow_mut()\u203a type signature\npub fn borrow_mut(&self) -> RefMut<'_, T>\n")),(0,o.kt)("p",null,"I think that we can definitely agree on the fact that ",(0,o.kt)("inlineCode",{parentName:"p"},"RefMut<'_, T>")," is not the\n",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell"),"."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"In my opinion"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell")," implements a ",(0,o.kt)("strong",{parentName:"p"},"separate")," ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," rather\nthan implementing the interface, because it ",(0,o.kt)("strong",{parentName:"p"},"cannot")," satisfy the type requirements\nof the trait."),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"I wonder how are we expected to deal with this conflict, if and when, we need\nboth the ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," of the trait and ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," of the ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell"),".")),(0,o.kt)("admonition",{title:"Fun fact",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"I was suggested by the compiler to do ",(0,o.kt)("inlineCode",{parentName:"p"},"use std::borrow::BorrowMut;")," and break the\ncode."),(0,o.kt)("p",{parentName:"admonition"},"So much for the ",(0,o.kt)("em",{parentName:"p"},"almighty")," and ",(0,o.kt)("em",{parentName:"p"},"helpful")," compiler\u2026")),(0,o.kt)("h2",{id:"day-21-monkey-math"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/21"},"Day 21: Monkey Math")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Computing an expression tree and then also finding ideal value for a node.")),(0,o.kt)("h3",{id:"solution-6"},"Solution"),(0,o.kt)("p",null,"Relatively simple, until you get to the 2nd part where you start to practice\na lot of the copy-paste. I have managed to sneak some perverted stuff in there\nthough :) Let's go through the details."),(0,o.kt)("h4",{id:"default-trait"},(0,o.kt)("inlineCode",{parentName:"h4"},"Default")," trait"),(0,o.kt)("p",null,"For the first time and twice I had a need to have a default value for my types,\nenumerations in this case. Rust offers a very nice trait",(0,o.kt)("sup",{parentName:"p",id:"fnref-1-990909"},(0,o.kt)("a",{parentName:"sup",href:"#fn-1-990909",className:"footnote-ref"},"1"))," that is described\nas:"),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"A trait for giving a type a useful default value.")),(0,o.kt)("p",null,"I guess it sums it up nicely. The more interesting part about this is the fact\nthat you can use the ",(0,o.kt)("em",{parentName:"p"},"macro machinery")," to save yourself some typing. If you have\nenumeration of which the default value doesn't bear any parameter, you can just\ndo",(0,o.kt)("sup",{parentName:"p",id:"fnref-2-990909"},(0,o.kt)("a",{parentName:"sup",href:"#fn-2-990909",className:"footnote-ref"},"2")),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"#[derive(Default)]\nenum Color {\n #[default]\n White,\n Gray,\n Black,\n}\n")),(0,o.kt)("h4",{id:"abusing-negation"},"Abusing negation"),(0,o.kt)("p",null,"If you want to use a ",(0,o.kt)("em",{parentName:"p"},"unary minus")," operator on your own type, you can implement\na ",(0,o.kt)("inlineCode",{parentName:"p"},"Neg")," trait",(0,o.kt)("sup",{parentName:"p",id:"fnref-3-990909"},(0,o.kt)("a",{parentName:"sup",href:"#fn-3-990909",className:"footnote-ref"},"3")),". I was dealing with a binary tree and needed a way how to look\nat the other side, so I have just implemented the negation for flipping between\nleft and right \ud83d\ude04"),(0,o.kt)("div",{className:"footnotes"},(0,o.kt)("hr",{parentName:"div"}),(0,o.kt)("ol",{parentName:"div"},(0,o.kt)("li",{parentName:"ol",id:"fn-1-990909"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/std/default/trait.Default.html"},(0,o.kt)("inlineCode",{parentName:"a"},"Default"))," docs",(0,o.kt)("a",{parentName:"li",href:"#fnref-1-990909",className:"footnote-backref"},"\u21a9")),(0,o.kt)("li",{parentName:"ol",id:"fn-2-990909"},"Pardon my example from the graph algorithms ;)",(0,o.kt)("a",{parentName:"li",href:"#fnref-2-990909",className:"footnote-backref"},"\u21a9")),(0,o.kt)("li",{parentName:"ol",id:"fn-3-990909"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/std/ops/trait.Neg.html"},(0,o.kt)("inlineCode",{parentName:"a"},"Neg"))," docs",(0,o.kt)("a",{parentName:"li",href:"#fnref-3-990909",className:"footnote-backref"},"\u21a9")))))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[4064],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>c});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=u(n),h=o,c=d["".concat(s,".").concat(h)]||d[h]||m[h]||i;return n?a.createElement(c,r(r({ref:t},p),{},{components:n})):a.createElement(c,r({ref:t},p))}));function c(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:o,r[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=n(7462),o=(n(7294),n(3905));const i={title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00",slug:"aoc-2022/3rd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},r=void 0,l={permalink:"/blog/aoc-2022/3rd-week",editUrl:"https://github.com/mfocko/blog/tree/main/blog/aoc-2022/03-week-3.md",source:"@site/blog/aoc-2022/03-week-3.md",title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00:00.000Z",formattedDate:"July 6, 2023",tags:[{label:"advent-of-code",permalink:"/blog/tags/advent-of-code"},{label:"advent-of-code-2022",permalink:"/blog/tags/advent-of-code-2022"},{label:"rust",permalink:"/blog/tags/rust"}],readingTime:11.565,hasTruncateMarker:!0,authors:[{name:"Matej Focko",email:"me+blog@mfocko.xyz",title:"a.k.a. @mf",url:"https://gitlab.com/mfocko",imageURL:"https://github.com/mfocko.png",key:"mf"}],frontMatter:{title:"3rd week of Advent of Code '22 in Rust",description:"Surviving third week in Rust.",date:"2023-07-06T21:00",slug:"aoc-2022/3rd-week",authors:"mf",tags:["advent-of-code","advent-of-code-2022","rust"],hide_table_of_contents:!1},prevItem:{title:"4th week of Advent of Code '22 in Rust",permalink:"/blog/aoc-2022/4th-week"},nextItem:{title:"Sort the matrix diagonally",permalink:"/blog/leetcode/sort-diagonally"}},s={authorsImageUrls:[void 0]},u=[{value:"Day 15: Beacon Exclusion Zone",id:"day-15-beacon-exclusion-zone",level:2},{value:"Solution",id:"solution",level:3},{value:"Day 16: Proboscidea Volcanium",id:"day-16-proboscidea-volcanium",level:2},{value:"Solution",id:"solution-1",level:3},{value:"Indexing in graph",id:"indexing-in-graph",level:4},{value:"Cartesian product",id:"cartesian-product",level:4},{value:"\u201cImplementing\u201d an iterator",id:"implementing-an-iterator",level:4},{value:"Day 17: Pyroclastic Flow",id:"day-17-pyroclastic-flow",level:2},{value:"Solution",id:"solution-2",level:3},{value:"Collision detection",id:"collision-detection",level:4},{value:"Infinite iterator",id:"infinite-iterator",level:4},{value:"Day 18: Boiling Boulders",id:"day-18-boiling-boulders",level:2},{value:"Solution",id:"solution-3",level:3},{value:"Day 19: Not Enough Minerals",id:"day-19-not-enough-minerals",level:2},{value:"Solution",id:"solution-4",level:3},{value:"Day 20: Grove Positioning System",id:"day-20-grove-positioning-system",level:2},{value:"Solution",id:"solution-5",level:3},{value:".borrow_mut()",id:"borrow_mut",level:4},{value:".borrow_mut() on Rc<RefCell<T>>",id:"borrow_mut-on-rcrefcellt",level:5},{value:"BorrowMut trait",id:"borrowmut-trait",level:5},{value:"Conflict",id:"conflict",level:5},{value:"Day 21: Monkey Math",id:"day-21-monkey-math",level:2},{value:"Solution",id:"solution-6",level:3},{value:"Default trait",id:"default-trait",level:4},{value:"Abusing negation",id:"abusing-negation",level:4}],p={toc:u},d="wrapper";function m(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Let's go through the third week of ",(0,o.kt)("a",{parentName:"p",href:"https://adventofcode.com"},(0,o.kt)("em",{parentName:"a"},"Advent of Code"))," in Rust."),(0,o.kt)("h2",{id:"day-15-beacon-exclusion-zone"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/15"},"Day 15: Beacon Exclusion Zone")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Triangulating a distress beacon based on the information from the sensors.")),(0,o.kt)("h3",{id:"solution"},"Solution"),(0,o.kt)("p",null,"Relatively easy thing to implement, no major Rust issues hit."),(0,o.kt)("h2",{id:"day-16-proboscidea-volcanium"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/16"},"Day 16: Proboscidea Volcanium")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Finding a max flow in a graph given some time constraints.")),(0,o.kt)("h3",{id:"solution-1"},"Solution"),(0,o.kt)("p",null,"I have used some interesting things to implement this and make it easier for me."),(0,o.kt)("h4",{id:"indexing-in-graph"},"Indexing in graph"),(0,o.kt)("p",null,"I have come across a situation where I needed to keep more information regarding\nthe graph\u2026 In that case you can, of course, create a structure and keep it in,\nbut once you have multiple members in the structure it gets harder to work with\nsince you need to address the fields in the structure. When you work with graph,\nyou frequently need to access the vertices and in this case it felt a lot easier\nto implement the indexing in a graph, rather than explicitly access the\nunderlying data structure."),(0,o.kt)("p",null,"Here you can see a rather short snippet from the solution that allows you to\n\u201cindex\u201d the graph:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"impl Index<&str> for Graph {\n type Output = Vertex;\n\n fn index(&self, index: &str) -> &Self::Output {\n &self.g[index]\n }\n}\n")),(0,o.kt)("h4",{id:"cartesian-product"},"Cartesian product"),(0,o.kt)("p",null,"During the implementation I had to utilize Floyd-Warshall algorithm for finding\nthe shortest path between pairs of vertices and utilized the ",(0,o.kt)("inlineCode",{parentName:"p"},"iproduct!")," macro\nfrom the ",(0,o.kt)("a",{parentName:"p",href:"https://crates.io/crates/itertools"},(0,o.kt)("inlineCode",{parentName:"a"},"itertools")),". It is a very useful higher-order function that allows\nyou to keep the nesting of the loops at a minimum level while still maintaining\nthe same functionality."),(0,o.kt)("h4",{id:"implementing-an-iterator"},"\u201cImplementing\u201d an iterator"),(0,o.kt)("p",null,"For the second part, you get to split the work between 2 actors. That way you\ncan achieve higher efficiency of the whole process that you're planning, but it\nalso makes it harder to evaluate algorithmically, since you need to check the\ndifferent ways the work can be split."),(0,o.kt)("p",null,"Being affected by ",(0,o.kt)("em",{parentName:"p"},"functional programming brain damage"),"\u2122\ufe0f, I have chosen to\ndo this part by function that returns an iterator over the possible ways:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"fn pairings(\n valves: &BTreeSet,\n) -> impl Iterator, BTreeSet)> + '_ {\n let mapping = valves.iter().collect_vec();\n\n let max_mask = 1 << (valves.len() - 1);\n\n (0..max_mask).map(move |mask| {\n let mut elephant = BTreeSet::new();\n let mut human = BTreeSet::new();\n\n for (i, &v) in mapping.iter().enumerate() {\n if (mask & (1 << i)) == 0 {\n human.insert(v.clone());\n } else {\n elephant.insert(v.clone());\n }\n }\n\n (human, elephant)\n })\n}\n")),(0,o.kt)("h2",{id:"day-17-pyroclastic-flow"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/17"},"Day 17: Pyroclastic Flow")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Simulating an autonomous Tetris where pieces get affected by a series of jets of\nhot gas.")),(0,o.kt)("h3",{id:"solution-2"},"Solution"),(0,o.kt)("p",null,"Similarly to the previous day I have created some iterators \ud83d\ude04"),(0,o.kt)("h4",{id:"collision-detection"},"Collision detection"),(0,o.kt)("p",null,"Once you need to check for collisions it is very helpful to be able to just\niterate through the positions that can actually collide with the wall or other\npiece."),(0,o.kt)("p",null,"To get the desired behaviour, you can just compose few smaller functions:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"fn occupied(shape: &[Vec]) -> impl Iterator + '_ {\n shape.iter().enumerate().flat_map(|(y, row)| {\n row.iter().enumerate().filter_map(move |(x, c)| {\n if c == &'#' {\n Some(Vector2D::new(x as isize, y as isize))\n } else {\n None\n }\n })\n })\n}\n")),(0,o.kt)("p",null,"In the end, we get relative positions which we can adjust later when given the\nspecific positions from iterator. You can see some interesting parts in this:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},".enumerate()")," allows us to get both the indices (coordinates) and the line\nor, later on, the character itself,"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},".flat_map()")," flattens the iterator, i.e. when we return another iterator,\nthey just get chained instead of iterating over iterators (which sounds pretty\ndisturbing, doesn't it?),"),(0,o.kt)("li",{parentName:"ul"},"and finally ",(0,o.kt)("inlineCode",{parentName:"li"},".filter_map()")," which is pretty similar to the \u201cbasic\u201d ",(0,o.kt)("inlineCode",{parentName:"li"},".map()"),"\nwith a one, key, difference that it expects the items of an iterator to be\nmapped to an ",(0,o.kt)("inlineCode",{parentName:"li"},"Option")," from which it ignores nothing (as in ",(0,o.kt)("inlineCode",{parentName:"li"},"None")," \ud83d\ude09)\nand also unwraps the values from ",(0,o.kt)("inlineCode",{parentName:"li"},"Some(\u2026)"),".")),(0,o.kt)("h4",{id:"infinite-iterator"},"Infinite iterator"),(0,o.kt)("p",null,"In the solution we cycle through both Tetris-like shapes that fall down and the\njets that move our pieces around. Initially I have implemented my own infinite\niterator that just yields the indices. It is a very simple, yet powerful, piece\nof code:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"struct InfiniteIndex {\n size: usize,\n i: usize,\n}\n\nimpl InfiniteIndex {\n fn new(size: usize) -> InfiniteIndex {\n InfiniteIndex { size, i: size - 1 }\n }\n}\n\nimpl Iterator for InfiniteIndex {\n type Item = usize;\n\n fn next(&mut self) -> Option {\n self.i = (self.i + 1) % self.size;\n Some(self.i)\n }\n}\n")),(0,o.kt)("p",null,"However when I'm looking at the code now, it doesn't really make much sense\u2026\nGuess what, we can use a built-in function that is implemented on iterators for\nthat! The function is called ",(0,o.kt)("inlineCode",{parentName:"p"},".cycle()")),(0,o.kt)("p",null,"On the other hand, I am not going to switch to that function, since it would\nintroduce an another myriad of issues caused by the fact that I create iterators\nright away in the constructor of my structure and the iterators would borrow\nboth the jets and shapes which would introduce a lifetime dependency into the\nstructure."),(0,o.kt)("h2",{id:"day-18-boiling-boulders"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/18"},"Day 18: Boiling Boulders")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Let's compute a surface area of some obsidian approximated via coordinates of\ncubes.")),(0,o.kt)("h3",{id:"solution-3"},"Solution"),(0,o.kt)("p",null,"This day is kinda interesting, because it shows how easily you can complicate the\nproblem and also how much can you screw yourself over with the optimization and\n\u201csmart\u201d approach."),(0,o.kt)("p",null,"For the first part you need to find the surface area of an obsidian that is\napproximated by cubes. Now, that is a very easy thing to do, just keep the track\nof already added cubes, and check if the newly added cube touches any face of any\nother cube. Simple, and with a ",(0,o.kt)("inlineCode",{parentName:"p"},"BTreeSet")," relatively efficient way to do it."),(0,o.kt)("p",null,"However the second part lets you on a secret that there may be some surface area\nfrom the \u201cinside\u201d too and you want to know only the one from the outside of the\nobsidian. I have seen some solutions later, but if you check your data, you might\nnotice that the bounding box of all the cubes isn't that big at all. Therefore I\nchose to pre-construct the box beforehand, fill in the cubes and then just run a\nBFS turning all the lava on the outside into the air. Now you just need to check\ncubes and count how many of their faces touch the air."),(0,o.kt)("h2",{id:"day-19-not-enough-minerals"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/19"},"Day 19: Not Enough Minerals")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Finding out the best strategy for building robots to collect geodes.")),(0,o.kt)("h3",{id:"solution-4"},"Solution"),(0,o.kt)("p",null,"Not much interesting stuff to mention apart from the suggestion to never believe\nthat the default implementation given by ",(0,o.kt)("inlineCode",{parentName:"p"},"derive")," macro is what you want, it\ndoesn't have to be. \ud83d\ude04"),(0,o.kt)("h2",{id:"day-20-grove-positioning-system"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/20"},"Day 20: Grove Positioning System")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Shuffling around the ",(0,o.kt)("em",{parentName:"p"},"circular linked list")," to find the coordinates.")),(0,o.kt)("p",null,"Now, small rant for this day is in place. They've never mentioned that coordinates\ncan repeat and therefore the values are non-unique. This is something that did\nnot happen in the given sample, but was present in the user input. It took \xbba lot\xab\nto realize that this is the issue."),(0,o.kt)("h3",{id:"solution-5"},"Solution"),(0,o.kt)("p",null,"I have tried implementing a circular linked list for this\u2026 and I have failed\nmiserably. To be fair, I still have no clue why. It was \u201cfun\u201d to play around with\nthe ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),". In the end I failed on ",(0,o.kt)("em",{parentName:"p"},"wrong answer"),". I have also encountered\na rather interesting issue with ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," method being used on ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),"."),(0,o.kt)("h4",{id:"borrow_mut"},(0,o.kt)("inlineCode",{parentName:"h4"},".borrow_mut()")),(0,o.kt)("p",null,"Consider the following snippet of the code (taken from the documentation):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'use std::cell::{RefCell, RefMut};\nuse std::collections::HashMap;\nuse std::rc::Rc;\n// use std::borrow::BorrowMut;\n\nfn main() {\n let shared_map: Rc> = Rc::new(RefCell::new(HashMap::new()));\n // Create a new block to limit the scope of the dynamic borrow\n {\n let mut map: RefMut<_> = shared_map.borrow_mut();\n map.insert("africa", 92388);\n map.insert("kyoto", 11837);\n map.insert("piccadilly", 11826);\n map.insert("marbles", 38);\n }\n\n // Note that if we had not let the previous borrow of the cache fall out\n // of scope then the subsequent borrow would cause a dynamic thread panic.\n // This is the major hazard of using `RefCell`.\n let total: i32 = shared_map.borrow().values().sum();\n println!("{total}");\n}\n')),(0,o.kt)("p",null,"We allocate a hash map on the heap and then in the inner block, we borrow it as\na mutable reference, so that we can use it."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"It is a very primitive example for ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>")," and mutable borrow.")),(0,o.kt)("p",null,"If you uncomment the 4th line with ",(0,o.kt)("inlineCode",{parentName:"p"},"use std::borrow::BorrowMut;"),", you cannot\ncompile the code anymore, because of"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"}," Compiling playground v0.0.1 (/playground)\nerror[E0308]: mismatched types\n --\x3e src/main.rs:10:34\n |\n10 | let mut map: RefMut<_> = shared_map.borrow_mut();\n | --------- ^^^^^^^^^^^^^^^^^^^^^^^ expected struct `RefMut`, found mutable reference\n | |\n | expected due to this\n |\n = note: expected struct `RefMut<'_, _>`\n found mutable reference `&mut Rc>>`\n\nerror[E0599]: no method named `insert` found for struct `RefMut<'_, _>` in the current scope\n --\x3e src/main.rs:11:13\n |\n11 | map.insert(\"africa\", 92388);\n | ^^^^^^ method not found in `RefMut<'_, _>`\n\nerror[E0599]: no method named `insert` found for struct `RefMut<'_, _>` in the current scope\n --\x3e src/main.rs:12:13\n |\n12 | map.insert(\"kyoto\", 11837);\n | ^^^^^^ method not found in `RefMut<'_, _>`\n\nerror[E0599]: no method named `insert` found for struct `RefMut<'_, _>` in the current scope\n --\x3e src/main.rs:13:13\n |\n13 | map.insert(\"piccadilly\", 11826);\n | ^^^^^^ method not found in `RefMut<'_, _>`\n\nerror[E0599]: no method named `insert` found for struct `RefMut<'_, _>` in the current scope\n --\x3e src/main.rs:14:13\n |\n14 | map.insert(\"marbles\", 38);\n | ^^^^^^ method not found in `RefMut<'_, _>`\n\nSome errors have detailed explanations: E0308, E0599.\nFor more information about an error, try `rustc --explain E0308`.\nerror: could not compile `playground` due to 5 previous errors\n")),(0,o.kt)("p",null,"It might seem ",(0,o.kt)("strong",{parentName:"p"},"a bit")," ridiculous. However, I got to a point where the compiler\nsuggested ",(0,o.kt)("inlineCode",{parentName:"p"},"use std::borrow::BorrowMut;")," and it resulted in breaking parts of the\ncode that worked previously. I think it may be a good idea to go over what is\nhappening here."),(0,o.kt)("h5",{id:"borrow_mut-on-rcrefcellt"},(0,o.kt)("inlineCode",{parentName:"h5"},".borrow_mut()")," on ",(0,o.kt)("inlineCode",{parentName:"h5"},"Rc>")),(0,o.kt)("p",null,"Let's consider a variable ",(0,o.kt)("inlineCode",{parentName:"p"},"x")," of type ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),". What happens when you\ncall ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," on it? We can look at the ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," type, and\u2026 hang on! There is\nneither ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," method or ",(0,o.kt)("inlineCode",{parentName:"p"},"BorrowMut")," trait implemented. How can we do it\nthen?"),(0,o.kt)("p",null,"Let's go further and we can see that ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell")," implements a ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()"),"\nmethod. OK, but how can we call it on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc"),"? Easily! ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," implements\n",(0,o.kt)("inlineCode",{parentName:"p"},"Deref")," and therefore you can call methods on ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc")," objects as if they were\n",(0,o.kt)("inlineCode",{parentName:"p"},"T")," objects. If we read on ",(0,o.kt)("em",{parentName:"p"},(0,o.kt)("inlineCode",{parentName:"em"},"Deref")," coercion"),", we can see the following:"),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"If ",(0,o.kt)("inlineCode",{parentName:"p"},"T")," implements ",(0,o.kt)("inlineCode",{parentName:"p"},"Deref"),", \u2026:"),(0,o.kt)("ul",{parentName:"blockquote"},(0,o.kt)("li",{parentName:"ul"},"\u2026"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"T")," implicitly implements all the (immutable) methods of the type ",(0,o.kt)("inlineCode",{parentName:"li"},"U"),"."))),(0,o.kt)("p",null,"What is the requirement for the ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," on ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell"),"? Well, it needs\n",(0,o.kt)("inlineCode",{parentName:"p"},"&self"),", so the ",(0,o.kt)("inlineCode",{parentName:"p"},"Deref")," implements the ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," for the ",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>"),"."),(0,o.kt)("h5",{id:"borrowmut-trait"},(0,o.kt)("inlineCode",{parentName:"h5"},"BorrowMut")," trait"),(0,o.kt)("p",null,"I have not been able to find a lot on this trait. My guess is that it provides a\nmethod instead of a syntactic sugar (",(0,o.kt)("inlineCode",{parentName:"p"},"&mut x"),") for the mutable borrow. And also\nit provides default implementations for the types:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"impl BorrowMut for String\n\nimpl BorrowMut for &mut T\nwhere\n T: ?Sized,\n\nimpl BorrowMut for T\nwhere\n T: ?Sized,\n\nimpl BorrowMut<[T]> for Vec\nwhere\n A: Allocator,\n\nimpl BorrowMut for Box\nwhere\n A: Allocator,\n T: ?Sized,\n\nimpl BorrowMut<[T]> for [T; N]\n")),(0,o.kt)("h5",{id:"conflict"},"Conflict"),(0,o.kt)("p",null,"Now the question is why did it break the code\u2026 My first take was that the type\n",(0,o.kt)("inlineCode",{parentName:"p"},"Rc>")," has some ",(0,o.kt)("em",{parentName:"p"},"specialized")," implementation of the ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," and\nthe ",(0,o.kt)("inlineCode",{parentName:"p"},"use")," overrides it with the default, which is true ",(0,o.kt)("strong",{parentName:"p"},"in a sense"),". However\nthere is no ",(0,o.kt)("em",{parentName:"p"},"specialized")," implementation. Let's have a look at the trait and the\ntype signature on the ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"// trait\npub trait BorrowMut: Borrow\nwhere\n Borrowed: ?Sized,\n{\n fn borrow_mut(&mut self) -> &mut Borrowed;\n}\n\n// \u2039RefCell.borrow_mut()\u203a type signature\npub fn borrow_mut(&self) -> RefMut<'_, T>\n")),(0,o.kt)("p",null,"I think that we can definitely agree on the fact that ",(0,o.kt)("inlineCode",{parentName:"p"},"RefMut<'_, T>")," is not the\n",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell"),"."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"In my opinion"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell")," implements a ",(0,o.kt)("strong",{parentName:"p"},"separate")," ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," rather\nthan implementing the interface, because it ",(0,o.kt)("strong",{parentName:"p"},"cannot")," satisfy the type requirements\nof the trait."),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"I wonder how are we expected to deal with this conflict, if and when, we need\nboth the ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," of the trait and ",(0,o.kt)("inlineCode",{parentName:"p"},".borrow_mut()")," of the ",(0,o.kt)("inlineCode",{parentName:"p"},"RefCell"),".")),(0,o.kt)("admonition",{title:"Fun fact",type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"I was suggested by the compiler to do ",(0,o.kt)("inlineCode",{parentName:"p"},"use std::borrow::BorrowMut;")," and break the\ncode."),(0,o.kt)("p",{parentName:"admonition"},"So much for the ",(0,o.kt)("em",{parentName:"p"},"almighty")," and ",(0,o.kt)("em",{parentName:"p"},"helpful")," compiler\u2026")),(0,o.kt)("h2",{id:"day-21-monkey-math"},(0,o.kt)("a",{parentName:"h2",href:"https://adventofcode.com/2022/day/21"},"Day 21: Monkey Math")),(0,o.kt)("admonition",{title:"tl;dr",type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Computing an expression tree and then also finding ideal value for a node.")),(0,o.kt)("h3",{id:"solution-6"},"Solution"),(0,o.kt)("p",null,"Relatively simple, until you get to the 2nd part where you start to practice\na lot of the copy-paste. I have managed to sneak some perverted stuff in there\nthough :) Let's go through the details."),(0,o.kt)("h4",{id:"default-trait"},(0,o.kt)("inlineCode",{parentName:"h4"},"Default")," trait"),(0,o.kt)("p",null,"For the first time and twice I had a need to have a default value for my types,\nenumerations in this case. Rust offers a very nice trait",(0,o.kt)("sup",{parentName:"p",id:"fnref-1-990909"},(0,o.kt)("a",{parentName:"sup",href:"#fn-1-990909",className:"footnote-ref"},"1"))," that is described\nas:"),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"A trait for giving a type a useful default value.")),(0,o.kt)("p",null,"I guess it sums it up nicely. The more interesting part about this is the fact\nthat you can use the ",(0,o.kt)("em",{parentName:"p"},"macro machinery")," to save yourself some typing. If you have\nenumeration of which the default value doesn't bear any parameter, you can just\ndo",(0,o.kt)("sup",{parentName:"p",id:"fnref-2-990909"},(0,o.kt)("a",{parentName:"sup",href:"#fn-2-990909",className:"footnote-ref"},"2")),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"#[derive(Default)]\nenum Color {\n #[default]\n White,\n Gray,\n Black,\n}\n")),(0,o.kt)("h4",{id:"abusing-negation"},"Abusing negation"),(0,o.kt)("p",null,"If you want to use a ",(0,o.kt)("em",{parentName:"p"},"unary minus")," operator on your own type, you can implement\na ",(0,o.kt)("inlineCode",{parentName:"p"},"Neg")," trait",(0,o.kt)("sup",{parentName:"p",id:"fnref-3-990909"},(0,o.kt)("a",{parentName:"sup",href:"#fn-3-990909",className:"footnote-ref"},"3")),". I was dealing with a binary tree and needed a way how to look\nat the other side, so I have just implemented the negation for flipping between\nleft and right \ud83d\ude04"),(0,o.kt)("div",{className:"footnotes"},(0,o.kt)("hr",{parentName:"div"}),(0,o.kt)("ol",{parentName:"div"},(0,o.kt)("li",{parentName:"ol",id:"fn-1-990909"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/std/default/trait.Default.html"},(0,o.kt)("inlineCode",{parentName:"a"},"Default"))," docs",(0,o.kt)("a",{parentName:"li",href:"#fnref-1-990909",className:"footnote-backref"},"\u21a9")),(0,o.kt)("li",{parentName:"ol",id:"fn-2-990909"},"Pardon my example from the graph algorithms ;)",(0,o.kt)("a",{parentName:"li",href:"#fnref-2-990909",className:"footnote-backref"},"\u21a9")),(0,o.kt)("li",{parentName:"ol",id:"fn-3-990909"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/std/ops/trait.Neg.html"},(0,o.kt)("inlineCode",{parentName:"a"},"Neg"))," docs",(0,o.kt)("a",{parentName:"li",href:"#fnref-3-990909",className:"footnote-backref"},"\u21a9")))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f533ef4a.6b0877e2.js b/assets/js/f533ef4a.e27803af.js similarity index 98% rename from assets/js/f533ef4a.6b0877e2.js rename to assets/js/f533ef4a.e27803af.js index 9ecb53f..dfa2bcd 100644 --- a/assets/js/f533ef4a.6b0877e2.js +++ b/assets/js/f533ef4a.e27803af.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2160],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,h=u["".concat(p,".").concat(m)]||u[m]||d[m]||i;return n?r.createElement(h,o(o({ref:t},c),{},{components:n})):r.createElement(h,o({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=n(7462),a=(n(7294),n(3905));const i={id:"seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n"},o=void 0,l={unversionedId:"bonuses/seminar-05-06",id:"bonuses/seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n",source:"@site/pb071/bonuses/05-06.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-05-06",permalink:"/pb071/bonuses/seminar-05-06",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/05-06.md",tags:[],version:"current",lastUpdatedAt:1694110423,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n"},sidebar:"autogeneratedBar",previous:{title:"4th seminar",permalink:"/pb071/bonuses/seminar-04"},next:{title:"8th seminar",permalink:"/pb071/bonuses/seminar-08"}},p={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Task no. 1: Reverse (0.5 K\u20a1)",id:"task-no-1-reverse-05-k",level:3},{value:"Task no. 2: Vigen\xe8re (0.5 K\u20a1)",id:"task-no-2-vigen\xe8re-05-k",level:3},{value:"Bonus part (0.5 K\u20a1)",id:"bonus-part-05-k",level:4},{value:"Task no. 3: Bit madness (0.5 K\u20a1)",id:"task-no-3-bit-madness-05-k",level:3},{value:"Task no. 4: All combined to BMP (0.5 K\u20a1)",id:"task-no-4-all-combined-to-bmp-05-k",level:3},{value:"Submitting",id:"submitting",level:2}],c={toc:s},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"For this bonus you can get at maximum 2.5 K\u20a1."),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/05-06.tar.gz"},"Source")),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"In this bonus you will implement few functions that will be used together for\nimplementing a very special cipher."),(0,a.kt)("h3",{id:"task-no-1-reverse-05-k"},"Task no. 1: Reverse (0.5 K\u20a1)"),(0,a.kt)("p",null,"Write a function ",(0,a.kt)("inlineCode",{parentName:"p"},"char* reverse(const char* text)")," that returns copy of the input\nstring in reversed order (also uppercase)."),(0,a.kt)("p",null,"In case you are given ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL"),", return ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL"),"."),(0,a.kt)("p",null,"Example (more in tests):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'char* reversed = reverse("Hello world!");\n\nprintf("%s\\n", reversed);\n// "!DLROW OLLEH"\n\nif (reversed != NULL) {\n free(reversed);\n}\n')),(0,a.kt)("h3",{id:"task-no-2-vigen\xe8re-05-k"},"Task no. 2: Vigen\xe8re (0.5 K\u20a1)"),(0,a.kt)("p",null,"Vigen\xe8re cipher is similar to the Caesar cipher, but you also have a key that is\nused for encrypting (or decrypting)."),(0,a.kt)("p",null,"Your task is to write two functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* vigenere_encrypt(const char* key, const char* text)")," for encrypting"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* vigenere_decrypt(const char* key, const char* text)")," for decrypting")),(0,a.kt)("p",null,"In both of those you should return uppercase characters."),(0,a.kt)("p",null,"Meaning of the parameters you are given:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"key")," - String that represents key that is used for ","*","crypting. It consists of\none word and can have only characters of the alphabet. Does not matter if they\nare uppercase or lowercase."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"text")," - String that is to be ","*","crypted.")),(0,a.kt)("p",null,"Function returns address of the encrypted (or decrypted) string. Or ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL")," in case\nerror occurs."),(0,a.kt)("p",null,"Example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'char *encrypted = vigenere_encrypt("CoMPuTeR", "Hello world!");\n\nprintf("%s\\n", encrypted);\n// "JSXAI PSINR!"\n\nif (encrypted != NULL) {\n free(encrypted)\n}\n')),(0,a.kt)("h4",{id:"bonus-part-05-k"},"Bonus part (0.5 K\u20a1)"),(0,a.kt)("p",null,"If you can utilize helper function that would do both encrypting and decrypting,\nyou can gain 0.5 K\u20a1."),(0,a.kt)("p",null,"Usage of ",(0,a.kt)("inlineCode",{parentName:"p"},"true"),"/",(0,a.kt)("inlineCode",{parentName:"p"},"false")," to decide path in code is prohibited. It leads to merging\nof both functions into one. Point of this part is to discover a way to do this\ngenerically in such way that there are no separate paths for one or the other. One\nfunction with no branching for both of them, parametrization is your friend :)"),(0,a.kt)("h3",{id:"task-no-3-bit-madness-05-k"},"Task no. 3: Bit madness (0.5 K\u20a1)"),(0,a.kt)("p",null,"This is a state of the art crypto. Please do not share :)"),(0,a.kt)("p",null,"For encrypting:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Split the character that is to be encrypted in halves (4 and 4 bits each)."),(0,a.kt)("li",{parentName:"ol"},"Bits in 1st half are to be split into pairs. Swap bits in those pairs."),(0,a.kt)("li",{parentName:"ol"},"Then use the 4 bits that you created in the 2nd step for ",(0,a.kt)("inlineCode",{parentName:"li"},"XOR")," with the other\n4 bits.")),(0,a.kt)("p",null,"This simple and ingenious principle will be illustrated on the following example.\nString we want to encrypt is ",(0,a.kt)("inlineCode",{parentName:"p"},"Hello world!"),". We need to encrypt each letter separately,\nso we will demonstrate on letter ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),":"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Letter ",(0,a.kt)("inlineCode",{parentName:"p"},"H")," is represented in ASCII as ",(0,a.kt)("inlineCode",{parentName:"p"},"72"),"."),(0,a.kt)("p",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"p"},"72")," represented in binary is: ",(0,a.kt)("inlineCode",{parentName:"p"},"01001000"),". So first 4 bits are: ",(0,a.kt)("inlineCode",{parentName:"p"},"0100")," and last\n4 bits are ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"First half of bits (",(0,a.kt)("inlineCode",{parentName:"p"},"0100"),") consists of 2 pairs (",(0,a.kt)("inlineCode",{parentName:"p"},"01")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"00"),") which we swap\n(",(0,a.kt)("inlineCode",{parentName:"p"},"01 ~> 10")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"00 ~> 00"),"). That way we get ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"That half is used for xor with the other 4 bits:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"}," 1000 // second half\nXOR 1000 // first half after 2nd step\n--------\n 0000\n"))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Now we combine both halves (first one is ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),", which we got from the 2nd step\nand second one is ",(0,a.kt)("inlineCode",{parentName:"p"},"0000"),", which we got from the 3rd step) and get ",(0,a.kt)("inlineCode",{parentName:"p"},"10000000"),",\nwhich is encrypted character ",(0,a.kt)("inlineCode",{parentName:"p"},"H")," using this method."))),(0,a.kt)("p",null,"In case of decryption, reverse those steps."),(0,a.kt)("p",null,"Your task is to implement functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unsigned char* bit_encrypt(const char* text)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* bit_decrypt(const unsigned char* text)"))),(0,a.kt)("p",null,"Example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'unsigned char* encrypted = bit_encrypt("Hello world!");\n\nfor (int i = 0; i < 12;i++) {\n printf("%x ", encrypted[i]);\n //80 9c 95 95 96 11 bc 96 b9 95 9d 10\n}\n\nif (encrypted != NULL) {\n free(encrypted);\n}\n')),(0,a.kt)("h3",{id:"task-no-4-all-combined-to-bmp-05-k"},"Task no. 4: All combined to BMP (0.5 K\u20a1)"),(0,a.kt)("p",null,"Authors of the BMP cipher are non-disclosed :)"),(0,a.kt)("p",null,"Create pair of functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unsigned char* bmp_encrypt(const char* key, const char* text)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* bmp_decrypt(const char* key, const unsigned char* text)"))),(0,a.kt)("p",null,"BMP cipher consists of following steps for encrypting:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Reverse the input string"),(0,a.kt)("li",{parentName:"ol"},"Use Vigenere on the string you got from step #1"),(0,a.kt)("li",{parentName:"ol"},"Use bit madness on the string you got from step #2")),(0,a.kt)("p",null,"For decrypting, reverse the steps."),(0,a.kt)("h2",{id:"submitting"},"Submitting"),(0,a.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,a.kt)("hr",null))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2160],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,h=u["".concat(p,".").concat(m)]||u[m]||d[m]||i;return n?r.createElement(h,o(o({ref:t},c),{},{components:n})):r.createElement(h,o({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=n(7462),a=(n(7294),n(3905));const i={id:"seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n"},o=void 0,l={unversionedId:"bonuses/seminar-05-06",id:"bonuses/seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n",source:"@site/pb071/bonuses/05-06.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-05-06",permalink:"/pb071/bonuses/seminar-05-06",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/bonuses/05-06.md",tags:[],version:"current",lastUpdatedAt:1694111094,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n"},sidebar:"autogeneratedBar",previous:{title:"4th seminar",permalink:"/pb071/bonuses/seminar-04"},next:{title:"8th seminar",permalink:"/pb071/bonuses/seminar-08"}},p={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Task no. 1: Reverse (0.5 K\u20a1)",id:"task-no-1-reverse-05-k",level:3},{value:"Task no. 2: Vigen\xe8re (0.5 K\u20a1)",id:"task-no-2-vigen\xe8re-05-k",level:3},{value:"Bonus part (0.5 K\u20a1)",id:"bonus-part-05-k",level:4},{value:"Task no. 3: Bit madness (0.5 K\u20a1)",id:"task-no-3-bit-madness-05-k",level:3},{value:"Task no. 4: All combined to BMP (0.5 K\u20a1)",id:"task-no-4-all-combined-to-bmp-05-k",level:3},{value:"Submitting",id:"submitting",level:2}],c={toc:s},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"For this bonus you can get at maximum 2.5 K\u20a1."),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/05-06.tar.gz"},"Source")),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"In this bonus you will implement few functions that will be used together for\nimplementing a very special cipher."),(0,a.kt)("h3",{id:"task-no-1-reverse-05-k"},"Task no. 1: Reverse (0.5 K\u20a1)"),(0,a.kt)("p",null,"Write a function ",(0,a.kt)("inlineCode",{parentName:"p"},"char* reverse(const char* text)")," that returns copy of the input\nstring in reversed order (also uppercase)."),(0,a.kt)("p",null,"In case you are given ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL"),", return ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL"),"."),(0,a.kt)("p",null,"Example (more in tests):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'char* reversed = reverse("Hello world!");\n\nprintf("%s\\n", reversed);\n// "!DLROW OLLEH"\n\nif (reversed != NULL) {\n free(reversed);\n}\n')),(0,a.kt)("h3",{id:"task-no-2-vigen\xe8re-05-k"},"Task no. 2: Vigen\xe8re (0.5 K\u20a1)"),(0,a.kt)("p",null,"Vigen\xe8re cipher is similar to the Caesar cipher, but you also have a key that is\nused for encrypting (or decrypting)."),(0,a.kt)("p",null,"Your task is to write two functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* vigenere_encrypt(const char* key, const char* text)")," for encrypting"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* vigenere_decrypt(const char* key, const char* text)")," for decrypting")),(0,a.kt)("p",null,"In both of those you should return uppercase characters."),(0,a.kt)("p",null,"Meaning of the parameters you are given:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"key")," - String that represents key that is used for ","*","crypting. It consists of\none word and can have only characters of the alphabet. Does not matter if they\nare uppercase or lowercase."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"text")," - String that is to be ","*","crypted.")),(0,a.kt)("p",null,"Function returns address of the encrypted (or decrypted) string. Or ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL")," in case\nerror occurs."),(0,a.kt)("p",null,"Example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'char *encrypted = vigenere_encrypt("CoMPuTeR", "Hello world!");\n\nprintf("%s\\n", encrypted);\n// "JSXAI PSINR!"\n\nif (encrypted != NULL) {\n free(encrypted)\n}\n')),(0,a.kt)("h4",{id:"bonus-part-05-k"},"Bonus part (0.5 K\u20a1)"),(0,a.kt)("p",null,"If you can utilize helper function that would do both encrypting and decrypting,\nyou can gain 0.5 K\u20a1."),(0,a.kt)("p",null,"Usage of ",(0,a.kt)("inlineCode",{parentName:"p"},"true"),"/",(0,a.kt)("inlineCode",{parentName:"p"},"false")," to decide path in code is prohibited. It leads to merging\nof both functions into one. Point of this part is to discover a way to do this\ngenerically in such way that there are no separate paths for one or the other. One\nfunction with no branching for both of them, parametrization is your friend :)"),(0,a.kt)("h3",{id:"task-no-3-bit-madness-05-k"},"Task no. 3: Bit madness (0.5 K\u20a1)"),(0,a.kt)("p",null,"This is a state of the art crypto. Please do not share :)"),(0,a.kt)("p",null,"For encrypting:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Split the character that is to be encrypted in halves (4 and 4 bits each)."),(0,a.kt)("li",{parentName:"ol"},"Bits in 1st half are to be split into pairs. Swap bits in those pairs."),(0,a.kt)("li",{parentName:"ol"},"Then use the 4 bits that you created in the 2nd step for ",(0,a.kt)("inlineCode",{parentName:"li"},"XOR")," with the other\n4 bits.")),(0,a.kt)("p",null,"This simple and ingenious principle will be illustrated on the following example.\nString we want to encrypt is ",(0,a.kt)("inlineCode",{parentName:"p"},"Hello world!"),". We need to encrypt each letter separately,\nso we will demonstrate on letter ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),":"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Letter ",(0,a.kt)("inlineCode",{parentName:"p"},"H")," is represented in ASCII as ",(0,a.kt)("inlineCode",{parentName:"p"},"72"),"."),(0,a.kt)("p",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"p"},"72")," represented in binary is: ",(0,a.kt)("inlineCode",{parentName:"p"},"01001000"),". So first 4 bits are: ",(0,a.kt)("inlineCode",{parentName:"p"},"0100")," and last\n4 bits are ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"First half of bits (",(0,a.kt)("inlineCode",{parentName:"p"},"0100"),") consists of 2 pairs (",(0,a.kt)("inlineCode",{parentName:"p"},"01")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"00"),") which we swap\n(",(0,a.kt)("inlineCode",{parentName:"p"},"01 ~> 10")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"00 ~> 00"),"). That way we get ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"That half is used for xor with the other 4 bits:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"}," 1000 // second half\nXOR 1000 // first half after 2nd step\n--------\n 0000\n"))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Now we combine both halves (first one is ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),", which we got from the 2nd step\nand second one is ",(0,a.kt)("inlineCode",{parentName:"p"},"0000"),", which we got from the 3rd step) and get ",(0,a.kt)("inlineCode",{parentName:"p"},"10000000"),",\nwhich is encrypted character ",(0,a.kt)("inlineCode",{parentName:"p"},"H")," using this method."))),(0,a.kt)("p",null,"In case of decryption, reverse those steps."),(0,a.kt)("p",null,"Your task is to implement functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unsigned char* bit_encrypt(const char* text)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* bit_decrypt(const unsigned char* text)"))),(0,a.kt)("p",null,"Example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'unsigned char* encrypted = bit_encrypt("Hello world!");\n\nfor (int i = 0; i < 12;i++) {\n printf("%x ", encrypted[i]);\n //80 9c 95 95 96 11 bc 96 b9 95 9d 10\n}\n\nif (encrypted != NULL) {\n free(encrypted);\n}\n')),(0,a.kt)("h3",{id:"task-no-4-all-combined-to-bmp-05-k"},"Task no. 4: All combined to BMP (0.5 K\u20a1)"),(0,a.kt)("p",null,"Authors of the BMP cipher are non-disclosed :)"),(0,a.kt)("p",null,"Create pair of functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unsigned char* bmp_encrypt(const char* key, const char* text)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* bmp_decrypt(const char* key, const unsigned char* text)"))),(0,a.kt)("p",null,"BMP cipher consists of following steps for encrypting:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Reverse the input string"),(0,a.kt)("li",{parentName:"ol"},"Use Vigenere on the string you got from step #1"),(0,a.kt)("li",{parentName:"ol"},"Use bit madness on the string you got from step #2")),(0,a.kt)("p",null,"For decrypting, reverse the steps."),(0,a.kt)("h2",{id:"submitting"},"Submitting"),(0,a.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,a.kt)("hr",null))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f60c832f.d6dc7ae0.js b/assets/js/f60c832f.186a1d8e.js similarity index 99% rename from assets/js/f60c832f.d6dc7ae0.js rename to assets/js/f60c832f.186a1d8e.js index b92731e..b3dda48 100644 --- a/assets/js/f60c832f.d6dc7ae0.js +++ b/assets/js/f60c832f.186a1d8e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9611],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),l=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=m(e,["components","mdxType","originalType","parentName"]),u=l(a),d=r,h=u["".concat(s,".").concat(d)]||u[d]||c[d]||i;return a?n.createElement(h,o(o({ref:t},p),{},{components:a})):n.createElement(h,o({ref:t},p))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=d;var m={};for(var s in t)hasOwnProperty.call(t,s)&&(m[s]=t[s]);m.originalType=e,m[u]="string"==typeof e?e:r,o[1]=m;for(var l=2;l{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>m,toc:()=>l});var n=a(7462),r=(a(7294),a(3905));const i={slug:"garbage_collect",title:"Practice exam B",description:"Garbage everywhere\u2026\n",last_update:{date:new Date("2023-05-08T00:00:00.000Z")}},o="Garbage Collection",m={unversionedId:"pexam/b-garbage_collect",id:"pexam/b-garbage_collect",title:"Practice exam B",description:"Garbage everywhere\u2026\n",source:"@site/pb071/pexam/b-garbage_collect.md",sourceDirName:"pexam",slug:"/pexam/garbage_collect",permalink:"/pb071/pexam/garbage_collect",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/pexam/b-garbage_collect.md",tags:[],version:"current",lastUpdatedAt:1683504e3,formattedLastUpdatedAt:"May 8, 2023",frontMatter:{slug:"garbage_collect",title:"Practice exam B",description:"Garbage everywhere\u2026\n",last_update:{date:"2023-05-08T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Practice Exams",permalink:"/pb071/category/practice-exams"},next:{title:"Practice exam C",permalink:"/pb071/pexam/cams"}},s={},l=[{value:"Format of the shell history",id:"format-of-the-shell-history",level:2},{value:"Format of the output",id:"format-of-the-output",level:2},{value:"-gt \u2039min_size\u203a",id:"-gt-min_size",level:3},{value:"-f \u2039total_size\u203a \u2039min_unused\u203a",id:"-f-total_size-min_unused",level:3},{value:"Example usage",id:"example-usage",level:2},{value:"Requirements and notes",id:"requirements-and-notes",level:2}],p={toc:l},u="wrapper";function c(e){let{components:t,...a}=e;return(0,r.kt)(u,(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"garbage-collection"},"Garbage Collection"),(0,r.kt)("admonition",{title:"Exam environment",type:"caution"},(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"During the exam you will be provided with a barebone ",(0,r.kt)("em",{parentName:"li"},"exam session")," on the\n",(0,r.kt)("em",{parentName:"li"},"faculty computers"),"."),(0,r.kt)("li",{parentName:"ul"},"In browser you are only allowed to have the following tabs open:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.cppreference.com"},"C documentation")),(0,r.kt)("li",{parentName:"ul"},"page containing the assignment"))),(0,r.kt)("li",{parentName:"ul"},"You ",(0,r.kt)("strong",{parentName:"li"},"are not")," allowed to use your own source code, e.g. prepared beforehand\nor from the seminars."),(0,r.kt)("li",{parentName:"ul"},"You have ",(0,r.kt)("strong",{parentName:"li"},"5 minutes")," to read through the assignment and ask any follow-up\nquestions should be there something unclear."),(0,r.kt)("li",{parentName:"ul"},"You have ",(0,r.kt)("strong",{parentName:"li"},"60 minutes")," to work on the assignment, afterward your work will be\ndiscussed with your seminar tutor."))),(0,r.kt)("p",null,"You have gotten into a trouble during your regular upgrade of your archLinux",(0,r.kt)("sup",{parentName:"p",id:"fnref-1"},(0,r.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),"\ninstallation\u2026 You've been carelessly running the upgrades for months and forgot\nabout clearing up the caches."),(0,r.kt)("p",null,"Your task is to write a program ",(0,r.kt)("inlineCode",{parentName:"p"},"garbage_collect")," that will evaluate the shell\nhistory provided as a file and will try to find files or directories that are\nsuspiciously big and decide which of them should be deleted to free some space."),(0,r.kt)("h2",{id:"format-of-the-shell-history"},"Format of the shell history"),(0,r.kt)("p",null,"You are provided one file consisting of the captured buffer of the terminal. You\ncan see only two commands being used:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"cd \u2039somewhere\u203a")," that changes the current working directory."),(0,r.kt)("p",{parentName:"li"},"At the beginning you start in the root of the filesystem (i.e. ",(0,r.kt)("inlineCode",{parentName:"p"},"/"),")."),(0,r.kt)("p",{parentName:"li"},"You are ",(0,r.kt)("strong",{parentName:"p"},"guaranteed")," that ",(0,r.kt)("inlineCode",{parentName:"p"},"\u2039somewhere\u203a")," is:"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},".")," that is a current working directory (i.e. does nothing),"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"..")," that moves you up one level (in case you are in ",(0,r.kt)("inlineCode",{parentName:"li"},"/"),", does nothing), or"),(0,r.kt)("li",{parentName:"ul"},"is a valid directory in the current working directory.")),(0,r.kt)("admonition",{parentName:"li",type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"There are no guarantees or restrictions on the names of the files or\ndirectories!"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"ls")," that will list files in the current working directory and their\nrespective sizes. If there is a directory in the current working it has ",(0,r.kt)("inlineCode",{parentName:"p"},"dir"),"\ninstead of the size."))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ ls\ndir a\n14848514 b.txt\n8504156 c.dat\ndir d\n$ cd a\n$ cd .\n$ cd .\n$ cd .\n$ ls\ndir e\n29116 f\n2557 g\n62596 h.lst\n$ cd e\n$ ls\n584 i\n$ cd ..\n$ cd ..\n$ cd d\n$ ls\n4060174 j\n8033020 d.log\n5626152 d.ext\n7214296 k\n")),(0,r.kt)("p",null,"For this input, you will get following file system:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"- / (dir, size=48381165)\n - a (dir, size=94853)\n - e (dir, size=584)\n - i (file, size=584)\n - f (file, size=29116)\n - g (file, size=2557)\n - h.lst (file, size=62596)\n - b.txt (file, size=14848514)\n - c.dat (file, size=8504156)\n - d (dir, size=24933642)\n - j (file, size=4060174)\n - d.log (file, size=8033020)\n - d.ext (file, size=5626152)\n - k (file, size=7214296)\n")),(0,r.kt)("h2",{id:"format-of-the-output"},"Format of the output"),(0,r.kt)("p",null,"Your program should support 2 switches:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"-gt \u2039min_size\u203a")," that will print out suspiciously big files."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"-f \u2039total_size\u203a \u2039min_unused\u203a")," that will print out a file to be deleted.")),(0,r.kt)("h3",{id:"-gt-min_size"},(0,r.kt)("inlineCode",{parentName:"h3"},"-gt \u2039min_size\u203a")),(0,r.kt)("p",null,"With this switch you are provided one additional argument:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"min_size")," that is the lower bound (inclusive) for size of any file or\ndirectory that is supposed to be listed.")),(0,r.kt)("p",null,"When your program is being run with this switch, it is is supposed to print out\nall files ",(0,r.kt)("strong",{parentName:"p"},"and")," directories that are bigger than the provided ",(0,r.kt)("inlineCode",{parentName:"p"},"min_size"),"."),(0,r.kt)("h3",{id:"-f-total_size-min_unused"},(0,r.kt)("inlineCode",{parentName:"h3"},"-f \u2039total_size\u203a \u2039min_unused\u203a")),(0,r.kt)("p",null,"With this switch you are provided two additional arguments:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"total_size")," that is a total size of the filesystem",(0,r.kt)("sup",{parentName:"li",id:"fnref-2"},(0,r.kt)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2")),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"min_unused")," that is a minimum of free space required for an upgrade.")),(0,r.kt)("p",null,"Your program should find ",(0,r.kt)("strong",{parentName:"p"},"exactly one")," file or a directory that is of the\nsmallest size, but big enough to free enough space for the upgrade to proceed."),(0,r.kt)("p",null,"In other words, if that file or directory is deleted, following should hold:"),(0,r.kt)("div",{className:"math math-display"},(0,r.kt)("span",{parentName:"div",className:"katex-display"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mrow",{parentName:"mrow"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"o"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"_"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"s"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"z"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e")),(0,r.kt)("mo",{parentName:"mrow"},"\u2212"),(0,r.kt)("mrow",{parentName:"mrow"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"u"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"s"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d")),(0,r.kt)("mo",{parentName:"mrow"},"\u2265"),(0,r.kt)("mrow",{parentName:"mrow"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"_"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"u"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"u"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"s"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d"))),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathtt{total\\_size} - \\mathtt{used} \\geq \\mathtt{min\\_unused}")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7063em",verticalAlign:"-0.0951em"}}),(0,r.kt)("span",{parentName:"span",className:"mord"},(0,r.kt)("span",{parentName:"span",className:"mord mathtt"},"total_size")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,r.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7719em",verticalAlign:"-0.136em"}}),(0,r.kt)("span",{parentName:"span",className:"mord"},(0,r.kt)("span",{parentName:"span",className:"mord mathtt"},"used")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,r.kt)("span",{parentName:"span",className:"mrel"},"\u2265"),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7063em",verticalAlign:"-0.0951em"}}),(0,r.kt)("span",{parentName:"span",className:"mord"},(0,r.kt)("span",{parentName:"span",className:"mord mathtt"},"min_unused"))))))),(0,r.kt)("h2",{id:"example-usage"},"Example usage"),(0,r.kt)("p",null,"You can have a look at the example usage of your program. We can run your\nprogram from the shell like"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ ./garbage_collect shell_history.txt -gt 10000000\n24933642 /d\n14848514 /b.txt\n48381165 /\n\n$ ./garbage_collect shell_history.txt -f 70000000 30000000\n24933642 /d\n")),(0,r.kt)("h2",{id:"requirements-and-notes"},"Requirements and notes"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Define ",(0,r.kt)("strong",{parentName:"li"},"structures")," (and ",(0,r.kt)("strong",{parentName:"li"},"enumerations"),", if applicable) for the parsed\ninformation from the files."),(0,r.kt)("li",{parentName:"ul"},"For keeping the \u201crecords\u201d, use some ",(0,r.kt)("strong",{parentName:"li"},"dynamic")," data structure.",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Don't forget to consider pros and cons of using ",(0,r.kt)("em",{parentName:"li"},"specific")," data structures\nbefore going through implementing."))),(0,r.kt)("li",{parentName:"ul"},"You ",(0,r.kt)("strong",{parentName:"li"},"are not required")," to produce 1:1 output to the provided examples, they\nare just a hint to not waste your time tinkering with a user experience."),(0,r.kt)("li",{parentName:"ul"},"If any of the operations on the input files should fail,\n",(0,r.kt)("strong",{parentName:"li"},"you are expected to")," handle the situation ",(0,r.kt)("em",{parentName:"li"},"accordingly"),"."),(0,r.kt)("li",{parentName:"ul"},"Failures of any other common functions (e.g. functions used for memory\nmanagement) should be handled in ",(0,r.kt)("strong",{parentName:"li"},"the same way")," as they were in the\nhomeworks and seminars."),(0,r.kt)("li",{parentName:"ul"},"Your program ",(0,r.kt)("strong",{parentName:"li"},"must free")," all the resources before exiting.")),(0,r.kt)("div",{className:"footnotes"},(0,r.kt)("hr",{parentName:"div"}),(0,r.kt)("ol",{parentName:"div"},(0,r.kt)("li",{parentName:"ol",id:"fn-1"},"Also applies to Fedora, but\u2026 we use arch btw \ud83d\ude09",(0,r.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,r.kt)("li",{parentName:"ol",id:"fn-2"},"duh!",(0,r.kt)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9611],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),l=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=m(e,["components","mdxType","originalType","parentName"]),u=l(a),d=r,h=u["".concat(s,".").concat(d)]||u[d]||c[d]||i;return a?n.createElement(h,o(o({ref:t},p),{},{components:a})):n.createElement(h,o({ref:t},p))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=d;var m={};for(var s in t)hasOwnProperty.call(t,s)&&(m[s]=t[s]);m.originalType=e,m[u]="string"==typeof e?e:r,o[1]=m;for(var l=2;l{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>m,toc:()=>l});var n=a(7462),r=(a(7294),a(3905));const i={slug:"garbage_collect",title:"Practice exam B",description:"Garbage everywhere\u2026\n",last_update:{date:new Date("2023-05-08T00:00:00.000Z")}},o="Garbage Collection",m={unversionedId:"pexam/b-garbage_collect",id:"pexam/b-garbage_collect",title:"Practice exam B",description:"Garbage everywhere\u2026\n",source:"@site/pb071/pexam/b-garbage_collect.md",sourceDirName:"pexam",slug:"/pexam/garbage_collect",permalink:"/pb071/pexam/garbage_collect",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/pb071/pexam/b-garbage_collect.md",tags:[],version:"current",lastUpdatedAt:1683504e3,formattedLastUpdatedAt:"May 8, 2023",frontMatter:{slug:"garbage_collect",title:"Practice exam B",description:"Garbage everywhere\u2026\n",last_update:{date:"2023-05-08T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Practice Exams",permalink:"/pb071/category/practice-exams"},next:{title:"Practice exam C",permalink:"/pb071/pexam/cams"}},s={},l=[{value:"Format of the shell history",id:"format-of-the-shell-history",level:2},{value:"Format of the output",id:"format-of-the-output",level:2},{value:"-gt \u2039min_size\u203a",id:"-gt-min_size",level:3},{value:"-f \u2039total_size\u203a \u2039min_unused\u203a",id:"-f-total_size-min_unused",level:3},{value:"Example usage",id:"example-usage",level:2},{value:"Requirements and notes",id:"requirements-and-notes",level:2}],p={toc:l},u="wrapper";function c(e){let{components:t,...a}=e;return(0,r.kt)(u,(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"garbage-collection"},"Garbage Collection"),(0,r.kt)("admonition",{title:"Exam environment",type:"caution"},(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"During the exam you will be provided with a barebone ",(0,r.kt)("em",{parentName:"li"},"exam session")," on the\n",(0,r.kt)("em",{parentName:"li"},"faculty computers"),"."),(0,r.kt)("li",{parentName:"ul"},"In browser you are only allowed to have the following tabs open:",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.cppreference.com"},"C documentation")),(0,r.kt)("li",{parentName:"ul"},"page containing the assignment"))),(0,r.kt)("li",{parentName:"ul"},"You ",(0,r.kt)("strong",{parentName:"li"},"are not")," allowed to use your own source code, e.g. prepared beforehand\nor from the seminars."),(0,r.kt)("li",{parentName:"ul"},"You have ",(0,r.kt)("strong",{parentName:"li"},"5 minutes")," to read through the assignment and ask any follow-up\nquestions should be there something unclear."),(0,r.kt)("li",{parentName:"ul"},"You have ",(0,r.kt)("strong",{parentName:"li"},"60 minutes")," to work on the assignment, afterward your work will be\ndiscussed with your seminar tutor."))),(0,r.kt)("p",null,"You have gotten into a trouble during your regular upgrade of your archLinux",(0,r.kt)("sup",{parentName:"p",id:"fnref-1"},(0,r.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),"\ninstallation\u2026 You've been carelessly running the upgrades for months and forgot\nabout clearing up the caches."),(0,r.kt)("p",null,"Your task is to write a program ",(0,r.kt)("inlineCode",{parentName:"p"},"garbage_collect")," that will evaluate the shell\nhistory provided as a file and will try to find files or directories that are\nsuspiciously big and decide which of them should be deleted to free some space."),(0,r.kt)("h2",{id:"format-of-the-shell-history"},"Format of the shell history"),(0,r.kt)("p",null,"You are provided one file consisting of the captured buffer of the terminal. You\ncan see only two commands being used:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"cd \u2039somewhere\u203a")," that changes the current working directory."),(0,r.kt)("p",{parentName:"li"},"At the beginning you start in the root of the filesystem (i.e. ",(0,r.kt)("inlineCode",{parentName:"p"},"/"),")."),(0,r.kt)("p",{parentName:"li"},"You are ",(0,r.kt)("strong",{parentName:"p"},"guaranteed")," that ",(0,r.kt)("inlineCode",{parentName:"p"},"\u2039somewhere\u203a")," is:"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},".")," that is a current working directory (i.e. does nothing),"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"..")," that moves you up one level (in case you are in ",(0,r.kt)("inlineCode",{parentName:"li"},"/"),", does nothing), or"),(0,r.kt)("li",{parentName:"ul"},"is a valid directory in the current working directory.")),(0,r.kt)("admonition",{parentName:"li",type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"There are no guarantees or restrictions on the names of the files or\ndirectories!"))),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"ls")," that will list files in the current working directory and their\nrespective sizes. If there is a directory in the current working it has ",(0,r.kt)("inlineCode",{parentName:"p"},"dir"),"\ninstead of the size."))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ ls\ndir a\n14848514 b.txt\n8504156 c.dat\ndir d\n$ cd a\n$ cd .\n$ cd .\n$ cd .\n$ ls\ndir e\n29116 f\n2557 g\n62596 h.lst\n$ cd e\n$ ls\n584 i\n$ cd ..\n$ cd ..\n$ cd d\n$ ls\n4060174 j\n8033020 d.log\n5626152 d.ext\n7214296 k\n")),(0,r.kt)("p",null,"For this input, you will get following file system:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"- / (dir, size=48381165)\n - a (dir, size=94853)\n - e (dir, size=584)\n - i (file, size=584)\n - f (file, size=29116)\n - g (file, size=2557)\n - h.lst (file, size=62596)\n - b.txt (file, size=14848514)\n - c.dat (file, size=8504156)\n - d (dir, size=24933642)\n - j (file, size=4060174)\n - d.log (file, size=8033020)\n - d.ext (file, size=5626152)\n - k (file, size=7214296)\n")),(0,r.kt)("h2",{id:"format-of-the-output"},"Format of the output"),(0,r.kt)("p",null,"Your program should support 2 switches:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"-gt \u2039min_size\u203a")," that will print out suspiciously big files."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"-f \u2039total_size\u203a \u2039min_unused\u203a")," that will print out a file to be deleted.")),(0,r.kt)("h3",{id:"-gt-min_size"},(0,r.kt)("inlineCode",{parentName:"h3"},"-gt \u2039min_size\u203a")),(0,r.kt)("p",null,"With this switch you are provided one additional argument:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"min_size")," that is the lower bound (inclusive) for size of any file or\ndirectory that is supposed to be listed.")),(0,r.kt)("p",null,"When your program is being run with this switch, it is is supposed to print out\nall files ",(0,r.kt)("strong",{parentName:"p"},"and")," directories that are bigger than the provided ",(0,r.kt)("inlineCode",{parentName:"p"},"min_size"),"."),(0,r.kt)("h3",{id:"-f-total_size-min_unused"},(0,r.kt)("inlineCode",{parentName:"h3"},"-f \u2039total_size\u203a \u2039min_unused\u203a")),(0,r.kt)("p",null,"With this switch you are provided two additional arguments:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"total_size")," that is a total size of the filesystem",(0,r.kt)("sup",{parentName:"li",id:"fnref-2"},(0,r.kt)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2")),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"min_unused")," that is a minimum of free space required for an upgrade.")),(0,r.kt)("p",null,"Your program should find ",(0,r.kt)("strong",{parentName:"p"},"exactly one")," file or a directory that is of the\nsmallest size, but big enough to free enough space for the upgrade to proceed."),(0,r.kt)("p",null,"In other words, if that file or directory is deleted, following should hold:"),(0,r.kt)("div",{className:"math math-display"},(0,r.kt)("span",{parentName:"div",className:"katex-display"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mrow",{parentName:"mrow"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"o"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"_"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"s"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"z"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e")),(0,r.kt)("mo",{parentName:"mrow"},"\u2212"),(0,r.kt)("mrow",{parentName:"mrow"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"u"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"s"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d")),(0,r.kt)("mo",{parentName:"mrow"},"\u2265"),(0,r.kt)("mrow",{parentName:"mrow"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"_"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"u"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"u"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"s"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,r.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d"))),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathtt{total\\_size} - \\mathtt{used} \\geq \\mathtt{min\\_unused}")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7063em",verticalAlign:"-0.0951em"}}),(0,r.kt)("span",{parentName:"span",className:"mord"},(0,r.kt)("span",{parentName:"span",className:"mord mathtt"},"total_size")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,r.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7719em",verticalAlign:"-0.136em"}}),(0,r.kt)("span",{parentName:"span",className:"mord"},(0,r.kt)("span",{parentName:"span",className:"mord mathtt"},"used")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,r.kt)("span",{parentName:"span",className:"mrel"},"\u2265"),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7063em",verticalAlign:"-0.0951em"}}),(0,r.kt)("span",{parentName:"span",className:"mord"},(0,r.kt)("span",{parentName:"span",className:"mord mathtt"},"min_unused"))))))),(0,r.kt)("h2",{id:"example-usage"},"Example usage"),(0,r.kt)("p",null,"You can have a look at the example usage of your program. We can run your\nprogram from the shell like"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$ ./garbage_collect shell_history.txt -gt 10000000\n24933642 /d\n14848514 /b.txt\n48381165 /\n\n$ ./garbage_collect shell_history.txt -f 70000000 30000000\n24933642 /d\n")),(0,r.kt)("h2",{id:"requirements-and-notes"},"Requirements and notes"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Define ",(0,r.kt)("strong",{parentName:"li"},"structures")," (and ",(0,r.kt)("strong",{parentName:"li"},"enumerations"),", if applicable) for the parsed\ninformation from the files."),(0,r.kt)("li",{parentName:"ul"},"For keeping the \u201crecords\u201d, use some ",(0,r.kt)("strong",{parentName:"li"},"dynamic")," data structure.",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"Don't forget to consider pros and cons of using ",(0,r.kt)("em",{parentName:"li"},"specific")," data structures\nbefore going through implementing."))),(0,r.kt)("li",{parentName:"ul"},"You ",(0,r.kt)("strong",{parentName:"li"},"are not required")," to produce 1:1 output to the provided examples, they\nare just a hint to not waste your time tinkering with a user experience."),(0,r.kt)("li",{parentName:"ul"},"If any of the operations on the input files should fail,\n",(0,r.kt)("strong",{parentName:"li"},"you are expected to")," handle the situation ",(0,r.kt)("em",{parentName:"li"},"accordingly"),"."),(0,r.kt)("li",{parentName:"ul"},"Failures of any other common functions (e.g. functions used for memory\nmanagement) should be handled in ",(0,r.kt)("strong",{parentName:"li"},"the same way")," as they were in the\nhomeworks and seminars."),(0,r.kt)("li",{parentName:"ul"},"Your program ",(0,r.kt)("strong",{parentName:"li"},"must free")," all the resources before exiting.")),(0,r.kt)("div",{className:"footnotes"},(0,r.kt)("hr",{parentName:"div"}),(0,r.kt)("ol",{parentName:"div"},(0,r.kt)("li",{parentName:"ol",id:"fn-1"},"Also applies to Fedora, but\u2026 we use arch btw \ud83d\ude09",(0,r.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,r.kt)("li",{parentName:"ol",id:"fn-2"},"duh!",(0,r.kt)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/fcc91f97.acb581ec.js b/assets/js/fcc91f97.9c27af9a.js similarity index 99% rename from assets/js/fcc91f97.acb581ec.js rename to assets/js/fcc91f97.9c27af9a.js index cae1f66..1b7ea26 100644 --- a/assets/js/fcc91f97.acb581ec.js +++ b/assets/js/fcc91f97.9c27af9a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[6234],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>d});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var m=n.createContext({}),l=function(e){var t=n.useContext(m),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},p=function(e){var t=l(e.components);return n.createElement(m.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,m=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),c=l(a),u=r,d=c["".concat(m,".").concat(u)]||c[u]||h[u]||i;return a?n.createElement(d,s(s({ref:t},p),{},{components:a})):n.createElement(d,s({ref:t},p))}));function d(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,s=new Array(i);s[0]=u;var o={};for(var m in t)hasOwnProperty.call(t,m)&&(o[m]=t[m]);o.originalType=e,o[c]="string"==typeof e?e:r,s[1]=o;for(var l=2;l{a.r(t),a.d(t,{assets:()=>m,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>o,toc:()=>l});var n=a(7462),r=(a(7294),a(3905));const i={id:"iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",tags:["csharp","graphs","iterators","iterative"],last_update:{date:new Date("2021-05-18T00:00:00.000Z")}},s=void 0,o={unversionedId:"graphs/iterative-and-iterators",id:"graphs/iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",source:"@site/ib002/10-graphs/2021-05-18-iterative-and-iterators.md",sourceDirName:"10-graphs",slug:"/graphs/iterative-and-iterators",permalink:"/ib002/graphs/iterative-and-iterators",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/10-graphs/2021-05-18-iterative-and-iterators.md",tags:[{label:"csharp",permalink:"/ib002/tags/csharp"},{label:"graphs",permalink:"/ib002/tags/graphs"},{label:"iterators",permalink:"/ib002/tags/iterators"},{label:"iterative",permalink:"/ib002/tags/iterative"}],version:"current",lastUpdatedAt:1621296e3,formattedLastUpdatedAt:"May 18, 2021",frontMatter:{id:"iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",tags:["csharp","graphs","iterators","iterative"],last_update:{date:"2021-05-18T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Graphs",permalink:"/ib002/category/graphs"},next:{title:"Distance boundaries from BFS tree on undirected graphs",permalink:"/ib002/graphs/bfs-tree"}},m={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Different implementations",id:"different-implementations",level:2},{value:"Recursive DFS implementation from exercises without colors",id:"recursive-dfs-implementation-from-exercises-without-colors",level:3},{value:"Iterative DFS from the exercises",id:"iterative-dfs-from-the-exercises",level:3},{value:"My iterative with path in stack",id:"my-iterative-with-path-in-stack",level:3},{value:"My iterative solution with iterators",id:"my-iterative-solution-with-iterators",level:3},{value:"Implementation",id:"implementation",level:2}],p={toc:l},c="wrapper";function h(e){let{components:t,...a}=e;return(0,r.kt)(c,(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"pathname:///files/ib002/graphs/iterative-and-iterators.tar.gz"},"Source code used later on."))),(0,r.kt)("p",null,"As we have talked on the seminar, iterative approach to implementing DFS is not very intuitive and is a very easy way how to create an incorrect implementation."),(0,r.kt)("p",null,"On the other hand, we have seen iterative implementation in the exercises and I have also prepared two from which one was similar to recursive implementation without colors from exercises and the other one used features of high-level languages."),(0,r.kt)("h2",{id:"different-implementations"},"Different implementations"),(0,r.kt)("h3",{id:"recursive-dfs-implementation-from-exercises-without-colors"},"Recursive DFS implementation from exercises without colors"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"function VisitedDFS(u: Vertex, visited: VertexSet) return VertexSet is\n v: Vertex;\nbegin\n visited.Union(To_Set(u));\n\n for v in u.successors loop\n if not Contains(visited, v) then\n visited := visitedDFS(v, Visited);\n end if;\n end loop;\n\n return visited;\nend VisitedDFS;\n")),(0,r.kt)("p",null,"This implementation is correct, does the DFS traversal as it should, however it has one \u201csmallish\u201d downside and that is the time complexity. The usage of set raises the time complexity, of course it is implementation dependant. However in case of either RB-tree or hash-table implementation, we get look-up in time ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")")))))," for hash-table in worst-case or ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"log"),(0,r.kt)("mo",{parentName:"mrow"},"\u2061"),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(\\log n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mop"},"lo",(0,r.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")")))))," for the other in the worst-case. Both are not ideal compared to checking color on vertex."),(0,r.kt)("h3",{id:"iterative-dfs-from-the-exercises"},"Iterative DFS from the exercises"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure IterDFS(u: Vertex) is\n stack: StateVector;\n i, time: Integer;\n v: Vertex;\nbegin\n stack.Append(VertexState(u, 0));\n u.color := Gray;\n time := 1;\n u.d := time;\n\n while not stack.Is_Empty loop\n u := stack.Last_Element.Vertex;\n i := stack.Last_Element.NextIndex;\n stack.Delete_Last;\n\n if i < u.successors.Length then\n -- search is not finished, is pushed back to stack\n stack.Append(VertexState(u, k + 1));\n\n v := u.successors.Element(i);\n if v.color = White then\n stack.Append(VertexState(v, 0));\n v.color := Gray;\n time := time + 1;\n v.d := time;\n end if;\n else\n -- u has no other successors, we can finish the search\n time := time + 1;\n u.f := time;\n u.color := Black;\n end if;\n end loop;\n\nend IterDFS;\n")),(0,r.kt)("p",null,"As we can see, there is some ordering in which we search through the successors. Time complexity is OK, stack holds at most all vertices (they must be on the current path)."),(0,r.kt)("h3",{id:"my-iterative-with-path-in-stack"},"My iterative with path in stack"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure DFS(start: Vertex) is\n path: VertexVector;\n time: Integer;\n hasSuccessor: Bool;\n successor: Vertex;\nbegin\n path.Append(start);\n time := 1;\n\n start.d := time;\n start.color := Gray;\n\n while not path.Is_Empty loop\n hasSuccessor := false;\n\n for successor in path.Last_Element.successors loop\n if successor.color = White then\n hasSuccessor := true;\n\n successor.d := time + 1;\n successor.color := Gray;\n time := time + 1;\n\n path.Append(successor);\n\n exit;\n end if;\n end loop;\n\n if not hasSuccessor then\n path.Last_Element.f := time + 1;\n path.Last_Element.color := Black;\n\n time := time + 1;\n path.Delete_Last;\n end if;\n\n end loop;\nend DFS;\n")),(0,r.kt)("p",null,"This approach is similar to the iterative solution from the exercises, but it does not keep the index of the next successor, therefore it always iterates through all of them, which raises the time complexity."),(0,r.kt)("h3",{id:"my-iterative-solution-with-iterators"},"My iterative solution with iterators"),(0,r.kt)("p",null,"On the other hand, we do not actually have to depend on the representation of the graph. In this case, we just ",(0,r.kt)("em",{parentName:"p"},"somehow")," obtain the iterator (which yields all of the succesors) and keep it in the stack."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure DFS(start: Vertex) is\n path: StateVector;\n time: Integer;\n current: State;\n nextVertex: Vertex;\nbegin\n path.Append(State(start));\n time := 1;\n\n start.d := time;\n start.color := Gray;\n\n while not path.Is_Empty loop\n current := path.Last_Element;\n\n if not Move_Next(current.successors) then\n path.Delete_Last;\n\n time := time + 1;\n current.vertex.f := time;\n\n current.vertex.color := Black;\n else if current.successors.Value.color = white then\n nextVertex := current.successors.Value;\n\n time := time + 1;\n nextVertex.d := time;\n\n nextVertex.color := Gray;\n\n path.Append(State(nextVertex));\n end if;\n end loop;\nend DFS;\n")),(0,r.kt)("p",null,"( The way we manipulate with the iterators is closest to the C# implementation. Apart from the ",(0,r.kt)("inlineCode",{parentName:"p"},"Iterator")," thing :) In case you tried to implement it in C++, you would more than likely need to change the check, since you would get first successor right at the beginning )"),(0,r.kt)("p",null,"So here we don't keep indices, but the iterators. We can also check existence of other successors easily: by the iterator moving after the last successor."),(0,r.kt)("p",null,"Closer explanation of the ",(0,r.kt)("em",{parentName:"p"},"iterator shenanigans")," follows. In the beginning, either ",(0,r.kt)("inlineCode",{parentName:"p"},"start")," or when pushing new vertex, we are pushing an iterator that points ",(0,r.kt)("em",{parentName:"p"},"just before")," the first successor. When populating ",(0,r.kt)("inlineCode",{parentName:"p"},"lastVertex")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"successors")," in the ",(0,r.kt)("inlineCode",{parentName:"p"},"while"),"-loop, we take the element from the top of the stack. ",(0,r.kt)("inlineCode",{parentName:"p"},"MoveNext")," returns ",(0,r.kt)("inlineCode",{parentName:"p"},"true")," if there is an element, i.e. successor in this case. If it returns ",(0,r.kt)("inlineCode",{parentName:"p"},"false")," we have nothing to do and we pop the vertex from the stack (also set finishing time and color). If we have successor we check if it has been already visited or not. If has not, we set discovery time and color accordingly, also we add it to stack."),(0,r.kt)("h2",{id:"implementation"},"Implementation"),(0,r.kt)("p",null,"In case you want to play around with the code. At the beginning there is a link to the C# implementation that can be used. It has a basic representation of graph and includes BFS/DFS implementation in classes."),(0,r.kt)("p",null,"In ",(0,r.kt)("inlineCode",{parentName:"p"},"Program.cs")," you can also find a method that returns graph we used on the seminar."))}h.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[6234],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>d});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var m=n.createContext({}),l=function(e){var t=n.useContext(m),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},p=function(e){var t=l(e.components);return n.createElement(m.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,m=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),c=l(a),u=r,d=c["".concat(m,".").concat(u)]||c[u]||h[u]||i;return a?n.createElement(d,s(s({ref:t},p),{},{components:a})):n.createElement(d,s({ref:t},p))}));function d(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,s=new Array(i);s[0]=u;var o={};for(var m in t)hasOwnProperty.call(t,m)&&(o[m]=t[m]);o.originalType=e,o[c]="string"==typeof e?e:r,s[1]=o;for(var l=2;l{a.r(t),a.d(t,{assets:()=>m,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>o,toc:()=>l});var n=a(7462),r=(a(7294),a(3905));const i={id:"iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",tags:["csharp","graphs","iterators","iterative"],last_update:{date:new Date("2021-05-18T00:00:00.000Z")}},s=void 0,o={unversionedId:"graphs/iterative-and-iterators",id:"graphs/iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",source:"@site/ib002/10-graphs/2021-05-18-iterative-and-iterators.md",sourceDirName:"10-graphs",slug:"/graphs/iterative-and-iterators",permalink:"/ib002/graphs/iterative-and-iterators",draft:!1,editUrl:"https://github.com/mfocko/blog/tree/main/ib002/10-graphs/2021-05-18-iterative-and-iterators.md",tags:[{label:"csharp",permalink:"/ib002/tags/csharp"},{label:"graphs",permalink:"/ib002/tags/graphs"},{label:"iterators",permalink:"/ib002/tags/iterators"},{label:"iterative",permalink:"/ib002/tags/iterative"}],version:"current",lastUpdatedAt:1621296e3,formattedLastUpdatedAt:"May 18, 2021",frontMatter:{id:"iterative-and-iterators",title:"Iterative algorithms via iterators",description:"Iterative DFS using iterators.\n",tags:["csharp","graphs","iterators","iterative"],last_update:{date:"2021-05-18T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Graphs",permalink:"/ib002/category/graphs"},next:{title:"Distance boundaries from BFS tree on undirected graphs",permalink:"/ib002/graphs/bfs-tree"}},m={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Different implementations",id:"different-implementations",level:2},{value:"Recursive DFS implementation from exercises without colors",id:"recursive-dfs-implementation-from-exercises-without-colors",level:3},{value:"Iterative DFS from the exercises",id:"iterative-dfs-from-the-exercises",level:3},{value:"My iterative with path in stack",id:"my-iterative-with-path-in-stack",level:3},{value:"My iterative solution with iterators",id:"my-iterative-solution-with-iterators",level:3},{value:"Implementation",id:"implementation",level:2}],p={toc:l},c="wrapper";function h(e){let{components:t,...a}=e;return(0,r.kt)(c,(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"pathname:///files/ib002/graphs/iterative-and-iterators.tar.gz"},"Source code used later on."))),(0,r.kt)("p",null,"As we have talked on the seminar, iterative approach to implementing DFS is not very intuitive and is a very easy way how to create an incorrect implementation."),(0,r.kt)("p",null,"On the other hand, we have seen iterative implementation in the exercises and I have also prepared two from which one was similar to recursive implementation without colors from exercises and the other one used features of high-level languages."),(0,r.kt)("h2",{id:"different-implementations"},"Different implementations"),(0,r.kt)("h3",{id:"recursive-dfs-implementation-from-exercises-without-colors"},"Recursive DFS implementation from exercises without colors"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"function VisitedDFS(u: Vertex, visited: VertexSet) return VertexSet is\n v: Vertex;\nbegin\n visited.Union(To_Set(u));\n\n for v in u.successors loop\n if not Contains(visited, v) then\n visited := visitedDFS(v, Visited);\n end if;\n end loop;\n\n return visited;\nend VisitedDFS;\n")),(0,r.kt)("p",null,"This implementation is correct, does the DFS traversal as it should, however it has one \u201csmallish\u201d downside and that is the time complexity. The usage of set raises the time complexity, of course it is implementation dependant. However in case of either RB-tree or hash-table implementation, we get look-up in time ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")")))))," for hash-table in worst-case or ",(0,r.kt)("span",{parentName:"p",className:"math math-inline"},(0,r.kt)("span",{parentName:"span",className:"katex"},(0,r.kt)("span",{parentName:"span",className:"katex-mathml"},(0,r.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,r.kt)("semantics",{parentName:"math"},(0,r.kt)("mrow",{parentName:"semantics"},(0,r.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,r.kt)("mi",{parentName:"mrow"},"log"),(0,r.kt)("mo",{parentName:"mrow"},"\u2061"),(0,r.kt)("mi",{parentName:"mrow"},"n"),(0,r.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,r.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(\\log n)")))),(0,r.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,r.kt)("span",{parentName:"span",className:"base"},(0,r.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,r.kt)("span",{parentName:"span",className:"mopen"},"("),(0,r.kt)("span",{parentName:"span",className:"mop"},"lo",(0,r.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,r.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,r.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,r.kt)("span",{parentName:"span",className:"mclose"},")")))))," for the other in the worst-case. Both are not ideal compared to checking color on vertex."),(0,r.kt)("h3",{id:"iterative-dfs-from-the-exercises"},"Iterative DFS from the exercises"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure IterDFS(u: Vertex) is\n stack: StateVector;\n i, time: Integer;\n v: Vertex;\nbegin\n stack.Append(VertexState(u, 0));\n u.color := Gray;\n time := 1;\n u.d := time;\n\n while not stack.Is_Empty loop\n u := stack.Last_Element.Vertex;\n i := stack.Last_Element.NextIndex;\n stack.Delete_Last;\n\n if i < u.successors.Length then\n -- search is not finished, is pushed back to stack\n stack.Append(VertexState(u, k + 1));\n\n v := u.successors.Element(i);\n if v.color = White then\n stack.Append(VertexState(v, 0));\n v.color := Gray;\n time := time + 1;\n v.d := time;\n end if;\n else\n -- u has no other successors, we can finish the search\n time := time + 1;\n u.f := time;\n u.color := Black;\n end if;\n end loop;\n\nend IterDFS;\n")),(0,r.kt)("p",null,"As we can see, there is some ordering in which we search through the successors. Time complexity is OK, stack holds at most all vertices (they must be on the current path)."),(0,r.kt)("h3",{id:"my-iterative-with-path-in-stack"},"My iterative with path in stack"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure DFS(start: Vertex) is\n path: VertexVector;\n time: Integer;\n hasSuccessor: Bool;\n successor: Vertex;\nbegin\n path.Append(start);\n time := 1;\n\n start.d := time;\n start.color := Gray;\n\n while not path.Is_Empty loop\n hasSuccessor := false;\n\n for successor in path.Last_Element.successors loop\n if successor.color = White then\n hasSuccessor := true;\n\n successor.d := time + 1;\n successor.color := Gray;\n time := time + 1;\n\n path.Append(successor);\n\n exit;\n end if;\n end loop;\n\n if not hasSuccessor then\n path.Last_Element.f := time + 1;\n path.Last_Element.color := Black;\n\n time := time + 1;\n path.Delete_Last;\n end if;\n\n end loop;\nend DFS;\n")),(0,r.kt)("p",null,"This approach is similar to the iterative solution from the exercises, but it does not keep the index of the next successor, therefore it always iterates through all of them, which raises the time complexity."),(0,r.kt)("h3",{id:"my-iterative-solution-with-iterators"},"My iterative solution with iterators"),(0,r.kt)("p",null,"On the other hand, we do not actually have to depend on the representation of the graph. In this case, we just ",(0,r.kt)("em",{parentName:"p"},"somehow")," obtain the iterator (which yields all of the succesors) and keep it in the stack."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ada",metastring:"showLineNumbers",showLineNumbers:!0},"procedure DFS(start: Vertex) is\n path: StateVector;\n time: Integer;\n current: State;\n nextVertex: Vertex;\nbegin\n path.Append(State(start));\n time := 1;\n\n start.d := time;\n start.color := Gray;\n\n while not path.Is_Empty loop\n current := path.Last_Element;\n\n if not Move_Next(current.successors) then\n path.Delete_Last;\n\n time := time + 1;\n current.vertex.f := time;\n\n current.vertex.color := Black;\n else if current.successors.Value.color = white then\n nextVertex := current.successors.Value;\n\n time := time + 1;\n nextVertex.d := time;\n\n nextVertex.color := Gray;\n\n path.Append(State(nextVertex));\n end if;\n end loop;\nend DFS;\n")),(0,r.kt)("p",null,"( The way we manipulate with the iterators is closest to the C# implementation. Apart from the ",(0,r.kt)("inlineCode",{parentName:"p"},"Iterator")," thing :) In case you tried to implement it in C++, you would more than likely need to change the check, since you would get first successor right at the beginning )"),(0,r.kt)("p",null,"So here we don't keep indices, but the iterators. We can also check existence of other successors easily: by the iterator moving after the last successor."),(0,r.kt)("p",null,"Closer explanation of the ",(0,r.kt)("em",{parentName:"p"},"iterator shenanigans")," follows. In the beginning, either ",(0,r.kt)("inlineCode",{parentName:"p"},"start")," or when pushing new vertex, we are pushing an iterator that points ",(0,r.kt)("em",{parentName:"p"},"just before")," the first successor. When populating ",(0,r.kt)("inlineCode",{parentName:"p"},"lastVertex")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"successors")," in the ",(0,r.kt)("inlineCode",{parentName:"p"},"while"),"-loop, we take the element from the top of the stack. ",(0,r.kt)("inlineCode",{parentName:"p"},"MoveNext")," returns ",(0,r.kt)("inlineCode",{parentName:"p"},"true")," if there is an element, i.e. successor in this case. If it returns ",(0,r.kt)("inlineCode",{parentName:"p"},"false")," we have nothing to do and we pop the vertex from the stack (also set finishing time and color). If we have successor we check if it has been already visited or not. If has not, we set discovery time and color accordingly, also we add it to stack."),(0,r.kt)("h2",{id:"implementation"},"Implementation"),(0,r.kt)("p",null,"In case you want to play around with the code. At the beginning there is a link to the C# implementation that can be used. It has a basic representation of graph and includes BFS/DFS implementation in classes."),(0,r.kt)("p",null,"In ",(0,r.kt)("inlineCode",{parentName:"p"},"Program.cs")," you can also find a method that returns graph we used on the seminar."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/main.5876beef.js b/assets/js/main.a28961b3.js similarity index 99% rename from assets/js/main.5876beef.js rename to assets/js/main.a28961b3.js index 52c45bb..d38c563 100644 --- a/assets/js/main.5876beef.js +++ b/assets/js/main.a28961b3.js @@ -1,2 +1,2 @@ -/*! For license information please see main.5876beef.js.LICENSE.txt */ -(self.webpackChunkfi=self.webpackChunkfi||[]).push([[179],{830:(e,t,n)=>{"use strict";n.d(t,{W:()=>a});var r=n(7294);function a(){return r.createElement("svg",{width:"20",height:"20",className:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},r.createElement("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}},723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7294),a=n(7462),o=n(8356),i=n.n(o),l=n(6887);const s={"01a85c17":[()=>Promise.all([n.e(532),n.e(4013)]).then(n.bind(n,4524)),"@theme/BlogTagsListPage",4524],"0220f5fc":[()=>n.e(1378).then(n.t.bind(n,5804,19)),"/home/runner/work/blog/blog/.docusaurus/docusaurus-plugin-content-blog/blog/plugin-route-context-module-100.json",5804],"0608d96f":[()=>n.e(7568).then(n.t.bind(n,7158,19)),"~blog/blog/blog-tags-vps-843-list.json",7158],"09bc59e7":[()=>n.e(4932).then(n.t.bind(n,3649,19)),"~docs/ib002/category-ib-002-autogeneratedbar-category-graphs-387.json",3649],"0bfe45d5":[()=>n.e(4269).then(n.t.bind(n,3847,19)),"~blog/blog/blog-tags-rust-0c9-list.json",3847],"0fcbc6ca":[()=>Promise.all([n.e(532),n.e(1851)]).then(n.bind(n,9900)),"@site/src/pages/talks.tsx",9900],"146d9b84":[()=>n.e(9300).then(n.t.bind(n,6671,19)),"~blog/blog/blog-tags-admin-b05-list.json",6671],"14eb3368":[()=>Promise.all([n.e(532),n.e(9817)]).then(n.bind(n,4228)),"@theme/DocCategoryGeneratedIndexPage",4228],17896441:[()=>Promise.all([n.e(532),n.e(8954),n.e(7918)]).then(n.bind(n,5154)),"@theme/DocItem",5154],"18f481e4":[()=>n.e(6057).then(n.t.bind(n,1738,19)),"~docs/ib002/tag-ib-002-tags-java-086.json",1738],"19d7c045":[()=>n.e(4637).then(n.t.bind(n,7772,19)),"~blog/blog/blog-tags-advent-of-code-49f.json",7772],"1a4e3797":[()=>Promise.all([n.e(532),n.e(7920)]).then(n.bind(n,9172)),"@theme/SearchPage",9172],"1be78505":[()=>Promise.all([n.e(532),n.e(9514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"1bebd4ed":[()=>n.e(404).then(n.t.bind(n,9623,19)),"~docs/pb071/version-current-metadata-prop-751.json",9623],"1e2009d3":[()=>n.e(3906).then(n.bind(n,2131)),"@site/ib002/08-rb-trees/2022-04-05-applications.md",2131],"1e298f0c":[()=>n.e(2732).then(n.t.bind(n,3467,19)),"~docs/ib002/tag-ib-002-tags-bfs-346.json",3467],"22a175ec":[()=>Promise.all([n.e(532),n.e(6890)]).then(n.bind(n,707)),"@site/src/pages/contributions.tsx",707],"2523321d":[()=>n.e(9193).then(n.bind(n,5998)),"@site/pb071/bonuses/08.md",5998],27470891:[()=>n.e(4972).then(n.t.bind(n,9249,19)),"/home/runner/work/blog/blog/.docusaurus/docusaurus-plugin-content-docs/pb071/plugin-route-context-module-100.json",9249],"280c26e1":[()=>n.e(5529).then(n.t.bind(n,3272,19)),"/home/runner/work/blog/blog/.docusaurus/docusaurus-plugin-content-docs/ib002/plugin-route-context-module-100.json",3272],29694455:[()=>n.e(3388).then(n.t.bind(n,9828,19)),"~blog/blog/blog-tags-iterators-977-list.json",9828],"2a09abcd":[()=>n.e(1246).then(n.bind(n,3903)),"@site/ib002/10-graphs/2022-04-30-bfs-tree.md",3903],"3011a4c0":[()=>n.e(7926).then(n.t.bind(n,1670,19)),"~blog/blog/blog-tags-copr-70b-list.json",1670],"337bc122":[()=>n.e(1731).then(n.bind(n,8378)),"@site/pb071/00-intro-pb071.md",8378],"3593220c":[()=>n.e(8167).then(n.t.bind(n,2947,19)),"~docs/ib002/tag-ib-002-tags-greedy-99b.json",2947],"3720c009":[()=>Promise.all([n.e(532),n.e(3751)]).then(n.bind(n,727)),"@theme/DocTagsListPage",727],"377f3aa1":[()=>n.e(1011).then(n.bind(n,3248)),"@site/blog/aoc-2022/02-week-2.md",3248],"37cf4872":[()=>n.e(7979).then(n.t.bind(n,821,19)),"~docs/ib002/tag-ib-002-tags-postconditions-162.json",821],"3aef4518":[()=>n.e(1505).then(n.t.bind(n,1921,19)),"~docs/ib002/tag-ib-002-tags-iterative-678.json",1921],"3da4b779":[()=>n.e(2177).then(n.bind(n,8180)),"@site/blog/aoc-2022/04-week-4.md",8180],"3de247b5":[()=>Promise.all([n.e(532),n.e(3184)]).then(n.bind(n,5306)),"@site/ib002/08-rb-trees/2023-06-10-rules.md",5306],"4200b1a9":[()=>n.e(866).then(n.t.bind(n,4612,19)),"~blog/blog/blog-archive-80c.json",4612],"4621632b":[()=>n.e(3519).then(n.t.bind(n,9760,19)),"~blog/blog/blog-tags-cpp-7c7-list.json",9760],"4688cd57":[()=>n.e(932).then(n.t.bind(n,2647,19)),"~docs/pb071/category-pb-071-autogeneratedbar-category-bonuses-855.json",2647],"470a9204":[()=>n.e(3936).then(n.t.bind(n,4439,19)),"~docs/ib002/tag-ib-002-tags-applications-a68.json",4439],"4c4e9f30":[()=>n.e(7883).then(n.t.bind(n,7803,19)),"~docs/ib002/tag-ib-002-tags-exponential-5c3.json",7803],"4e286f4e":[()=>n.e(1501).then(n.bind(n,6038)),"@site/ib002/04-recursion/2022-11-29-karel-1.md",6038],"4edd2021":[()=>n.e(5975).then(n.t.bind(n,1705,19)),"~blog/blog/blog-tags-cpp-7c7.json",1705],"4ee12fa2":[()=>n.e(7963).then(n.bind(n,9258)),"@site/pb161/00-intro-pb161.md",9258],51624505:[()=>n.e(3731).then(n.bind(n,905)),"@site/blog/aoc-2022/00-intro.md",905],"52bff962":[()=>n.e(9710).then(n.t.bind(n,1193,19)),"~docs/ib002/tags-list-current-prop-15a.json",1193],"52f2a5bf":[()=>n.e(5430).then(n.t.bind(n,1387,19)),"~blog/blog/blog-tags-red-hat-df4.json",1387],"58dd4fbd":[()=>n.e(3340).then(n.t.bind(n,3047,19)),"~docs/ib002/tag-ib-002-tags-c-d4e.json",3047],"5af27364":[()=>n.e(3502).then(n.t.bind(n,3162,19)),"~docs/ib002/tag-ib-002-tags-balanced-trees-896.json",3162],"5e9f5e1a":[()=>Promise.resolve().then(n.bind(n,6809)),"@generated/docusaurus.config",6809],"62d847b3":[()=>n.e(8520).then(n.t.bind(n,1901,19)),"~blog/blog/blog-tags-advent-of-code-2022-3db-list.json",1901],"66d5ef6c":[()=>n.e(9228).then(n.t.bind(n,4087,19)),"~blog/blog/blog-tags-tags-4c2.json",4087],"6875c492":[()=>Promise.all([n.e(532),n.e(8954),n.e(6048),n.e(8610)]).then(n.bind(n,1714)),"@theme/BlogTagsPostsPage",1714],"713b7838":[()=>n.e(2167).then(n.bind(n,6652)),"@site/pb071/bonuses/04.md",6652],"73d5f13d":[()=>n.e(7555).then(n.t.bind(n,3974,19)),"~docs/ib002/tag-ib-002-tags-iterators-e30.json",3974],"74c2e0e9":[()=>n.e(3528).then(n.t.bind(n,2235,19)),"~docs/ib002/tag-ib-002-tags-backtracking-737.json",2235],"75316eff":[()=>n.e(4287).then(n.t.bind(n,5603,19)),"~docs/ib002/tag-ib-002-tags-python-65c.json",5603],"75cccf44":[()=>n.e(4256).then(n.bind(n,634)),"@site/blog/leetcode/sort-matrix-diagonally.md?truncated=true",634],"765ea78b":[()=>n.e(3039).then(n.t.bind(n,3010,19)),"~blog/blog/blog-tags-\ud83c\udfed-551.json",3010],"788cc978":[()=>n.e(9157).then(n.bind(n,3506)),"@site/ib002/03-time-complexity/2021-03-31-extend.md",3506],"7cf94373":[()=>n.e(3095).then(n.bind(n,1010)),"@site/pb071/bonuses/10.md",1010],"7d580cdb":[()=>n.e(8442).then(n.bind(n,7527)),"@site/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",7527],"82b3b723":[()=>n.e(5787).then(n.t.bind(n,6564,19)),"~docs/ib002/tag-ib-002-tags-dynamic-programming-5f1.json",6564],"834ed470":[()=>n.e(3223).then(n.bind(n,6454)),"@site/ib002/00-intro-ib002.md",6454],"83bf91d3":[()=>n.e(7823).then(n.bind(n,1187)),"@site/pb071/mr.md",1187],"8418981c":[()=>n.e(5383).then(n.t.bind(n,1930,19)),"~docs/ib002/tag-ib-002-tags-recursion-36f.json",1930],"86cd1460":[()=>n.e(1235).then(n.t.bind(n,8968,19)),"~blog/blog/blog-tags-leetcode-042.json",8968],"8b1802c5":[()=>n.e(8480).then(n.t.bind(n,832,19)),"~blog/blog/blog-tags-advent-of-code-49f-list.json",832],"8c0e532b":[()=>n.e(822).then(n.t.bind(n,3968,19)),"~blog/blog/blog-tags-vps-843.json",3968],"8e1fadd0":[()=>n.e(6554).then(n.t.bind(n,9278,19)),"~docs/ib002/category-ib-002-autogeneratedbar-category-algorithms-and-correctness-947.json",9278],"90425ffc":[()=>n.e(8769).then(n.bind(n,3167)),"@site/pb071/bonuses/03.md",3167],"9287eafd":[()=>n.e(5521).then(n.t.bind(n,716,19)),"~blog/blog/blog-tags-rust-0c9.json",716],"94036ea2":[()=>n.e(4477).then(n.t.bind(n,6996,19)),"~docs/pb161/version-current-metadata-prop-751.json",6996],"95b96bb9":[()=>n.e(3561).then(n.t.bind(n,4577,19)),"~blog/blog/blog-post-list-prop-blog.json",4577],"95be84b6":[()=>n.e(3835).then(n.t.bind(n,1820,19)),"~docs/ib002/tag-ib-002-tags-csharp-684.json",1820],"95f41f0b":[()=>n.e(9385).then(n.bind(n,6534)),"@site/blog/aoc-2022/01-week-1.md?truncated=true",6534],"9e4087bc":[()=>n.e(3608).then(n.bind(n,3169)),"@theme/BlogArchivePage",3169],"9eb50c57":[()=>n.e(7509).then(n.bind(n,6239)),"@site/ib002/02-algorithms-correctness/2021-03-18-postcondition-ambiguity.md",6239],a082abd3:[()=>n.e(8786).then(n.t.bind(n,3276,19)),"~blog/blog/blog-tags-admin-b05.json",3276],a2be6ffb:[()=>n.e(4800).then(n.bind(n,5185)),"@site/pb161/environment.md",5185],a6a48ea2:[()=>n.e(3618).then(n.bind(n,8763)),"@site/blog/aoc-2022/02-week-2.md?truncated=true",8763],a6aa9e1f:[()=>Promise.all([n.e(532),n.e(8954),n.e(6048),n.e(3089)]).then(n.bind(n,46)),"@theme/BlogListPage",46],a7098721:[()=>n.e(1050).then(n.t.bind(n,6615,19)),"~blog/blog/blog-c06.json",6615],a7d8226e:[()=>n.e(516).then(n.t.bind(n,4475,19)),"~docs/ib002/category-ib-002-autogeneratedbar-category-asymptotic-notation-and-time-complexity-5a5.json",4475],a80747a0:[()=>n.e(5824).then(n.t.bind(n,4464,19)),"~blog/blog/blog-tags-advent-of-code-2022-3db.json",4464],ab2721d4:[()=>n.e(7755).then(n.bind(n,861)),"@site/blog/aoc-2022/04-week-4.md?truncated=true",861],af8b72a7:[()=>n.e(5658).then(n.bind(n,3650)),"@site/blog/2023-08-02-copr.md?truncated=true",3650],b0067e0a:[()=>n.e(1272).then(n.t.bind(n,2611,19)),"~docs/ib002/version-current-metadata-prop-751.json",2611],b0291f37:[()=>n.e(6097).then(n.t.bind(n,7085,19)),"/home/runner/work/blog/blog/.docusaurus/docusaurus-theme-search-algolia/default/plugin-route-context-module-100.json",7085],b25fbc58:[()=>n.e(9197).then(n.t.bind(n,5617,19)),"~blog/blog/blog-tags-\ud83c\udfed-551-list.json",5617],b2c263ce:[()=>n.e(6192).then(n.t.bind(n,8379,19)),"~docs/ib002/category-ib-002-autogeneratedbar-category-recursion-061.json",8379],b45dccf0:[()=>n.e(9679).then(n.t.bind(n,8296,19)),"~blog/blog/blog-tags-copr-70b.json",8296],b5a32f14:[()=>n.e(2433).then(n.bind(n,9746)),"@site/blog/2023-08-02-copr.md",9746],b9b1ccdc:[()=>n.e(9044).then(n.bind(n,284)),"@site/pb071/pexam/c-cams.md",284],bb882650:[()=>n.e(8091).then(n.bind(n,6974)),"@site/blog/aoc-2022/03-week-3.md?truncated=true",6974],be4da062:[()=>n.e(6498).then(n.t.bind(n,4436,19)),"~docs/ib002/tag-ib-002-tags-time-complexity-7a0.json",4436],c4f5d8e4:[()=>Promise.all([n.e(532),n.e(4195)]).then(n.bind(n,3261)),"@site/src/pages/index.js",3261],c8cbffbd:[()=>n.e(9814).then(n.t.bind(n,4166,19)),"/home/runner/work/blog/blog/.docusaurus/docusaurus-plugin-content-docs/pb161/plugin-route-context-module-100.json",4166],ccc49370:[()=>Promise.all([n.e(532),n.e(8954),n.e(6048),n.e(6103)]).then(n.bind(n,5203)),"@theme/BlogPostPage",5203],cfa2b263:[()=>n.e(3086).then(n.bind(n,6031)),"@site/blog/leetcode/sort-matrix-diagonally.md",6031],d02d148d:[()=>n.e(7780).then(n.t.bind(n,9221,19)),"~docs/ib002/tag-ib-002-tags-testing-4cc.json",9221],d5ca4423:[()=>n.e(5126).then(n.t.bind(n,1032,19)),"~docs/ib002/tag-ib-002-tags-sorting-23e.json",1032],d661cf04:[()=>n.e(6112).then(n.t.bind(n,8194,19)),"~docs/pb071/category-pb-071-autogeneratedbar-category-practice-exams-a48.json",8194],d675395f:[()=>n.e(2741).then(n.t.bind(n,5745,19)),"/home/runner/work/blog/blog/.docusaurus/docusaurus-plugin-content-pages/default/plugin-route-context-module-100.json",5745],d74d369f:[()=>n.e(9479).then(n.t.bind(n,2231,19)),"~docs/ib002/category-ib-002-autogeneratedbar-category-red-black-trees-6b6.json",2231],d79dd549:[()=>n.e(5169).then(n.t.bind(n,9261,19)),"~blog/blog/blog-tags-red-hat-df4-list.json",9261],d7f7fb17:[()=>n.e(1171).then(n.bind(n,8049)),"@site/blog/aoc-2022/00-intro.md?truncated=true",8049],d9adc206:[()=>n.e(4252).then(n.t.bind(n,6297,19)),"~docs/ib002/tag-ib-002-tags-dynamic-array-119.json",6297],dadfcff0:[()=>n.e(7624).then(n.t.bind(n,3095,19)),"~docs/ib002/tag-ib-002-tags-graphs-c81.json",3095],df203c0f:[()=>n.e(9924).then(n.bind(n,491)),"@theme/DocTagDocListPage",491],dff2ebad:[()=>n.e(146).then(n.bind(n,577)),"@site/blog/aoc-2022/01-week-1.md",577],e25b3183:[()=>n.e(6).then(n.t.bind(n,5934,19)),"~docs/ib002/tag-ib-002-tags-top-down-dp-cc1.json",5934],e89da83e:[()=>n.e(8757).then(n.t.bind(n,7416,19)),"~blog/blog/blog-tags-leetcode-042-list.json",7416],eb7cc117:[()=>n.e(143).then(n.t.bind(n,3635,19)),"~docs/ib002/tag-ib-002-tags-red-black-trees-22f.json",3635],edfd2a45:[()=>n.e(7248).then(n.t.bind(n,1955,19)),"~docs/ib002/tag-ib-002-tags-karel-bbc.json",1955],f48be158:[()=>n.e(4064).then(n.bind(n,9859)),"@site/blog/aoc-2022/03-week-3.md",9859],f533ef4a:[()=>n.e(2160).then(n.bind(n,6489)),"@site/pb071/bonuses/05-06.md",6489],f60c832f:[()=>n.e(9611).then(n.bind(n,2490)),"@site/pb071/pexam/b-garbage_collect.md",2490],fcc91f97:[()=>n.e(6234).then(n.bind(n,4507)),"@site/ib002/10-graphs/2021-05-18-iterative-and-iterators.md",4507],fd0b1e16:[()=>n.e(5388).then(n.t.bind(n,955,19)),"~docs/ib002/tag-ib-002-tags-bottom-up-dp-3a4.json",955],ff472cd9:[()=>n.e(8643).then(n.t.bind(n,7122,19)),"~blog/blog/blog-tags-iterators-977.json",7122]};function c(e){let{error:t,retry:n,pastDelay:a}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):a?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var u=n(9670),d=n(226);function f(e,t){if("*"===e)return i()({loading:c,loader:()=>n.e(7515).then(n.bind(n,4972)),modules:["@theme/NotFound"],webpack:()=>[4972],render(e,t){const n=e.default;return r.createElement(d.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const o=l[`${e}-${t}`],f={},p=[],m=[],g=(0,u.Z)(o);return Object.entries(g).forEach((e=>{let[t,n]=e;const r=s[n];r&&(f[t]=r[0],p.push(r[1]),m.push(r[2]))})),i().Map({loading:c,loader:f,modules:p,webpack:()=>m,render(t,n){const i=JSON.parse(JSON.stringify(o));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let o=i;const l=n.split(".");l.slice(0,-1).forEach((e=>{o=o[e]})),o[l[l.length-1]]=a}));const l=i.__comp;delete i.__comp;const s=i.__context;return delete i.__context,r.createElement(d.z,{value:s},r.createElement(l,(0,a.Z)({},i,n)))}})}const p=[{path:"/blog/",component:f("/blog/","608"),exact:!0},{path:"/blog/2023/08/02/copr/",component:f("/blog/2023/08/02/copr/","69d"),exact:!0},{path:"/blog/aoc-2022/1st-week/",component:f("/blog/aoc-2022/1st-week/","df4"),exact:!0},{path:"/blog/aoc-2022/2nd-week/",component:f("/blog/aoc-2022/2nd-week/","783"),exact:!0},{path:"/blog/aoc-2022/3rd-week/",component:f("/blog/aoc-2022/3rd-week/","7c5"),exact:!0},{path:"/blog/aoc-2022/4th-week/",component:f("/blog/aoc-2022/4th-week/","1ac"),exact:!0},{path:"/blog/aoc-2022/intro/",component:f("/blog/aoc-2022/intro/","ada"),exact:!0},{path:"/blog/archive/",component:f("/blog/archive/","22d"),exact:!0},{path:"/blog/leetcode/sort-diagonally/",component:f("/blog/leetcode/sort-diagonally/","d97"),exact:!0},{path:"/blog/tags/",component:f("/blog/tags/","f23"),exact:!0},{path:"/blog/tags/\ud83c\udfed/",component:f("/blog/tags/\ud83c\udfed/","ffd"),exact:!0},{path:"/blog/tags/admin/",component:f("/blog/tags/admin/","d3a"),exact:!0},{path:"/blog/tags/advent-of-code-2022/",component:f("/blog/tags/advent-of-code-2022/","7bd"),exact:!0},{path:"/blog/tags/advent-of-code/",component:f("/blog/tags/advent-of-code/","313"),exact:!0},{path:"/blog/tags/copr/",component:f("/blog/tags/copr/","959"),exact:!0},{path:"/blog/tags/cpp/",component:f("/blog/tags/cpp/","770"),exact:!0},{path:"/blog/tags/iterators/",component:f("/blog/tags/iterators/","2eb"),exact:!0},{path:"/blog/tags/leetcode/",component:f("/blog/tags/leetcode/","e31"),exact:!0},{path:"/blog/tags/red-hat/",component:f("/blog/tags/red-hat/","a58"),exact:!0},{path:"/blog/tags/rust/",component:f("/blog/tags/rust/","281"),exact:!0},{path:"/blog/tags/vps/",component:f("/blog/tags/vps/","1b8"),exact:!0},{path:"/contributions/",component:f("/contributions/","541"),exact:!0},{path:"/ib002/tags/",component:f("/ib002/tags/","9d6"),exact:!0},{path:"/ib002/tags/applications/",component:f("/ib002/tags/applications/","54e"),exact:!0},{path:"/ib002/tags/backtracking/",component:f("/ib002/tags/backtracking/","c46"),exact:!0},{path:"/ib002/tags/balanced-trees/",component:f("/ib002/tags/balanced-trees/","1f4"),exact:!0},{path:"/ib002/tags/bfs/",component:f("/ib002/tags/bfs/","e19"),exact:!0},{path:"/ib002/tags/bottom-up-dp/",component:f("/ib002/tags/bottom-up-dp/","476"),exact:!0},{path:"/ib002/tags/c/",component:f("/ib002/tags/c/","3cd"),exact:!0},{path:"/ib002/tags/csharp/",component:f("/ib002/tags/csharp/","98e"),exact:!0},{path:"/ib002/tags/dynamic-array/",component:f("/ib002/tags/dynamic-array/","2c0"),exact:!0},{path:"/ib002/tags/dynamic-programming/",component:f("/ib002/tags/dynamic-programming/","4da"),exact:!0},{path:"/ib002/tags/exponential/",component:f("/ib002/tags/exponential/","f20"),exact:!0},{path:"/ib002/tags/graphs/",component:f("/ib002/tags/graphs/","87b"),exact:!0},{path:"/ib002/tags/greedy/",component:f("/ib002/tags/greedy/","21a"),exact:!0},{path:"/ib002/tags/iterative/",component:f("/ib002/tags/iterative/","531"),exact:!0},{path:"/ib002/tags/iterators/",component:f("/ib002/tags/iterators/","117"),exact:!0},{path:"/ib002/tags/java/",component:f("/ib002/tags/java/","65c"),exact:!0},{path:"/ib002/tags/karel/",component:f("/ib002/tags/karel/","142"),exact:!0},{path:"/ib002/tags/postconditions/",component:f("/ib002/tags/postconditions/","3a0"),exact:!0},{path:"/ib002/tags/python/",component:f("/ib002/tags/python/","df0"),exact:!0},{path:"/ib002/tags/recursion/",component:f("/ib002/tags/recursion/","bd5"),exact:!0},{path:"/ib002/tags/red-black-trees/",component:f("/ib002/tags/red-black-trees/","3cb"),exact:!0},{path:"/ib002/tags/sorting/",component:f("/ib002/tags/sorting/","e7c"),exact:!0},{path:"/ib002/tags/testing/",component:f("/ib002/tags/testing/","6f9"),exact:!0},{path:"/ib002/tags/time-complexity/",component:f("/ib002/tags/time-complexity/","83c"),exact:!0},{path:"/ib002/tags/top-down-dp/",component:f("/ib002/tags/top-down-dp/","ed8"),exact:!0},{path:"/search/",component:f("/search/","c7b"),exact:!0},{path:"/talks/",component:f("/talks/","819"),exact:!0},{path:"/ib002/",component:f("/ib002/","536"),routes:[{path:"/ib002/",component:f("/ib002/","e66"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/algorithms-correctness/postcondition-ambiguity/",component:f("/ib002/algorithms-correctness/postcondition-ambiguity/","5a3"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/category/algorithms-and-correctness/",component:f("/ib002/category/algorithms-and-correctness/","fb5"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/category/asymptotic-notation-and-time-complexity/",component:f("/ib002/category/asymptotic-notation-and-time-complexity/","8d1"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/category/graphs/",component:f("/ib002/category/graphs/","5c7"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/category/recursion/",component:f("/ib002/category/recursion/","04a"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/category/red-black-trees/",component:f("/ib002/category/red-black-trees/","b74"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/graphs/bfs-tree/",component:f("/ib002/graphs/bfs-tree/","204"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/graphs/iterative-and-iterators/",component:f("/ib002/graphs/iterative-and-iterators/","c8a"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/rb-trees/applications/",component:f("/ib002/rb-trees/applications/","616"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/rb-trees/rules/",component:f("/ib002/rb-trees/rules/","2b2"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/recursion/karel-1/",component:f("/ib002/recursion/karel-1/","0fd"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/recursion/pyramid-slide-down/",component:f("/ib002/recursion/pyramid-slide-down/","d87"),exact:!0,sidebar:"autogeneratedBar"},{path:"/ib002/time-complexity/extend/",component:f("/ib002/time-complexity/extend/","435"),exact:!0,sidebar:"autogeneratedBar"}]},{path:"/pb071/",component:f("/pb071/","372"),routes:[{path:"/pb071/",component:f("/pb071/","66f"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/bonuses/seminar-03/",component:f("/pb071/bonuses/seminar-03/","e23"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/bonuses/seminar-04/",component:f("/pb071/bonuses/seminar-04/","b7a"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/bonuses/seminar-05-06/",component:f("/pb071/bonuses/seminar-05-06/","50e"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/bonuses/seminar-08/",component:f("/pb071/bonuses/seminar-08/","e85"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/bonuses/seminar-10/",component:f("/pb071/bonuses/seminar-10/","b94"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/category/bonuses/",component:f("/pb071/category/bonuses/","abc"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/category/practice-exams/",component:f("/pb071/category/practice-exams/","41c"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/mr/",component:f("/pb071/mr/","7b2"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/pexam/cams/",component:f("/pb071/pexam/cams/","c14"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb071/pexam/garbage_collect/",component:f("/pb071/pexam/garbage_collect/","cba"),exact:!0,sidebar:"autogeneratedBar"}]},{path:"/pb161/",component:f("/pb161/","401"),routes:[{path:"/pb161/",component:f("/pb161/","726"),exact:!0,sidebar:"autogeneratedBar"},{path:"/pb161/environment/",component:f("/pb161/environment/","f56"),exact:!0,sidebar:"autogeneratedBar"}]},{path:"/",component:f("/","dfb"),exact:!0},{path:"*",component:f("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,t:()=>o});var r=n(7294);const a=r.createContext(!1);function o(e){let{children:t}=e;const[n,o]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{o(!0)}),[]),r.createElement(a.Provider,{value:n},t)}},9383:(e,t,n)=>{"use strict";var r=n(7294),a=n(3935),o=n(3727),i=n(405),l=n(412);const s=[n(2497),n(3310),n(8320),n(7439),n(7800)];var c=n(723),u=n(6550),d=n(8790);function f(e){let{children:t}=e;return r.createElement(r.Fragment,null,t)}var p=n(7462),m=n(5742),g=n(2263),h=n(4996),b=n(6668),v=n(833),y=n(4711),w=n(9727),k=n(3320),E=n(197);function S(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,g.Z)(),n=(0,y.l)();return r.createElement(m.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:a}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:a})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function _(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.Z)(),a=function(){const{siteConfig:{url:e}}=(0,g.Z)(),{pathname:t}=(0,u.TH)();return e+(0,h.Z)(t)}(),o=t?`${n}${t}`:a;return r.createElement(m.Z,null,r.createElement("meta",{property:"og:url",content:o}),r.createElement("link",{rel:"canonical",href:o}))}function x(){const{i18n:{currentLocale:e}}=(0,g.Z)(),{metadata:t,image:n}=(0,b.L)();return r.createElement(r.Fragment,null,r.createElement(m.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:w.h})),n&&r.createElement(v.d,{image:n}),r.createElement(_,null),r.createElement(S,null),r.createElement(E.Z,{tag:k.HX,locale:e}),r.createElement(m.Z,null,t.map(((e,t)=>r.createElement("meta",(0,p.Z)({key:t},e))))))}const T=new Map;function C(e){if(T.has(e.pathname))return{...e,pathname:T.get(e.pathname)};if((0,d.f)(c.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return T.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return T.set(e.pathname,t),{...e,pathname:t}}var A=n(8934),L=n(8940);function P(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const N=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,o=t.search===n.search;if(r&&a&&!o)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:a}),P("onRouteDidUpdate",{previousLocation:a,location:n}))}),[a,n]),t};function I(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(c.Z,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class O extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.Z.canUseDOM?P("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=P("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),I(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(N,{previousLocation:this.previousLocation,location:t},r.createElement(u.AW,{location:t,render:()=>e}))}}const R=O,M="__docusaurus-base-url-issue-banner-container",D="__docusaurus-base-url-issue-banner",B="__docusaurus-base-url-issue-banner-suggestion-container",F="__DOCUSAURUS_INSERT_BASEURL_BANNER";function $(e){return`\nwindow['${F}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${F}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${M}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n
\n

Your Docusaurus site did not load properly.

\n

A very common reason is a wrong site baseUrl configuration.

\n

Current configured baseUrl = ${e} ${"/"===e?" (default value)":""}

\n

We suggest trying baseUrl =

\n
\n`}(e)).replace(/{window[F]=!1}),[]),r.createElement(r.Fragment,null,!l.Z.canUseDOM&&r.createElement(m.Z,null,r.createElement("script",null,$(e))),r.createElement("div",{id:M}))}function z(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,g.Z)(),{pathname:n}=(0,u.TH)();return t&&n===e?r.createElement(j,null):null}function U(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:o}}=(0,g.Z)(),i=(0,h.Z)(e),{htmlLang:l,direction:s}=o[a];return r.createElement(m.Z,null,r.createElement("html",{lang:l,dir:s}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:i}))}var Z=n(4763);function H(){const e=(0,d.H)(c.Z),t=(0,u.TH)();return r.createElement(Z.Z,null,r.createElement(L.M,null,r.createElement(A.t,null,r.createElement(f,null,r.createElement(U,null),r.createElement(x,null),r.createElement(z,null),r.createElement(R,{location:C(t)},e)))))}var G=n(6887);const V=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var W=n(9670);const q=new Set,Y=new Set,K=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,X={prefetch(e){if(!(e=>!K()&&!Y.has(e)&&!q.has(e))(e))return!1;q.add(e);const t=(0,d.f)(c.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(G).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,W.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?V(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!K()&&!Y.has(e))(e)&&(Y.add(e),I(e))},Q=Object.freeze(X);if(l.Z.canUseDOM){window.docusaurus=Q;const e=a.hydrate;I(window.location.pathname).then((()=>{e(r.createElement(i.B6,null,r.createElement(o.VK,null,r.createElement(H,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>u,M:()=>d});var r=n(7294),a=n(6809);const o=JSON.parse('{"docusaurus-plugin-content-docs":{"pb071":{"path":"/pb071","versions":[{"name":"current","label":"Next","isLast":true,"path":"/pb071","mainDocId":"pb071-intro","docs":[{"id":"bonuses/seminar-03","path":"/pb071/bonuses/seminar-03","sidebar":"autogeneratedBar"},{"id":"bonuses/seminar-04","path":"/pb071/bonuses/seminar-04","sidebar":"autogeneratedBar"},{"id":"bonuses/seminar-05-06","path":"/pb071/bonuses/seminar-05-06","sidebar":"autogeneratedBar"},{"id":"bonuses/seminar-08","path":"/pb071/bonuses/seminar-08","sidebar":"autogeneratedBar"},{"id":"bonuses/seminar-10","path":"/pb071/bonuses/seminar-10","sidebar":"autogeneratedBar"},{"id":"mr","path":"/pb071/mr","sidebar":"autogeneratedBar"},{"id":"pb071-intro","path":"/pb071/","sidebar":"autogeneratedBar"},{"id":"pexam/b-garbage_collect","path":"/pb071/pexam/garbage_collect","sidebar":"autogeneratedBar"},{"id":"pexam/c-cams","path":"/pb071/pexam/cams","sidebar":"autogeneratedBar"},{"id":"/category/bonuses","path":"/pb071/category/bonuses","sidebar":"autogeneratedBar"},{"id":"/category/practice-exams","path":"/pb071/category/practice-exams","sidebar":"autogeneratedBar"}],"draftIds":[],"sidebars":{"autogeneratedBar":{"link":{"path":"/pb071/","label":"pb071-intro"}}}}],"breadcrumbs":true},"pb161":{"path":"/pb161","versions":[{"name":"current","label":"Next","isLast":true,"path":"/pb161","mainDocId":"pb161-intro","docs":[{"id":"environment","path":"/pb161/environment","sidebar":"autogeneratedBar"},{"id":"pb161-intro","path":"/pb161/","sidebar":"autogeneratedBar"}],"draftIds":[],"sidebars":{"autogeneratedBar":{"link":{"path":"/pb161/","label":"pb161-intro"}}}}],"breadcrumbs":true},"ib002":{"path":"/ib002","versions":[{"name":"current","label":"Next","isLast":true,"path":"/ib002","mainDocId":"ib002-intro","docs":[{"id":"algorithms-correctness/postcondition-ambiguity","path":"/ib002/algorithms-correctness/postcondition-ambiguity","sidebar":"autogeneratedBar"},{"id":"graphs/bfs-tree","path":"/ib002/graphs/bfs-tree","sidebar":"autogeneratedBar"},{"id":"graphs/iterative-and-iterators","path":"/ib002/graphs/iterative-and-iterators","sidebar":"autogeneratedBar"},{"id":"ib002-intro","path":"/ib002/","sidebar":"autogeneratedBar"},{"id":"rb-trees/applications","path":"/ib002/rb-trees/applications","sidebar":"autogeneratedBar"},{"id":"rb-trees/rules","path":"/ib002/rb-trees/rules","sidebar":"autogeneratedBar"},{"id":"recursion/karel-1","path":"/ib002/recursion/karel-1","sidebar":"autogeneratedBar"},{"id":"recursion/pyramid-slide-down","path":"/ib002/recursion/pyramid-slide-down","sidebar":"autogeneratedBar"},{"id":"time-complexity/extend","path":"/ib002/time-complexity/extend","sidebar":"autogeneratedBar"},{"id":"/category/algorithms-and-correctness","path":"/ib002/category/algorithms-and-correctness","sidebar":"autogeneratedBar"},{"id":"/category/asymptotic-notation-and-time-complexity","path":"/ib002/category/asymptotic-notation-and-time-complexity","sidebar":"autogeneratedBar"},{"id":"/category/recursion","path":"/ib002/category/recursion","sidebar":"autogeneratedBar"},{"id":"/category/red-black-trees","path":"/ib002/category/red-black-trees","sidebar":"autogeneratedBar"},{"id":"/category/graphs","path":"/ib002/category/graphs","sidebar":"autogeneratedBar"}],"draftIds":[],"sidebars":{"autogeneratedBar":{"link":{"path":"/ib002/","label":"ib002-intro"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var l=n(7529);const s=JSON.parse('{"docusaurusVersion":"2.4.1","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.4.1"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.4.1"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.4.1"},"docusaurus-theme-search-algolia":{"type":"package","name":"@docusaurus/theme-search-algolia","version":"2.4.1"},"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.4.1"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.4.1"},"docusaurus-plugin-sass":{"type":"package","name":"docusaurus-plugin-sass","version":"0.2.5"},"docusaurus-theme-mermaid":{"type":"package","name":"@docusaurus/theme-mermaid","version":"2.4.1"}}}'),c={siteConfig:a.default,siteMetadata:s,globalData:o,i18n:i,codeTranslations:l},u=r.createContext(c);function d(e){let{children:t}=e;return r.createElement(u.Provider,{value:c},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(412),o=n(5742),i=n(8780),l=n(7452);function s(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"}},r.createElement("h1",{style:{fontSize:"3rem"}},"This page crashed"),r.createElement("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"}},"Try again"),r.createElement(c,{error:t}))}function c(e){let{error:t}=e;const n=(0,i.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{style:{whiteSpace:"pre-wrap"}},n)}function u(e){let{error:t,tryAgain:n}=e;return r.createElement(f,{fallback:()=>r.createElement(s,{error:t,tryAgain:n})},r.createElement(o.Z,null,r.createElement("title",null,"Page Error")),r.createElement(l.Z,null,r.createElement(s,{error:t,tryAgain:n})))}const d=e=>r.createElement(u,e);class f extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??d)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(405);function o(e){return r.createElement(a.ql,e)}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7462),a=n(7294),o=n(3727),i=n(8780),l=n(2263),s=n(3919),c=n(412);const u=a.createContext({collectLink:()=>{}});var d=n(4996);function f(e,t){let{isNavLink:n,to:f,href:p,activeClassName:m,isActive:g,"data-noBrokenLinkCheck":h,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:{trailingSlash:y,baseUrl:w}}=(0,l.Z)(),{withBaseUrl:k}=(0,d.C)(),E=(0,a.useContext)(u),S=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>S.current));const _=f||p;const x=(0,s.Z)(_),T=_?.replace("pathname://","");let C=void 0!==T?(A=T,b&&(e=>e.startsWith("/"))(A)?k(A):A):void 0;var A;C&&x&&(C=(0,i.applyTrailingSlash)(C,{trailingSlash:y,baseUrl:w}));const L=(0,a.useRef)(!1),P=n?o.OL:o.rU,N=c.Z.canUseIntersectionObserver,I=(0,a.useRef)(),O=()=>{L.current||null==C||(window.docusaurus.preload(C),L.current=!0)};(0,a.useEffect)((()=>(!N&&x&&null!=C&&window.docusaurus.prefetch(C),()=>{N&&I.current&&I.current.disconnect()})),[I,C,N,x]);const R=C?.startsWith("#")??!1,M=!C||!x||R;return M||h||E.collectLink(C),M?a.createElement("a",(0,r.Z)({ref:S,href:C},_&&!x&&{target:"_blank",rel:"noopener noreferrer"},v)):a.createElement(P,(0,r.Z)({},v,{onMouseEnter:O,onTouchStart:O,innerRef:e=>{S.current=e,N&&e&&x&&(I.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(I.current.unobserve(e),I.current.disconnect(),null!=C&&window.docusaurus.prefetch(C))}))})),I.current.observe(e))},to:C},n&&{isActive:g,activeClassName:m}))}const p=a.forwardRef(f)},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s,I:()=>l});var r=n(7294);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var o=n(7529);function i(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return o[t??n]??n??t}function l(e,t){let{message:n,id:r}=e;return a(i({message:n,id:r}),t)}function s(e){let{children:t,id:n,values:o}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal children",t),new Error("The Docusaurus component only accept simple string values");const l=i({message:t,id:n});return r.createElement(r.Fragment,null,a(l,o))}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>i,Z:()=>l});var r=n(7294),a=n(2263),o=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8940);function o(){return(0,r.useContext)(a._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8934);function o(){return(0,r.useContext)(a._)}},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[o,i]=n;const l=a?`${a}.${o}`:o;r(i)?e(i,l):t[l]=i}))}(e),t}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,z:()=>o});var r=n(7294);const a=r.createContext(null);function o(e){let{children:t,value:n}=e;const o=r.useContext(a),i=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:o,value:n})),[o,n]);return r.createElement(a.Provider,{value:i},t)}},143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>b,gA:()=>p,WS:()=>m,_r:()=>d,Jo:()=>v,zh:()=>f,yW:()=>h,gB:()=>g});var r=n(6550),a=n(2263),o=n(9935);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const l=e=>e.versions.find((e=>e.isLast));function s(e,t){const n=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}function c(e,t){const n=s(e,t),a=n?.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const u={},d=()=>i("docusaurus-plugin-content-docs")??u,f=e=>function(e,t,n){void 0===t&&(t=o.m),void 0===n&&(n={});const r=i(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=d(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),o=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!o&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return o}(t,n,e)}function m(e){void 0===e&&(e={});const t=p(e),{pathname:n}=(0,r.TH)();if(!t)return;return{activePlugin:t,activeVersion:s(t.pluginData,n)}}function g(e){return f(e).versions}function h(e){const t=f(e);return l(t)}function b(e){const t=f(e),{pathname:n}=(0,r.TH)();return c(t,n)}function v(e){const t=f(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=l(e);return{latestDocSuggestion:c(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const o={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},3310:(e,t,n)=>{"use strict";n.r(t);var r=n(7410),a=n(6809);!function(e){const{themeConfig:{prism:t}}=a.default,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{n(9462)(`./prism-${e}`)})),delete globalThis.Prism}(r.Z)},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294);const a={iconExternalLink:"iconExternalLink_nPIU"};function o(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:a.iconExternalLink},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},7452:(e,t,n)=>{"use strict";n.d(t,{Z:()=>Pt});var r=n(7294),a=n(6010),o=n(4763),i=n(833),l=n(7462),s=n(6550),c=n(5999),u=n(5936);const d="__docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){const e=(0,r.useRef)(null),{action:t}=(0,s.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&f(t)}),[]);return(0,u.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,onClick:n}}const m=(0,c.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function g(e){const t=e.children??m,{containerRef:n,onClick:a}=p();return r.createElement("div",{ref:n,role:"region","aria-label":m},r.createElement("a",(0,l.Z)({},e,{href:`#${d}`,onClick:a}),t))}var h=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(g,{className:v.skipToContent})}var w=n(6668),k=n(9689);function E(e){let{width:t=21,height:n=21,color:a="currentColor",strokeWidth:o=1.2,className:i,...s}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 15 15",width:t,height:n},s),r.createElement("g",{stroke:a,strokeWidth:o},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const S={closeButton:"closeButton_CVFx"};function _(e){return r.createElement("button",(0,l.Z)({type:"button","aria-label":(0,c.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,a.Z)("clean-btn close",S.closeButton,e.className)}),r.createElement(E,{width:14,height:14,strokeWidth:3.1}))}const x={content:"content_knG7"};function T(e){const{announcementBar:t}=(0,w.L)(),{content:n}=t;return r.createElement("div",(0,l.Z)({},e,{className:(0,a.Z)(x.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const C={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function A(){const{announcementBar:e}=(0,w.L)(),{isActive:t,close:n}=(0,k.nT)();if(!t)return null;const{backgroundColor:a,textColor:o,isCloseable:i}=e;return r.createElement("div",{className:C.announcementBar,style:{backgroundColor:a,color:o},role:"banner"},i&&r.createElement("div",{className:C.announcementBarPlaceholder}),r.createElement(T,{className:C.announcementBarContent}),i&&r.createElement(_,{onClick:n,className:C.announcementBarClose}))}var L=n(3163),P=n(2466);var N=n(902),I=n(3102);const O=r.createContext(null);function R(e){let{children:t}=e;const n=function(){const e=(0,L.e)(),t=(0,I.HY)(),[n,a]=(0,r.useState)(!1),o=null!==t.component,i=(0,N.D9)(o);return(0,r.useEffect)((()=>{o&&!i&&a(!0)}),[o,i]),(0,r.useEffect)((()=>{o?e.shown||a(!0):a(!1)}),[e.shown,o]),(0,r.useMemo)((()=>[n,a]),[n])}();return r.createElement(O.Provider,{value:n},t)}function M(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function D(){const e=(0,r.useContext)(O);if(!e)throw new N.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),o=(0,I.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:M(o)})),[a,o,t])}function B(e){let{header:t,primaryMenu:n,secondaryMenu:o}=e;const{shown:i}=D();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},o)))}var F=n(2949),$=n(2389);function j(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function z(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const U={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function Z(e){let{className:t,buttonClassName:n,value:o,onChange:i}=e;const l=(0,$.Z)(),s=(0,c.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===o?(0,c.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)(U.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",U.toggleButton,!l&&U.toggleButtonDisabled,n),type:"button",onClick:()=>i("dark"===o?"light":"dark"),disabled:!l,title:s,"aria-label":s,"aria-live":"polite"},r.createElement(j,{className:(0,a.Z)(U.toggleIcon,U.lightToggleIcon)}),r.createElement(z,{className:(0,a.Z)(U.toggleIcon,U.darkToggleIcon)})))}const H=r.memo(Z),G={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function V(e){let{className:t}=e;const n=(0,w.L)().navbar.style,a=(0,w.L)().colorMode.disableSwitch,{colorMode:o,setColorMode:i}=(0,F.I)();return a?null:r.createElement(H,{className:t,buttonClassName:"dark"===n?G.darkNavbarColorModeToggle:void 0,value:o,onChange:i})}var W=n(1327);function q(){return r.createElement(W.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function Y(){const e=(0,L.e)();return r.createElement("button",{type:"button","aria-label":(0,c.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(E,{color:"var(--ifm-color-emphasis-600)"}))}function K(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(q,null),r.createElement(V,{className:"margin-right--md"}),r.createElement(Y,null))}var X=n(9960),Q=n(4996),J=n(3919),ee=n(8022),te=n(9471);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:o,label:i,html:s,isDropdownLink:c,prependBaseUrlToHref:u,...d}=e;const f=(0,Q.Z)(a),p=(0,Q.Z)(t),m=(0,Q.Z)(o,{forcePrependBaseUrl:!0}),g=i&&o&&!(0,J.Z)(o),h=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,i,g&&r.createElement(te.Z,c&&{width:12,height:12}))};return o?r.createElement(X.Z,(0,l.Z)({href:u?m:o},d,h)):r.createElement(X.Z,(0,l.Z)({to:f,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?(0,ee.F)(n,t.pathname):t.pathname.startsWith(p)},d,h))}function re(e){let{className:t,isDropdownItem:n=!1,...o}=e;const i=r.createElement(ne,(0,l.Z)({className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},o));return n?r.createElement("li",null,i):i}function ae(e){let{className:t,isDropdownItem:n,...o}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(ne,(0,l.Z)({className:(0,a.Z)("menu__link",t)},o)))}function oe(e){let{mobile:t=!1,position:n,...a}=e;const o=t?ae:re;return r.createElement(o,(0,l.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ie=n(6043),le=n(8596),se=n(2263);function ce(e,t){return e.some((e=>function(e,t){return!!(0,le.Mg)(e.to,t)||!!(0,ee.F)(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ue(e){let{items:t,position:n,className:o,onClick:i,...s}=e;const c=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{c.current&&!c.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[c]),r.createElement("div",{ref:c,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},r.createElement(ne,(0,l.Z)({"aria-haspopup":"true","aria-expanded":u,role:"button",href:s.to?void 0:"#",className:(0,a.Z)("navbar__link",o)},s,{onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!u))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,t)=>r.createElement(Ze,(0,l.Z)({isDropdownItem:!0,activeClassName:"dropdown__link--active"},e,{key:t}))))))}function de(e){let{items:t,className:n,position:o,onClick:i,...c}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,se.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=ce(t,u),{collapsed:f,toggleCollapsed:p,setCollapsed:m}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[u,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":f})},r.createElement(ne,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},c,{onClick:e=>{e.preventDefault(),p()}}),c.children??c.label),r.createElement(ie.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:f},t.map(((e,t)=>r.createElement(Ze,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active"},e,{key:t}))))))}function fe(e){let{mobile:t=!1,...n}=e;const a=t?de:ue;return r.createElement(a,n)}var pe=n(4711);function me(e){let{width:t=20,height:n=20,...a}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},a),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const ge="iconLanguage_nlXk";function he(){return r.createElement("svg",{width:"15",height:"15",className:"DocSearch-Control-Key-Icon"},r.createElement("path",{d:"M4.505 4.496h2M5.505 5.496v5M8.216 4.496l.055 5.993M10 7.5c.333.333.5.667.5 1v2M12.326 4.5v5.996M8.384 4.496c1.674 0 2.116 0 2.116 1.5s-.442 1.5-2.116 1.5M3.205 9.303c-.09.448-.277 1.21-1.241 1.203C1 10.5.5 9.513.5 8V7c0-1.57.5-2.5 1.464-2.494.964.006 1.134.598 1.24 1.342M12.553 10.5h1.953",strokeWidth:"1.2",stroke:"currentColor",fill:"none",strokeLinecap:"square"}))}var be=n(830),ve=["translations"];function ye(){return ye=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var Se="Ctrl";var _e=r.forwardRef((function(e,t){var n=e.translations,a=void 0===n?{}:n,o=Ee(e,ve),i=a.buttonText,l=void 0===i?"Search":i,s=a.buttonAriaLabel,c=void 0===s?"Search":s,u=we((0,r.useState)(null),2),d=u[0],f=u[1];return(0,r.useEffect)((function(){"undefined"!=typeof navigator&&(/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?f("\u2318"):f(Se))}),[]),r.createElement("button",ye({type:"button",className:"DocSearch DocSearch-Button","aria-label":c},o,{ref:t}),r.createElement("span",{className:"DocSearch-Button-Container"},r.createElement(be.W,null),r.createElement("span",{className:"DocSearch-Button-Placeholder"},l)),r.createElement("span",{className:"DocSearch-Button-Keys"},null!==d&&r.createElement(r.Fragment,null,r.createElement("kbd",{className:"DocSearch-Button-Key"},d===Se?r.createElement(he,null):d),r.createElement("kbd",{className:"DocSearch-Button-Key"},"K"))))})),xe=n(5742),Te=n(6177),Ce=n(239),Ae=n(3320);var Le=n(3935);const Pe={button:{buttonText:(0,c.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"}),buttonAriaLabel:(0,c.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"})},modal:{searchBox:{resetButtonTitle:(0,c.I)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),resetButtonAriaLabel:(0,c.I)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),cancelButtonText:(0,c.I)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"}),cancelButtonAriaLabel:(0,c.I)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"})},startScreen:{recentSearchesTitle:(0,c.I)({id:"theme.SearchModal.startScreen.recentSearchesTitle",message:"Recent",description:"The title for recent searches"}),noRecentSearchesText:(0,c.I)({id:"theme.SearchModal.startScreen.noRecentSearchesText",message:"No recent searches",description:"The text when no recent searches"}),saveRecentSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.saveRecentSearchButtonTitle",message:"Save this search",description:"The label for save recent search button"}),removeRecentSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.removeRecentSearchButtonTitle",message:"Remove this search from history",description:"The label for remove recent search button"}),favoriteSearchesTitle:(0,c.I)({id:"theme.SearchModal.startScreen.favoriteSearchesTitle",message:"Favorite",description:"The title for favorite searches"}),removeFavoriteSearchButtonTitle:(0,c.I)({id:"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle",message:"Remove this search from favorites",description:"The label for remove favorite search button"})},errorScreen:{titleText:(0,c.I)({id:"theme.SearchModal.errorScreen.titleText",message:"Unable to fetch results",description:"The title for error screen of search modal"}),helpText:(0,c.I)({id:"theme.SearchModal.errorScreen.helpText",message:"You might want to check your network connection.",description:"The help text for error screen of search modal"})},footer:{selectText:(0,c.I)({id:"theme.SearchModal.footer.selectText",message:"to select",description:"The explanatory text of the action for the enter key"}),selectKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.selectKeyAriaLabel",message:"Enter key",description:"The ARIA label for the Enter key button that makes the selection"}),navigateText:(0,c.I)({id:"theme.SearchModal.footer.navigateText",message:"to navigate",description:"The explanatory text of the action for the Arrow up and Arrow down key"}),navigateUpKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.navigateUpKeyAriaLabel",message:"Arrow up",description:"The ARIA label for the Arrow up key button that makes the navigation"}),navigateDownKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.navigateDownKeyAriaLabel",message:"Arrow down",description:"The ARIA label for the Arrow down key button that makes the navigation"}),closeText:(0,c.I)({id:"theme.SearchModal.footer.closeText",message:"to close",description:"The explanatory text of the action for Escape key"}),closeKeyAriaLabel:(0,c.I)({id:"theme.SearchModal.footer.closeKeyAriaLabel",message:"Escape key",description:"The ARIA label for the Escape key button that close the modal"}),searchByText:(0,c.I)({id:"theme.SearchModal.footer.searchByText",message:"Search by",description:"The text explain that the search is making by Algolia"})},noResultsScreen:{noResultsText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.noResultsText",message:"No results for",description:"The text explains that there are no results for the following search"}),suggestedQueryText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.suggestedQueryText",message:"Try searching for",description:"The text for the suggested query when no results are found for the following search"}),reportMissingResultsText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsText",message:"Believe this query should return results?",description:"The text for the question where the user thinks there are missing results"}),reportMissingResultsLinkText:(0,c.I)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText",message:"Let us know.",description:"The text for the link to report missing results"})}},placeholder:(0,c.I)({id:"theme.SearchModal.placeholder",message:"Search docs",description:"The placeholder of the input of the DocSearch pop-up modal"})};let Ne=null;function Ie(e){let{hit:t,children:n}=e;return r.createElement(X.Z,{to:t.url},n)}function Oe(e){let{state:t,onClose:n}=e;const a=(0,Te.M)();return r.createElement(X.Z,{to:a(t.query),onClick:n},r.createElement(c.Z,{id:"theme.SearchBar.seeAll",values:{count:t.context.nbHits}},"See all {count} results"))}function Re(e){let{contextualSearch:t,externalUrlRegex:a,...o}=e;const{siteMetadata:i}=(0,se.Z)(),c=(0,Ce.l)(),u=function(){const{locale:e,tags:t}=(0,Ae._q)();return[`language:${e}`,t.map((e=>`docusaurus_tag:${e}`))]}(),d=o.searchParameters?.facetFilters??[],f=t?function(e,t){const n=e=>"string"==typeof e?[e]:e;return[...n(e),...n(t)]}(u,d):d,p={...o.searchParameters,facetFilters:f},m=(0,s.k6)(),g=(0,r.useRef)(null),h=(0,r.useRef)(null),[b,v]=(0,r.useState)(!1),[y,w]=(0,r.useState)(void 0),k=(0,r.useCallback)((()=>Ne?Promise.resolve():Promise.all([n.e(1426).then(n.bind(n,1426)),Promise.all([n.e(532),n.e(6945)]).then(n.bind(n,6945)),Promise.all([n.e(532),n.e(8894)]).then(n.bind(n,8894))]).then((e=>{let[{DocSearchModal:t}]=e;Ne=t}))),[]),E=(0,r.useCallback)((()=>{k().then((()=>{g.current=document.createElement("div"),document.body.insertBefore(g.current,document.body.firstChild),v(!0)}))}),[k,v]),S=(0,r.useCallback)((()=>{v(!1),g.current?.remove()}),[v]),_=(0,r.useCallback)((e=>{k().then((()=>{v(!0),w(e.key)}))}),[k,v,w]),x=(0,r.useRef)({navigate(e){let{itemUrl:t}=e;(0,ee.F)(a,t)?window.location.href=t:m.push(t)}}).current,T=(0,r.useRef)((e=>o.transformItems?o.transformItems(e):e.map((e=>({...e,url:c(e.url)}))))).current,C=(0,r.useMemo)((()=>e=>r.createElement(Oe,(0,l.Z)({},e,{onClose:S}))),[S]),A=(0,r.useCallback)((e=>(e.addAlgoliaAgent("docusaurus",i.docusaurusVersion),e)),[i.docusaurusVersion]);return function(e){var t=e.isOpen,n=e.onOpen,a=e.onClose,o=e.onInput,i=e.searchButtonRef;r.useEffect((function(){function e(e){var r;(27===e.keyCode&&t||"k"===(null===(r=e.key)||void 0===r?void 0:r.toLowerCase())&&(e.metaKey||e.ctrlKey)||!function(e){var t=e.target,n=t.tagName;return t.isContentEditable||"INPUT"===n||"SELECT"===n||"TEXTAREA"===n}(e)&&"/"===e.key&&!t)&&(e.preventDefault(),t?a():document.body.classList.contains("DocSearch--active")||document.body.classList.contains("DocSearch--active")||n()),i&&i.current===document.activeElement&&o&&/[a-zA-Z0-9]/.test(String.fromCharCode(e.keyCode))&&o(e)}return window.addEventListener("keydown",e),function(){window.removeEventListener("keydown",e)}}),[t,n,a,o,i])}({isOpen:b,onOpen:E,onClose:S,onInput:_,searchButtonRef:h}),r.createElement(r.Fragment,null,r.createElement(xe.Z,null,r.createElement("link",{rel:"preconnect",href:`https://${o.appId}-dsn.algolia.net`,crossOrigin:"anonymous"})),r.createElement(_e,{onTouchStart:k,onFocus:k,onMouseOver:k,onClick:E,ref:h,translations:Pe.button}),b&&Ne&&g.current&&(0,Le.createPortal)(r.createElement(Ne,(0,l.Z)({onClose:S,initialScrollY:window.scrollY,initialQuery:y,navigator:x,transformItems:T,hitComponent:Ie,transformSearchClient:A},o.searchPagePath&&{resultsFooterComponent:C},o,{searchParameters:p,placeholder:Pe.placeholder,translations:Pe.modal})),g.current))}function Me(){const{siteConfig:e}=(0,se.Z)();return r.createElement(Re,e.themeConfig.algolia)}const De={searchBox:"searchBox_ZlJk"};function Be(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,De.searchBox)},t)}var Fe=n(143),$e=n(3438);var je=n(373);const ze=e=>e.docs.find((t=>t.id===e.mainDocId));const Ue={default:oe,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...o}=e;const{i18n:{currentLocale:i,locales:u,localeConfigs:d}}=(0,se.Z)(),f=(0,pe.l)(),{search:p,hash:m}=(0,s.TH)(),g=[...n,...u.map((e=>{const n=`${`pathname://${f.createUrl({locale:e,fullyQualified:!1})}`}${p}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...a],h=t?(0,c.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return r.createElement(fe,(0,l.Z)({},o,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(me,{className:ge}),h),items:g}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(Be,{className:n},r.createElement(Me,null))},dropdown:fe,html:function(e){let{value:t,className:n,mobile:o=!1,isDropdownItem:i=!1}=e;const l=i?"li":"div";return r.createElement(l,{className:(0,a.Z)({navbar__item:!o&&!i,"menu__list-item":o},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,Fe.Iw)(a),s=(0,$e.vY)(t,a);return null===s?null:r.createElement(oe,(0,l.Z)({exact:!0},o,{isActive:()=>i?.path===s.path||!!i?.sidebar&&i.sidebar===s.sidebar,label:n??s.id,to:s.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,Fe.Iw)(a),s=(0,$e.oz)(t,a).link;if(!s)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(oe,(0,l.Z)({exact:!0},o,{isActive:()=>i?.sidebar===t,label:n??s.label,to:s.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:a,...o}=e;const i=(0,$e.lO)(a)[0],s=t??i.label,c=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return r.createElement(oe,(0,l.Z)({},o,{label:s,to:c}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:o,dropdownItemsAfter:i,...u}=e;const{search:d,hash:f}=(0,s.TH)(),p=(0,Fe.Iw)(n),m=(0,Fe.gB)(n),{savePreferredVersionName:g}=(0,je.J)(n),h=[...o,...m.map((e=>{const t=p.alternateDocVersions[e.name]??ze(e);return{label:e.label,to:`${t.path}${d}${f}`,isActive:()=>e===p.activeVersion,onClick:()=>g(e.name)}})),...i],b=(0,$e.lO)(n)[0],v=t&&h.length>1?(0,c.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&h.length>1?void 0:ze(b).path;return h.length<=1?r.createElement(oe,(0,l.Z)({},u,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(fe,(0,l.Z)({},u,{mobile:t,label:v,to:y,items:h,isActive:a?()=>!1:void 0}))}};function Ze(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=Ue[a];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(o,n)}function He(){const e=(0,L.e)(),t=(0,w.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(Ze,(0,l.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Ge(e){return r.createElement("button",(0,l.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(c.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function Ve(){const e=0===(0,w.L)().navbar.items.length,t=D();return r.createElement(r.Fragment,null,!e&&r.createElement(Ge,{onClick:()=>t.hide()}),t.content)}function We(){const e=(0,L.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(B,{header:r.createElement(K,null),primaryMenu:r.createElement(He,null),secondaryMenu:r.createElement(Ve,null)}):null}const qe={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Ye(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Ke(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:o}}=(0,w.L)(),i=(0,L.e)(),{navbarRef:l,isNavbarVisible:s}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),o=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(o.current=e.getBoundingClientRect().height)}),[]);return(0,P.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i=l?n(!1):i+c{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:l,"aria-label":(0,c.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[qe.navbarHideable,!s&&qe.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown})},t,r.createElement(Ye,{onClick:i.toggle}),r.createElement(We,null))}var Xe=n(8780);const Qe={errorBoundaryError:"errorBoundaryError_a6uf"};function Je(e){return r.createElement("button",(0,l.Z)({type:"button"},e),r.createElement(c.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error"},"Try again"))}function et(e){let{error:t}=e;const n=(0,Xe.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{className:Qe.errorBoundaryError},n)}class tt extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const nt="right";function rt(e){let{width:t=30,height:n=30,className:a,...o}=e;return r.createElement("svg",(0,l.Z)({className:a,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},o),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function at(){const{toggle:e,shown:t}=(0,L.e)();return r.createElement("button",{onClick:e,"aria-label":(0,c.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(rt,null))}const ot={colorModeToggle:"colorModeToggle_DEke"};function it(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(tt,{key:t,onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t})},r.createElement(Ze,e)))))}function lt(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function st(){const e=(0,L.e)(),t=(0,w.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??nt)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return r.createElement(lt,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(at,null),r.createElement(q,null),r.createElement(it,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(it,{items:a}),r.createElement(V,{className:ot.colorModeToggle}),!o&&r.createElement(Be,null,r.createElement(Me,null)))})}function ct(){return r.createElement(Ke,null,r.createElement(st,null))}function ut(e){let{item:t}=e;const{to:n,href:a,label:o,prependBaseUrlToHref:i,...s}=t,c=(0,Q.Z)(n),u=(0,Q.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(X.Z,(0,l.Z)({className:"footer__link-item"},a?{href:i?u:a}:{to:c},s),o,a&&!(0,J.Z)(a)&&r.createElement(te.Z,null))}function dt(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement(ut,{item:t}))}function ft(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(dt,{key:t,item:e})))))}function pt(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(ft,{key:t,column:e}))))}function mt(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function gt(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(ut,{item:t})}function ht(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(gt,{item:e}),t.length!==n+1&&r.createElement(mt,null))))))}function bt(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(pt,{columns:t}):r.createElement(ht,{links:t})}var vt=n(941);const yt={footerLogoLink:"footerLogoLink_BH7S"};function wt(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Q.C)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(vt.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function kt(e){let{logo:t}=e;return t.href?r.createElement(X.Z,{href:t.href,className:yt.footerLogoLink,target:t.target},r.createElement(wt,{logo:t})):r.createElement(wt,{logo:t})}function Et(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function St(e){let{style:t,links:n,logo:o,copyright:i}=e;return r.createElement("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(o||i)&&r.createElement("div",{className:"footer__bottom text--center"},o&&r.createElement("div",{className:"margin-bottom--sm"},o),i)))}function _t(){const{footer:e}=(0,w.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:o}=e;return r.createElement(St,{style:o,links:n&&n.length>0&&r.createElement(bt,{links:n}),logo:a&&r.createElement(kt,{logo:a}),copyright:t&&r.createElement(Et,{copyright:t})})}const xt=r.memo(_t),Tt=(0,N.Qc)([F.S,k.pl,P.OC,je.L5,i.VC,function(e){let{children:t}=e;return r.createElement(I.n2,null,r.createElement(L.M,null,r.createElement(R,null,t)))}]);function Ct(e){let{children:t}=e;return r.createElement(Tt,null,t)}function At(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(c.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("div",{className:"margin-vert--lg"},r.createElement(Je,{onClick:n,className:"button button--primary shadow--lw"})),r.createElement("hr",null),r.createElement("div",{className:"margin-vert--md"},r.createElement(et,{error:t})))))}const Lt={mainWrapper:"mainWrapper_z2l0"};function Pt(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:c}=e;return(0,b.t)(),r.createElement(Ct,null,r.createElement(i.d,{title:s,description:c}),r.createElement(y,null),r.createElement(A,null),r.createElement(ct,null),r.createElement("div",{id:d,className:(0,a.Z)(h.k.wrapper.main,Lt.mainWrapper,l)},r.createElement(o.Z,{fallback:e=>r.createElement(At,e)},t)),!n&&r.createElement(xt,null))}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(7462),a=n(7294),o=n(9960),i=n(4996),l=n(2263),s=n(6668),c=n(941);function u(e){let{logo:t,alt:n,imageClassName:r}=e;const o={light:(0,i.Z)(t.src),dark:(0,i.Z)(t.srcDark||t.src)},l=a.createElement(c.Z,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return r?a.createElement("div",{className:r},l):l}function d(e){const{siteConfig:{title:t}}=(0,l.Z)(),{navbar:{title:n,logo:c}}=(0,s.L)(),{imageClassName:d,titleClassName:f,...p}=e,m=(0,i.Z)(c?.href||"/"),g=n?"":t,h=c?.alt??g;return a.createElement(o.Z,(0,r.Z)({to:m},p,c?.target&&{target:c.target}),c&&a.createElement(u,{logo:c,alt:h,imageClassName:d}),null!=n&&a.createElement("b",{className:f},n))}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(5742);function o(e){let{locale:t,version:n,tag:o}=e;const i=t;return r.createElement(a.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),o&&r.createElement("meta",{name:"docusaurus_tag",content:o}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),o&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:o}))}},941:(e,t,n)=>{"use strict";n.d(t,{Z:()=>c});var r=n(7462),a=n(7294),o=n(6010),i=n(2389),l=n(2949);const s={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function c(e){const t=(0,i.Z)(),{colorMode:n}=(0,l.I)(),{sources:c,className:u,alt:d,...f}=e,p=t?"dark"===n?["dark"]:["light"]:["light","dark"];return a.createElement(a.Fragment,null,p.map((e=>a.createElement("img",(0,r.Z)({key:e,src:c[e],alt:d,className:(0,o.Z)(s.themedImage,s[`themedImage--${e}`],u)},f)))))}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>s,z:()=>h});var r=n(7462),a=n(7294),o=n(412),i=n(1442);const l="ease-in-out";function s(e){let{initialState:t}=e;const[n,r]=(0,a.useState)(t??!1),o=(0,a.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:o}}const c={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function d(e,t){const n=t?c:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function f(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const o=(0,a.useRef)(!1);(0,a.useEffect)((()=>{const e=t.current;function a(){const t=e.scrollHeight,n=r?.duration??function(e){if((0,i.n)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??l}`,height:`${t}px`}}function s(){const t=a();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return d(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(s(),requestAnimationFrame((()=>{e.style.height=c.height,e.style.overflow=c.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{s()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function p(e){if(!o.Z.canUseDOM)return e?c:u}function m(e){let{as:t="div",collapsed:n,children:r,animation:o,onCollapseTransitionEnd:i,className:l,disableSSRStyle:s}=e;const c=(0,a.useRef)(null);return f({collapsibleRef:c,collapsed:n,animation:o}),a.createElement(t,{ref:c,style:s?void 0:p(n),onTransitionEnd:e=>{"height"===e.propertyName&&(d(c.current,n),i?.(n))},className:l},r)}function g(e){let{collapsed:t,...n}=e;const[o,i]=(0,a.useState)(!t),[l,s]=(0,a.useState)(t);return(0,a.useLayoutEffect)((()=>{t||i(!0)}),[t]),(0,a.useLayoutEffect)((()=>{o&&s(t)}),[o,t]),o?a.createElement(m,(0,r.Z)({},n,{collapsed:l})):null}function h(e){let{lazy:t,...n}=e;const r=t?g:m;return a.createElement(r,n)}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>p});var r=n(7294),a=n(2389),o=n(12),i=n(902),l=n(6668);const s=(0,o.WA)("docusaurus.announcement.dismiss"),c=(0,o.WA)("docusaurus.announcement.id"),u=()=>"true"===s.get(),d=e=>s.set(String(e)),f=r.createContext(null);function p(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.L)(),t=(0,a.Z)(),[n,o]=(0,r.useState)((()=>!!t&&u()));(0,r.useEffect)((()=>{o(u())}),[]);const i=(0,r.useCallback)((()=>{d(!0),o(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;c.set(t),r&&d(!1),!r&&u()||o(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return r.createElement(f.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(f);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>h,S:()=>g});var r=n(7294),a=n(412),o=n(902),i=n(12),l=n(6668);const s=r.createContext(void 0),c="theme",u=(0,i.WA)(c),d={light:"light",dark:"dark"},f=e=>e===d.dark?d.dark:d.light,p=e=>a.Z.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),m=e=>{u.set(f(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.L)(),[a,o]=(0,r.useState)(p(e));(0,r.useEffect)((()=>{t&&u.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(o(t),a&&m(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),u.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==c)return;const t=u.get();null!==t&&i(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:i,get isDarkTheme(){return a===d.dark},setLightTheme(){i(d.light)},setDarkTheme(){i(d.dark)}})),[a,i])}();return r.createElement(s.Provider,{value:n},t)}function h(){const e=(0,r.useContext)(s);if(null==e)throw new o.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>v,L5:()=>h,Oh:()=>y});var r=n(7294),a=n(143),o=n(9935),i=n(6668),l=n(3438),s=n(902),c=n(12);const u=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,c.WA)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.WA)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.WA)(u(e),{persistence:t}).del()}},f=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const p=r.createContext(null);function m(){const e=(0,a._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[o,l]=(0,r.useState)((()=>f(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=d.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[o,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=m();return r.createElement(p.Provider,{value:n},t)}function h(e){let{children:t}=e;return l.cE?r.createElement(g,null,t):r.createElement(r.Fragment,null,t)}function b(){const e=(0,r.useContext)(p);if(!e)throw new s.i6("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=o.m);const t=(0,a.zh)(e),[n,i]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}function y(){const e=(0,a._r)(),[t]=b();function n(n){const r=e[n],{preferredVersionName:a}=t[n];return r.versions.find((e=>e.name===a))??null}const r=Object.keys(e);return Object.fromEntries(r.map((e=>[e,n(e)])))}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,b:()=>l});var r=n(7294),a=n(902);const o=Symbol("EmptyContext"),i=r.createContext(o);function l(e){let{children:t,name:n,items:a}=e;const o=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return r.createElement(i.Provider,{value:o},t)}function s(){const e=(0,r.useContext)(i);if(e===o)throw new a.i6("DocsSidebarProvider");return e}},4477:(e,t,n)=>{"use strict";n.d(t,{E:()=>l,q:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t,version:n}=e;return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(null===e)throw new a.i6("DocsVersionProvider");return e}},3163:(e,t,n)=>{"use strict";n.d(t,{M:()=>d,e:()=>f});var r=n(7294),a=n(3102),o=n(7524),i=n(1980),l=n(6668),s=n(902);const c=r.createContext(void 0);function u(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,l.L)().navbar;return 0===t.length&&!e.component}(),t=(0,o.i)(),n=!e&&"mobile"===t,[s,c]=(0,r.useState)(!1);(0,i.Rb)((()=>{if(s)return c(!1),!1}));const u=(0,r.useCallback)((()=>{c((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&c(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:s})),[e,n,u,s])}function d(e){let{children:t}=e;const n=u();return r.createElement(c.Provider,{value:n},t)}function f(){const e=r.useContext(c);if(void 0===e)throw new s.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>l,Zo:()=>s,n2:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function s(e){let{component:t,props:n}=e;const i=(0,r.useContext)(o);if(!i)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,l]=i,s=(0,a.Ql)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>o});var r=n(7294);const a="navigation-with-keyboard";function o(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},6177:(e,t,n)=>{"use strict";n.d(t,{K:()=>l,M:()=>s});var r=n(7294),a=n(2263),o=n(1980);const i="q";function l(){return(0,o.Nc)(i)}function s(){const{siteConfig:{baseUrl:e,themeConfig:t}}=(0,a.Z)(),{algolia:{searchPagePath:n}}=t;return(0,r.useCallback)((t=>`${e}${n}?${i}=${encodeURIComponent(t)}`),[e,n])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>c});var r=n(7294),a=n(412);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(){return a.Z.canUseDOM?window.innerWidth>i?o.desktop:o.mobile:o.ssr}const s=!1;function c(){const[e,t]=(0,r.useState)((()=>s?"ssr":l()));return(0,r.useEffect)((()=>{function e(){t(l())}const n=s?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},1442:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{n:()=>r})},3438:(e,t,n)=>{"use strict";n.d(t,{MN:()=>x,Wl:()=>m,_F:()=>v,cE:()=>f,hI:()=>_,jA:()=>g,lO:()=>k,oz:()=>E,s1:()=>w,vY:()=>S,xz:()=>p});var r=n(7294),a=n(6550),o=n(8790),i=n(143),l=n(373),s=n(4477),c=n(1116),u=n(7392),d=n(8596);const f=!!i._r;function p(e){const t=(0,s.E)();if(!e)return;const n=t.docs[e];if(!n)throw new Error(`no version doc found by id=${e}`);return n}function m(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=m(t);if(e)return e}}}function g(){const{pathname:e}=(0,a.TH)(),t=(0,c.V)();if(!t)throw new Error("Unexpected: cant find current sidebar in context");const n=y({sidebarItems:t.items,pathname:e,onlyCategories:!0}).slice(-1)[0];if(!n)throw new Error(`${e} is not associated with a category. useCurrentSidebarCategory() should only be used on category index pages.`);return n}const h=(e,t)=>void 0!==e&&(0,d.Mg)(e,t),b=(e,t)=>e.some((e=>v(e,t)));function v(e,t){return"link"===e.type?h(e.href,t):"category"===e.type&&(h(e.href,t)||b(e.items,t))}function y(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const o of t)if("category"===o.type&&((0,d.Mg)(o.href,n)||e(o.items))||"link"===o.type&&(0,d.Mg)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function w(){const e=(0,c.V)(),{pathname:t}=(0,a.TH)(),n=(0,i.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?y({sidebarItems:e.items,pathname:t}):null}function k(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,l.J)(e),a=(0,i.yW)(e);return(0,r.useMemo)((()=>(0,u.j)([t,n,a].filter(Boolean))),[t,n,a])}function E(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function S(e,t){const n=k(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${(0,u.j)(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function _(e){let{route:t,versionMetadata:n}=e;const r=(0,a.TH)(),i=t.routes,l=i.find((e=>(0,a.LX)(r.pathname,e)));if(!l)return null;const s=l.sidebar,c=s?n.docsSidebars[s]:void 0;return{docElement:(0,o.H)(i),sidebarName:s,sidebarItems:c}}function x(e){return e.filter((e=>"category"!==e.type||!!m(e)))}},2128:(e,t,n)=>{"use strict";n.d(t,{p:()=>a});var r=n(2263);function a(e){const{siteConfig:t}=(0,r.Z)(),{title:n,titleDelimiter:a}=t;return e?.trim().length?`${e.trim()} ${a} ${n}`:n}},1980:(e,t,n)=>{"use strict";n.d(t,{Nc:()=>c,Rb:()=>l,_X:()=>s});var r=n(7294),a=n(6550),o=n(1688),i=n(902);function l(e){!function(e){const t=(0,a.k6)(),n=(0,i.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}function s(e){return function(e){const t=(0,a.k6)();return(0,o.useSyncExternalStore)(t.listen,(()=>e(t)),(()=>e(t)))}((t=>null===e?null:new URLSearchParams(t.location.search).get(e)))}function c(e){const t=s(e)??"",n=function(){const e=(0,a.k6)();return(0,r.useCallback)(((t,n,r)=>{const a=new URLSearchParams(e.location.search);n?a.set(t,n):a.delete(t),(r?.push?e.push:e.replace)({search:a.toString()})}),[e])}();return[t,(0,r.useCallback)(((t,r)=>{n(e,t,r)}),[n,e])]}},7392:(e,t,n)=>{"use strict";function r(e,t){return void 0===t&&(t=(e,t)=>e===t),e.filter(((n,r)=>e.findIndex((e=>t(e,n)))!==r))}function a(e){return Array.from(new Set(e))}n.d(t,{j:()=>a,l:()=>r})},833:(e,t,n)=>{"use strict";n.d(t,{FG:()=>f,d:()=>u,VC:()=>p});var r=n(7294),a=n(6010),o=n(5742),i=n(226);function l(){const e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(4996),c=n(2128);function u(e){let{title:t,description:n,keywords:a,image:i,children:l}=e;const u=(0,c.p)(t),{withBaseUrl:d}=(0,s.C)(),f=i?d(i,{absolute:!0}):void 0;return r.createElement(o.Z,null,t&&r.createElement("title",null,u),t&&r.createElement("meta",{property:"og:title",content:u}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),f&&r.createElement("meta",{property:"og:image",content:f}),f&&r.createElement("meta",{name:"twitter:image",content:f}),l)}const d=r.createContext(void 0);function f(e){let{className:t,children:n}=e;const i=r.useContext(d),l=(0,a.Z)(i,t);return r.createElement(d.Provider,{value:l},r.createElement(o.Z,null,r.createElement("html",{className:l})),n)}function p(e){let{children:t}=e;const n=l(),o=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return r.createElement(f,{className:(0,a.Z)(o,i)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>i,Qc:()=>c,Ql:()=>s,i6:()=>l,zX:()=>o});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function o(e){const t=(0,r.useRef)(e);return a((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function i(e){const t=(0,r.useRef)();return a((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function s(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function c(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8022:(e,t,n)=>{"use strict";function r(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}n.d(t,{F:()=>r})},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>i,Ns:()=>l});var r=n(7294),a=n(723),o=n(2263);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,o.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>p,OC:()=>s,RF:()=>d,o5:()=>f});var r=n(7294),a=n(412),o=n(2389),i=n(902);const l=r.createContext(void 0);function s(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(l.Provider,{value:n},t)}function c(){const e=(0,r.useContext)(l);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const u=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=c(),a=(0,r.useRef)(u()),o=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();o(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[o,n,...t])}function f(){const e=c(),t=function(){const e=(0,r.useRef)({elem:null,top:0}),t=(0,r.useCallback)((t=>{e.current={elem:t,top:t.getBoundingClientRect().top}}),[]),n=(0,r.useCallback)((()=>{const{current:{elem:t,top:n}}=e;if(!t)return{restored:!1};const r=t.getBoundingClientRect().top-n;return r&&window.scrollBy({left:0,top:r}),e.current={elem:null,top:0},{restored:0!==r}}),[]);return(0,r.useMemo)((()=>({save:t,restore:n})),[n,t])}(),n=(0,r.useRef)(void 0),a=(0,r.useCallback)((r=>{t.save(r),e.disableScrollEvents(),n.current=()=>{const{restored:r}=t.restore();if(n.current=void 0,r){const t=()=>{e.enableScrollEvents(),window.removeEventListener("scroll",t)};window.addEventListener("scroll",t)}else e.enableScrollEvents()}}),[e,t]);return(0,r.useLayoutEffect)((()=>{queueMicrotask((()=>n.current?.()))})),{blockElementScrollPositionUntilNextRender:a}}function p(){const e=(0,r.useRef)(null),t=(0,o.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&at&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>i,_q:()=>s,os:()=>l});var r=n(143),a=n(2263),o=n(373);const i="default";function l(e,t){return`docs-${e}-${t}`}function s(){const{i18n:e}=(0,a.Z)(),t=(0,r._r)(),n=(0,r.WS)(),s=(0,o.Oh)();const c=[i,...Object.keys(t).map((function(e){const r=n?.activePlugin.pluginId===e?n.activeVersion:void 0,a=s[e],o=t[e].versions.find((e=>e.isLast));return l(e,(r??a??o).name)}))];return{locale:e.currentLocale,tags:c}}},12:(e,t,n)=>{"use strict";n.d(t,{Nk:()=>d,WA:()=>u});var r=n(7294),a=n(1688);const o="localStorage";function i(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(o)}function l(e){if(void 0===e&&(e=o),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,s||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),s=!0),null}var t}let s=!1;const c={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function u(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=l(t?.persistence);return null===n?c:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),i({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),i({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}function d(e,t){const n=(0,r.useRef)((()=>null===e?c:u(e,t))).current(),o=(0,r.useCallback)((e=>"undefined"==typeof window?()=>{}:n.listen(e)),[n]);return[(0,a.useSyncExternalStore)(o,(()=>"undefined"==typeof window?null:n.get()),(()=>null)),n]}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>o});var r=n(2263),a=n(6550);function o(){const{siteConfig:{baseUrl:e,url:t},i18n:{defaultLocale:n,currentLocale:o}}=(0,r.Z)(),{pathname:i}=(0,a.TH)(),l=o===n?e:e.replace(`/${o}/`,"/"),s=i.replace(e,"");return{createUrl:function(e){let{locale:r,fullyQualified:a}=e;return`${a?t:""}${function(e){return e===n?`${l}`:`${l}${e}/`}(r)}${s}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>i});var r=n(7294),a=n(6550),o=n(902);function i(e){const t=(0,a.TH)(),n=(0,o.D9)(t),i=(0,o.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},6278:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){const{siteConfig:{themeConfig:e}}=(0,r.Z)();return e}},239:(e,t,n)=>{"use strict";n.d(t,{l:()=>l});var r=n(7294),a=n(8022),o=n(4996),i=n(6278);function l(){const{withBaseUrl:e}=(0,o.C)(),{algolia:{externalUrlRegex:t,replaceSearchResultPathname:n}}=(0,i.L)();return(0,r.useCallback)((r=>{const o=new URL(r);if((0,a.F)(t,o.href))return r;const i=`${o.pathname+o.hash}`;return e(function(e,t){return t?e.replaceAll(new RegExp(t.from,"g"),t.to):e}(i,n))}),[e,t,n])}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),o="/"===a||a===r?a:(i=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(a,o)}},4143:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}});var o=n(4143);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return o.getErrorCausalChain}})},6010:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;ta});const a=function(){for(var e,t,n=0,a="";n{"use strict";n.d(t,{lX:()=>w,q_:()=>T,ob:()=>p,PP:()=>A,Ep:()=>f});var r=n(7462);function a(e){return"/"===e.charAt(0)}function o(e,t){for(var n=t,r=n+1,a=e.length;r=0;f--){var p=i[f];"."===p?o(i,f):".."===p?(o(i,f),d++):d&&(o(i,f),d--)}if(!c)for(;d--;d)i.unshift("..");!c||""===i[0]||i[0]&&a(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(8776);function s(e){return"/"===e.charAt(0)?e:"/"+e}function c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function p(e,t,n,a){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),o.state=t):(void 0===(o=(0,r.Z)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(o.key=n),a?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=i(o.pathname,a.pathname)):o.pathname=a.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;rt?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=p(e,t,g(),w.location);u.confirmTransitionTo(a,r,n,(function(e){e&&(w.entries[w.index]=a,d({action:r,location:a}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=w.index+e;return t>=0&&t{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=p(n);a&&a!==m&&e(t,a,r)}var i=u(n);d&&(i=i.concat(d(n)));for(var l=s(t),g=s(n),h=0;h{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,a,o,i,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},7439:(e,t,n)=>{"use strict";n.r(t)},2497:(e,t,n)=>{"use strict";n.r(t)},7800:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'
'};function a(e,t,n){return en?n:e}function o(e){return 100*(-1+e)}function i(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var o=n.render(!t),c=o.querySelector(r.barSelector),u=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(c,i(e,u,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,i=t.querySelector(r.barSelector),l=e?"-100":o(n.status||0),c=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&p(a),c!=document.body&&u(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+o)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function o(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,a[1],a[2])}}();function c(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=f(e),r=n+t;c(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=f(e);c(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},7418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(a){return!1}}()?Object.assign:function(e,a){for(var o,i,l=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),s=1;s{"use strict";n.d(t,{Z:()=>o});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=d.reach);S+=E.value.length,E=E.next){var _=E.value;if(t.length>e.length)return;if(!(_ instanceof a)){var x,T=1;if(v){if(!(x=o(k,S,e,b))||x.index>=e.length)break;var C=x.index,A=x.index+x[0].length,L=S;for(L+=E.value.length;C>=L;)L+=(E=E.next).value.length;if(S=L-=E.value.length,E.value instanceof a)continue;for(var P=E;P!==t.tail&&(Ld.reach&&(d.reach=R);var M=E.prev;if(I&&(M=s(t,M,I),S+=I.length),c(t,M,T),E=s(t,M,new a(f,h?r.tokenize(N,h):N,y,N)),O&&s(t,E,O),T>1){var D={cause:f+","+m,reach:R};i(e,t,n,E.prev,S,D),d&&D.reach>d.reach&&(d.reach=D.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function s(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function c(e,t,n){for(var r=t.next,a=0;a"+o.content+""},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^$/i;var r={"included-cdata":{pattern://i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",o)}}),Object.defineProperty(a.languages.markup.tag,"addAttribute",{value:function(e,t){a.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:a.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),a.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),a.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},a.languages.c.string],char:a.languages.c.char,comment:a.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:a.languages.c}}}}),a.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete a.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(a),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(a),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(a),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:a.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),a.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),a.languages.markup&&(a.languages.markup.tag.addInlined("script","javascript"),a.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),a.languages.js=a.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(a),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*/.source.replace(//g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),o=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\s*:\s)/.source.replace(/<>/g,(function(){return r})).replace(/<>/g,(function(){return"(?:"+a+"|"+o+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(o),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(a),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(//g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),o=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+o+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+o+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+o+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)|_(?:(?!_))+_)+__\b|\*\*(?:(?!\*)|\*(?:(?!\*))+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)|__(?:(?!_))+__)+_\b|\*(?:(?!\*)|\*\*(?:(?!\*))+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~))+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\]))+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\]))+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n",quot:'"'},s=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(a),a.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:a.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},a.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n0)){var l=f(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s=0&&p(c,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],o=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function s(t,n,r){var a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function c(t){var n={};n["interpolation-punctuation"]=a;var o=e.tokenize(t,n);if(3===o.length){var i=[1,1];i.push.apply(i,s(o[1],e.languages.javascript,"javascript")),o.splice.apply(o,i)}return new e.Token("interpolation",o,r.alias,t)}function u(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),i=0,u={},d=s(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=l(i++,r)););return u[n]=a,n})).join(""),n,r),f=Object.keys(u);return i=0,function e(t){for(var n=0;n=f.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=f[i],o="string"==typeof r?r:r.content,l=o.indexOf(a);if(-1!==l){++i;var s=o.substring(0,l),d=c(u[a]),p=o.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),p){var g=[p];e(g),m.push.apply(m,g)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var h=r.content;Array.isArray(h)?e(h):e([h])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function f(e){return"string"==typeof e?e:Array.isArray(e)?e.map(f).join(""):f(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=n.length;r]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(//g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:(?:\s*,\s*(?:\*\s*as\s+|\{[^{}]*\}))?|\*\s*as\s+|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r*\.{3}(?:[^{}]|)*\})/.source;function o(e,t){return e=e.replace(//g,(function(){return n})).replace(//g,(function(){return r})).replace(//g,(function(){return a})),RegExp(e,t)}a=o(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=o(/<\/?(?:[\w.:-]+(?:+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|))?|))**\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(//.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var i=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(i).join(""):""},l=function(t){for(var n=[],r=0;r0&&n[n.length-1].tagName===i(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:i(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:o=!0),(o||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var s=i(a);r0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(s=i(t[r-1])+s,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",s,null,s)}a.content&&"string"!=typeof a.content&&l(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(a),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(a),a.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},a.languages.go=a.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),a.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete a.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s=o.length);s++){var c=l[s];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=o[a],d=n.tokenStack[u],f="string"==typeof c?c:c.content,p=t(r,u),m=f.indexOf(p);if(m>-1){++a;var g=f.substring(0,m),h=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=f.substring(m+p.length),v=[];g&&v.push.apply(v,i([g])),v.push(h),b&&v.push.apply(v,i([b])),"string"==typeof c?l.splice.apply(l,[s,1].concat(v)):c.content=v}}else c.content&&i(c.content)}return l}(n.tokens)}}}})}(a),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(a),a.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},a.languages.webmanifest=a.languages.json,a.languages.less=a.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},a.languages.objectivec=a.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete a.languages.objectivec["class-name"],a.languages.objc=a.languages.objectivec,a.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},a.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),a.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete a.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(a),a.languages.scss=a.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),a.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),a.languages.scss.atrule.inside.rest=a.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(a),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(a),a.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const o=a},5795:()=>{Prism.languages.ada={comment:/--.*/,string:/"(?:""|[^"\r\f\n])*"/,number:[{pattern:/\b\d(?:_?\d)*#[\dA-F](?:_?[\dA-F])*(?:\.[\dA-F](?:_?[\dA-F])*)?#(?:E[+-]?\d(?:_?\d)*)?/i},{pattern:/\b\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:E[+-]?\d(?:_?\d)*)?\b/i}],attribute:{pattern:/\b'\w+/,alias:"attr-name"},keyword:/\b(?:abort|abs|abstract|accept|access|aliased|all|and|array|at|begin|body|case|constant|declare|delay|delta|digits|do|else|elsif|end|entry|exception|exit|for|function|generic|goto|if|in|interface|is|limited|loop|mod|new|not|null|of|or|others|out|overriding|package|pragma|private|procedure|protected|raise|range|record|rem|renames|requeue|return|reverse|select|separate|some|subtype|synchronized|tagged|task|terminate|then|type|until|use|when|while|with|xor)\b/i,boolean:/\b(?:false|true)\b/i,operator:/<[=>]?|>=?|=>?|:=|\/=?|\*\*?|[&+-]/,punctuation:/\.\.?|[,;():]/,char:/'.'/,variable:/\b[a-z](?:\w)*\b/i}},7874:()=>{!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i{!function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,(function(e,n){return"(?:"+t[+n]+")"}))}function n(e,n,r){return RegExp(t(e,n),r||"")}function r(e,t){for(var n=0;n>/g,(function(){return"(?:"+e+")"}));return e.replace(/<>/g,"[^\\s\\S]")}var a="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",o="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",l="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function s(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var c=s(o),u=RegExp(s(a+" "+o+" "+i+" "+l)),d=s(o+" "+i+" "+l),f=s(a+" "+o+" "+l),p=r(/<(?:[^<>;=+\-*/%&|^]|<>)*>/.source,2),m=r(/\((?:[^()]|<>)*\)/.source,2),g=/@?\b[A-Za-z_]\w*\b/.source,h=t(/<<0>>(?:\s*<<1>>)?/.source,[g,p]),b=t(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[d,h]),v=/\[\s*(?:,\s*)*\]/.source,y=t(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[b,v]),w=t(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[p,m,v]),k=t(/\(<<0>>+(?:,<<0>>+)+\)/.source,[w]),E=t(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[k,b,v]),S={keyword:u,punctuation:/[<>()?,.:[\]]/},_=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,x=/"(?:\\.|[^\\"\r\n])*"/.source,T=/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source;e.languages.csharp=e.languages.extend("clike",{string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[T]),lookbehind:!0,greedy:!0},{pattern:n(/(^|[^@$\\])<<0>>/.source,[x]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:n(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[b]),lookbehind:!0,inside:S},{pattern:n(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[g,E]),lookbehind:!0,inside:S},{pattern:n(/(\busing\s+)<<0>>(?=\s*=)/.source,[g]),lookbehind:!0},{pattern:n(/(\b<<0>>\s+)<<1>>/.source,[c,h]),lookbehind:!0,inside:S},{pattern:n(/(\bcatch\s*\(\s*)<<0>>/.source,[b]),lookbehind:!0,inside:S},{pattern:n(/(\bwhere\s+)<<0>>/.source,[g]),lookbehind:!0},{pattern:n(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[y]),lookbehind:!0,inside:S},{pattern:n(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[E,f,g]),inside:S}],keyword:u,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:n(/([(,]\s*)<<0>>(?=\s*:)/.source,[g]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:n(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[g]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:n(/(\b(?:default|sizeof|typeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[m]),lookbehind:!0,alias:"class-name",inside:S},"return-type":{pattern:n(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[E,b]),inside:S,alias:"class-name"},"constructor-invocation":{pattern:n(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[E]),lookbehind:!0,inside:S,alias:"class-name"},"generic-method":{pattern:n(/<<0>>\s*<<1>>(?=\s*\()/.source,[g,p]),inside:{function:n(/^<<0>>/.source,[g]),generic:{pattern:RegExp(p),alias:"class-name",inside:S}}},"type-list":{pattern:n(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[c,h,g,E,u.source,m,/\bnew\s*\(\s*\)/.source]),lookbehind:!0,inside:{"record-arguments":{pattern:n(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source,[h,m]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:u,"class-name":{pattern:RegExp(E),greedy:!0,inside:S},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var C=x+"|"+_,A=t(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[C]),L=r(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[A]),2),P=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,N=t(/<<0>>(?:\s*\(<<1>>*\))?/.source,[b,L]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:n(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[P,N]),lookbehind:!0,greedy:!0,inside:{target:{pattern:n(/^<<0>>(?=\s*:)/.source,[P]),alias:"keyword"},"attribute-arguments":{pattern:n(/\(<<0>>*\)/.source,[L]),inside:e.languages.csharp},"class-name":{pattern:RegExp(b),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var I=/:[^}\r\n]+/.source,O=r(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[A]),2),R=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[O,I]),M=r(t(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<>*\)/.source,[C]),2),D=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[M,I]);function B(t,r){return{interpolation:{pattern:n(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{"format-string":{pattern:n(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[r,I]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:n(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[R]),lookbehind:!0,greedy:!0,inside:B(R,O)},{pattern:n(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[D]),lookbehind:!0,greedy:!0,inside:B(D,M)}],char:{pattern:RegExp(_),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(Prism)},397:()=>{!function(e){var t="(?:"+[/[a-zA-Z_\x80-\uFFFF][\w\x80-\uFFFF]*/.source,/-?(?:\.\d+|\d+(?:\.\d*)?)/.source,/"[^"\\]*(?:\\[\s\S][^"\\]*)*"/.source,/<(?:[^<>]|(?!)*>/.source].join("|")+")",n={markup:{pattern:/(^<)[\s\S]+(?=>$)/,lookbehind:!0,alias:["language-markup","language-html","language-xml"],inside:e.languages.markup}};function r(e,n){return RegExp(e.replace(//g,(function(){return t})),n)}e.languages.dot={comment:{pattern:/\/\/.*|\/\*[\s\S]*?\*\/|^#.*/m,greedy:!0},"graph-name":{pattern:r(/(\b(?:digraph|graph|subgraph)[ \t\r\n]+)/.source,"i"),lookbehind:!0,greedy:!0,alias:"class-name",inside:n},"attr-value":{pattern:r(/(=[ \t\r\n]*)/.source),lookbehind:!0,greedy:!0,inside:n},"attr-name":{pattern:r(/([\[;, \t\r\n])(?=[ \t\r\n]*=)/.source),lookbehind:!0,greedy:!0,inside:n},keyword:/\b(?:digraph|edge|graph|node|strict|subgraph)\b/i,"compass-point":{pattern:/(:[ \t\r\n]*)(?:[ewc_]|[ns][ew]?)(?![\w\x80-\uFFFF])/,lookbehind:!0,alias:"builtin"},node:{pattern:r(/(^|[^-.\w\x80-\uFFFF\\])/.source),lookbehind:!0,greedy:!0,inside:n},operator:/[=:]|-[->]/,punctuation:/[\[\]{};,]/},e.languages.gv=e.languages.dot}(Prism)},1295:()=>{Prism.languages.haskell={comment:{pattern:/(^|[^-!#$%*+=?&@|~.:<>^\\\/])(?:--(?:(?=.)[^-!#$%*+=?&@|~.:<>^\\\/].*|$)|\{-[\s\S]*?-\})/m,lookbehind:!0},char:{pattern:/'(?:[^\\']|\\(?:[abfnrtv\\"'&]|\^[A-Z@[\]^_]|ACK|BEL|BS|CAN|CR|DC1|DC2|DC3|DC4|DEL|DLE|EM|ENQ|EOT|ESC|ETB|ETX|FF|FS|GS|HT|LF|NAK|NUL|RS|SI|SO|SOH|SP|STX|SUB|SYN|US|VT|\d+|o[0-7]+|x[0-9a-fA-F]+))'/,alias:"string"},string:{pattern:/"(?:[^\\"]|\\(?:\S|\s+\\))*"/,greedy:!0},keyword:/\b(?:case|class|data|deriving|do|else|if|in|infixl|infixr|instance|let|module|newtype|of|primitive|then|type|where)\b/,"import-statement":{pattern:/(^[\t ]*)import\s+(?:qualified\s+)?(?:[A-Z][\w']*)(?:\.[A-Z][\w']*)*(?:\s+as\s+(?:[A-Z][\w']*)(?:\.[A-Z][\w']*)*)?(?:\s+hiding\b)?/m,lookbehind:!0,inside:{keyword:/\b(?:as|hiding|import|qualified)\b/,punctuation:/\./}},builtin:/\b(?:abs|acos|acosh|all|and|any|appendFile|approxRational|asTypeOf|asin|asinh|atan|atan2|atanh|basicIORun|break|catch|ceiling|chr|compare|concat|concatMap|const|cos|cosh|curry|cycle|decodeFloat|denominator|digitToInt|div|divMod|drop|dropWhile|either|elem|encodeFloat|enumFrom|enumFromThen|enumFromThenTo|enumFromTo|error|even|exp|exponent|fail|filter|flip|floatDigits|floatRadix|floatRange|floor|fmap|foldl|foldl1|foldr|foldr1|fromDouble|fromEnum|fromInt|fromInteger|fromIntegral|fromRational|fst|gcd|getChar|getContents|getLine|group|head|id|inRange|index|init|intToDigit|interact|ioError|isAlpha|isAlphaNum|isAscii|isControl|isDenormalized|isDigit|isHexDigit|isIEEE|isInfinite|isLower|isNaN|isNegativeZero|isOctDigit|isPrint|isSpace|isUpper|iterate|last|lcm|length|lex|lexDigits|lexLitChar|lines|log|logBase|lookup|map|mapM|mapM_|max|maxBound|maximum|maybe|min|minBound|minimum|mod|negate|not|notElem|null|numerator|odd|or|ord|otherwise|pack|pi|pred|primExitWith|print|product|properFraction|putChar|putStr|putStrLn|quot|quotRem|range|rangeSize|read|readDec|readFile|readFloat|readHex|readIO|readInt|readList|readLitChar|readLn|readOct|readParen|readSigned|reads|readsPrec|realToFrac|recip|rem|repeat|replicate|return|reverse|round|scaleFloat|scanl|scanl1|scanr|scanr1|seq|sequence|sequence_|show|showChar|showInt|showList|showLitChar|showParen|showSigned|showString|shows|showsPrec|significand|signum|sin|sinh|snd|sort|span|splitAt|sqrt|subtract|succ|sum|tail|take|takeWhile|tan|tanh|threadToIOResult|toEnum|toInt|toInteger|toLower|toRational|toUpper|truncate|uncurry|undefined|unlines|until|unwords|unzip|unzip3|userError|words|writeFile|zip|zip3|zipWith|zipWith3)\b/,number:/\b(?:\d+(?:\.\d+)?(?:e[+-]?\d+)?|0o[0-7]+|0x[0-9a-f]+)\b/i,operator:[{pattern:/`(?:[A-Z][\w']*\.)*[_a-z][\w']*`/,greedy:!0},{pattern:/(\s)\.(?=\s)/,lookbehind:!0},/[-!#$%*+=?&@|~:<>^\\\/][-!#$%*+=?&@|~.:<>^\\\/]*|\.[-!#$%*+=?&@|~.:<>^\\\/]+/],hvariable:{pattern:/\b(?:[A-Z][\w']*\.)*[_a-z][\w']*/,inside:{punctuation:/\./}},constant:{pattern:/\b(?:[A-Z][\w']*\.)*[A-Z][\w']*/,inside:{punctuation:/\./}},punctuation:/[{}[\];(),.:]/},Prism.languages.hs=Prism.languages.haskell},2503:()=>{!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,r={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[r,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:r.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:r.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":r,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:r.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:r.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism)},8704:()=>{Prism.languages.nix={comment:{pattern:/\/\*[\s\S]*?\*\/|#.*/,greedy:!0},string:{pattern:/"(?:[^"\\]|\\[\s\S])*"|''(?:(?!'')[\s\S]|''(?:'|\\|\$\{))*''/,greedy:!0,inside:{interpolation:{pattern:/(^|(?:^|(?!'').)[^\\])\$\{(?:[^{}]|\{[^}]*\})*\}/,lookbehind:!0,inside:null}}},url:[/\b(?:[a-z]{3,7}:\/\/)[\w\-+%~\/.:#=?&]+/,{pattern:/([^\/])(?:[\w\-+%~.:#=?&]*(?!\/\/)[\w\-+%~\/.:#=?&])?(?!\/\/)\/[\w\-+%~\/.:#=?&]*/,lookbehind:!0}],antiquotation:{pattern:/\$(?=\{)/,alias:"important"},number:/\b\d+\b/,keyword:/\b(?:assert|builtins|else|if|in|inherit|let|null|or|then|with)\b/,function:/\b(?:abort|add|all|any|attrNames|attrValues|baseNameOf|compareVersions|concatLists|currentSystem|deepSeq|derivation|dirOf|div|elem(?:At)?|fetch(?:Tarball|url)|filter(?:Source)?|fromJSON|genList|getAttr|getEnv|hasAttr|hashString|head|import|intersectAttrs|is(?:Attrs|Bool|Function|Int|List|Null|String)|length|lessThan|listToAttrs|map|mul|parseDrvName|pathExists|read(?:Dir|File)|removeAttrs|replaceStrings|seq|sort|stringLength|sub(?:string)?|tail|throw|to(?:File|JSON|Path|String|XML)|trace|typeOf)\b|\bfoldl'\B/,boolean:/\b(?:false|true)\b/,operator:/[=!<>]=?|\+\+?|\|\||&&|\/\/|->?|[?@]/,punctuation:/[{}()[\].,:;]/},Prism.languages.nix.string.inside.interpolation.inside=Prism.languages.nix},3210:()=>{Prism.languages.pascal={directive:{pattern:/\{\$[\s\S]*?\}/,greedy:!0,alias:["marco","property"]},comment:{pattern:/\(\*[\s\S]*?\*\)|\{[\s\S]*?\}|\/\/.*/,greedy:!0},string:{pattern:/(?:'(?:''|[^'\r\n])*'(?!')|#[&$%]?[a-f\d]+)+|\^[a-z]/i,greedy:!0},asm:{pattern:/(\basm\b)[\s\S]+?(?=\bend\s*[;[])/i,lookbehind:!0,greedy:!0,inside:null},keyword:[{pattern:/(^|[^&])\b(?:absolute|array|asm|begin|case|const|constructor|destructor|do|downto|else|end|file|for|function|goto|if|implementation|inherited|inline|interface|label|nil|object|of|operator|packed|procedure|program|record|reintroduce|repeat|self|set|string|then|to|type|unit|until|uses|var|while|with)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:dispose|exit|false|new|true)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:class|dispinterface|except|exports|finalization|finally|initialization|inline|library|on|out|packed|property|raise|resourcestring|threadvar|try)\b/i,lookbehind:!0},{pattern:/(^|[^&])\b(?:absolute|abstract|alias|assembler|bitpacked|break|cdecl|continue|cppdecl|cvar|default|deprecated|dynamic|enumerator|experimental|export|external|far|far16|forward|generic|helper|implements|index|interrupt|iochecks|local|message|name|near|nodefault|noreturn|nostackframe|oldfpccall|otherwise|overload|override|pascal|platform|private|protected|public|published|read|register|reintroduce|result|safecall|saveregisters|softfloat|specialize|static|stdcall|stored|strict|unaligned|unimplemented|varargs|virtual|write)\b/i,lookbehind:!0}],number:[/(?:[&%]\d+|\$[a-f\d]+)/i,/\b\d+(?:\.\d+)?(?:e[+-]?\d+)?/i],operator:[/\.\.|\*\*|:=|<[<=>]?|>[>=]?|[+\-*\/]=?|[@^=]/,{pattern:/(^|[^&])\b(?:and|as|div|exclude|in|include|is|mod|not|or|shl|shr|xor)\b/,lookbehind:!0}],punctuation:/\(\.|\.\)|[()\[\]:;,.]/},Prism.languages.pascal.asm.inside=Prism.languages.extend("pascal",{asm:void 0,keyword:void 0,operator:void 0}),Prism.languages.objectpascal=Prism.languages.pascal},9385:()=>{!function(e){e.languages.ruby=e.languages.extend("clike",{comment:{pattern:/#.*|^=begin\s[\s\S]*?^=end/m,greedy:!0},"class-name":{pattern:/(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/,operator:/\.{2,3}|&\.|===||[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/,punctuation:/[(){}[\].,;]/}),e.languages.insertBefore("ruby","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}});var t={pattern:/((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/,lookbehind:!0,inside:{content:{pattern:/^(#\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:e.languages.ruby},delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"}}};delete e.languages.ruby.function;var n="(?:"+[/([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source,/\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source,/<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source].join("|")+")",r=/(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source;e.languages.insertBefore("ruby","keyword",{"regex-literal":[{pattern:RegExp(/%r/.source+n+/[egimnosux]{0,6}/.source),greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:[{pattern:RegExp(/(^|[^:]):/.source+r),lookbehind:!0,greedy:!0},{pattern:RegExp(/([\r\n{(,][ \t]*)/.source+r+/(?=:(?!:))/.source),lookbehind:!0,greedy:!0}],"method-definition":{pattern:/(\bdef\s+)\w+(?:\s*\.\s*\w+)?/,lookbehind:!0,inside:{function:/\b\w+$/,keyword:/^self\b/,"class-name":/^\w+/,punctuation:/\./}}}),e.languages.insertBefore("ruby","string",{"string-literal":[{pattern:RegExp(/%[qQiIwWs]?/.source+n),greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?/}},interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?'|'$/}},string:/[\s\S]+/}}],"command-literal":[{pattern:RegExp(/%x/.source+n),greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}},{pattern:/`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/,greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}}]}),delete e.languages.ruby.string,e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/,constant:/\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/}),e.languages.rb=e.languages.ruby}(Prism)},767:()=>{!function(e){for(var t=/\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|)*\*\//.source,n=0;n<2;n++)t=t.replace(//g,(function(){return t}));t=t.replace(//g,(function(){return/[^\s\S]/.source})),e.languages.rust={comment:[{pattern:RegExp(/(^|[^\\])/.source+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:"attr-name",inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:"punctuation"},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:"symbol"},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:"punctuation"},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:"function"},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:"class-name"},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:"namespace"},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:"namespace",inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:"property"},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<>?=?|[@?]/},e.languages.rust["closure-params"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(Prism)},9462:(e,t,n)=>{var r={"./prism-ada":5795,"./prism-bash":7874,"./prism-csharp":9016,"./prism-dot":397,"./prism-haskell":1295,"./prism-java":2503,"./prism-nix":8704,"./prism-pascal":3210,"./prism-ruby":9385,"./prism-rust":767};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=9462},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(7418),o=n(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n