From 3154ebc93d5ddad5a84aefe1d64bdd57f710f5db Mon Sep 17 00:00:00 2001 From: <> Date: Tue, 9 Jul 2024 10:49:42 +0000 Subject: [PATCH] Deployed dc5ab38 with MkDocs version: 1.6.0 --- .nojekyll | 0 404.html | 1072 +++ assets/CloudSIG repositories schema.png | Bin 0 -> 37126 bytes assets/CloudSIG-dependencies.png | Bin 0 -> 80396 bytes assets/RDO Trunk repositories shema.png | Bin 0 -> 66442 bytes assets/favicon-rdo.ico | Bin 0 -> 25150 bytes assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.fe8b6f2b.min.js | 29 + assets/javascripts/bundle.fe8b6f2b.min.js.map | 7 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.el.min.js | 1 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.he.min.js | 1 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.b8dbb3d2.min.js | 42 + .../workers/search.b8dbb3d2.min.js.map | 7 + assets/new-dependencies-2.png | Bin 0 -> 107831 bytes assets/rdo-ci-2.png | Bin 0 -> 146137 bytes assets/rdo-ftbfs-dashboard.png | Bin 0 -> 75601 bytes ...-full-workflow-high-level-no-buildlogs.png | Bin 0 -> 70140 bytes assets/rdo-zuul-ci.png | Bin 0 -> 245851 bytes assets/rdologo.png | Bin 0 -> 1647 bytes assets/spencer.png | Bin 0 -> 102826 bytes assets/stylesheets/main.6543a935.min.css | 1 + assets/stylesheets/main.6543a935.min.css.map | 1 + assets/stylesheets/palette.06af60db.min.css | 1 + .../stylesheets/palette.06af60db.min.css.map | 1 + community/community-meeting/index.html | 1426 ++++ community/faq/index.html | 1552 ++++ community/index.html | 1311 ++++ community/irc-etiquette/index.html | 1230 +++ community/mailing-lists/index.html | 1163 +++ community/rdo-videos/index.html | 1267 ++++ contribute/add-packages/index.html | 1227 +++ contribute/get_packages_ready/index.html | 1259 ++++ .../how-to-fix-a-ftbfs-using-dlrn/index.html | 1122 +++ contribute/index.html | 1186 +++ contribute/intro-packaging/index.html | 1662 ++++ contribute/mentors.html/index.html | 1223 +++ contribute/new_release_guide/index.html | 1424 ++++ contribute/onboarding/index.html | 1625 ++++ .../package-building-overview/index.html | 1351 ++++ contribute/packager/index.html | 1270 ++++ .../rdo-packaging-guidelines/index.html | 1349 ++++ contribute/release/index.html | 1231 +++ contribute/requirements/index.html | 1487 ++++ contribute/retire-packages/index.html | 1160 +++ .../general_concept_comparison/index.html | 1460 ++++ .../how-to-install-rdo-repo/index.html | 1149 +++ deliverables/index.html | 1144 +++ deliverables/release-cadence/index.html | 1429 ++++ deliverables/repos/index.html | 1342 ++++ deliverables/trunk-repos/index.html | 1262 ++++ deploy/index.html | 1214 +++ deploy/packstack/index.html | 1206 +++ deploy/tripleo/index.html | 1142 +++ factory/dlrn/index.html | 1306 ++++ factory/index.html | 1144 +++ factory/pipeline/index.html | 1272 ++++ factory/promotion-pipeline/index.html | 1391 ++++ factory/workflow-overview/index.html | 1155 +++ index.html | 1407 ++++ misc/networking/index.html | 1308 ++++ misc/qpid-errors/index.html | 1141 +++ misc/selinux-issues/index.html | 1195 +++ misc/selinux/index.html | 1109 +++ misc/troubleshoot/index.html | 1104 +++ misc/uninstalling-rdo/index.html | 1099 +++ search/search_index.json | 1 + sitemap.xml | 3 + sitemap.xml.gz | Bin 0 -> 127 bytes stylesheets/extra.css | 3 + 101 files changed, 60873 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 assets/CloudSIG repositories schema.png create mode 100644 assets/CloudSIG-dependencies.png create mode 100644 assets/RDO Trunk repositories shema.png create mode 100644 assets/favicon-rdo.ico create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.fe8b6f2b.min.js create mode 100644 assets/javascripts/bundle.fe8b6f2b.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.el.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.he.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.b8dbb3d2.min.js create mode 100644 assets/javascripts/workers/search.b8dbb3d2.min.js.map create mode 100644 assets/new-dependencies-2.png create mode 100644 assets/rdo-ci-2.png create mode 100644 assets/rdo-ftbfs-dashboard.png create mode 100644 assets/rdo-full-workflow-high-level-no-buildlogs.png create mode 100644 assets/rdo-zuul-ci.png create mode 100644 assets/rdologo.png create mode 100644 assets/spencer.png create mode 100644 assets/stylesheets/main.6543a935.min.css create mode 100644 assets/stylesheets/main.6543a935.min.css.map create mode 100644 assets/stylesheets/palette.06af60db.min.css create mode 100644 assets/stylesheets/palette.06af60db.min.css.map create mode 100644 community/community-meeting/index.html create mode 100644 community/faq/index.html create mode 100644 community/index.html create mode 100644 community/irc-etiquette/index.html create mode 100644 community/mailing-lists/index.html create mode 100644 community/rdo-videos/index.html create mode 100644 contribute/add-packages/index.html create mode 100644 contribute/get_packages_ready/index.html create mode 100644 contribute/how-to-fix-a-ftbfs-using-dlrn/index.html create mode 100644 contribute/index.html create mode 100644 contribute/intro-packaging/index.html create mode 100644 contribute/mentors.html/index.html create mode 100644 contribute/new_release_guide/index.html create mode 100644 contribute/onboarding/index.html create mode 100644 contribute/package-building-overview/index.html create mode 100644 contribute/packager/index.html create mode 100644 contribute/rdo-packaging-guidelines/index.html create mode 100644 contribute/release/index.html create mode 100644 contribute/requirements/index.html create mode 100644 contribute/retire-packages/index.html create mode 100644 deliverables/general_concept_comparison/index.html create mode 100644 deliverables/how-to-install-rdo-repo/index.html create mode 100644 deliverables/index.html create mode 100644 deliverables/release-cadence/index.html create mode 100644 deliverables/repos/index.html create mode 100644 deliverables/trunk-repos/index.html create mode 100644 deploy/index.html create mode 100644 deploy/packstack/index.html create mode 100644 deploy/tripleo/index.html create mode 100644 factory/dlrn/index.html create mode 100644 factory/index.html create mode 100644 factory/pipeline/index.html create mode 100644 factory/promotion-pipeline/index.html create mode 100644 factory/workflow-overview/index.html create mode 100644 index.html create mode 100644 misc/networking/index.html create mode 100644 misc/qpid-errors/index.html create mode 100644 misc/selinux-issues/index.html create mode 100644 misc/selinux/index.html create mode 100644 misc/troubleshoot/index.html create mode 100644 misc/uninstalling-rdo/index.html create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz create mode 100644 stylesheets/extra.css diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..9c4f903 --- /dev/null +++ b/404.html @@ -0,0 +1,1072 @@ + + + + + + + + + + + + + + + + + + + + + + + + An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/assets/CloudSIG repositories schema.png b/assets/CloudSIG repositories schema.png new file mode 100644 index 0000000000000000000000000000000000000000..350f5082e1bd6cea530e2041bcc15e7198fadfbc GIT binary patch literal 37126 zcmeFYXIxWR+b#~n3^vdKRGPpD3epL^qa%V8VF@7PRfg+~W_6P0>q!MzrX{lLs)c<_`X9fOe1^zEq;5k#3CON0Id~>{TC!yJU>qMnG z^)*vILZ5ef~b$iIoZN>k(*>~emb7(%~+;=j6^gN`m zb10H|p5k$|z#OJ``7qe(SNF4B^5Q4v`I`i7^fs<9-eQfsHRE?QyxE4m9^jy@s(P0$ zvv%hzaVSwoWru4g_%ITjSDJJ=bcPP_$T=5>J-OAM{Ar?B!H%1Iqy_GTYwJY70*;Qu zmgB0wPtlpv(r4rK1q@d?%4JXPPU%;00Pa-uHYu@e=CTwg#iN(ws{Xzc!r?pn4ehr% zd3@aRnwOhlx$W#L*^&$lPPS(Cu(Qp#60kF^c@{z7 zjWkg|9eGq$ zH9y*EuIYfVbGEPhpIcffQ(R9orQMW=C{Dn9_mkLcE}!MEwSI;W+Q|q0cvRmxJo$3s zV}INUscK0CCj3GdMQ!wbX>SDU_Lel;-tjRE6pTa+XX8qstX9H+h*yi%9 z{%>9#pVSezZ)SR%HSDEa=}s_z9q8%cNVIdXk2inam6AcN)4&_7G4>IVB=2vSa3i!60vccff zof_8qH&~TpAJlfPNSWLmN!{xBubT5S#Dy-ZguhGTc~8jh+j^~yWUy7~YU1*DlLl(i zSAdI%flF~a5#tm066M7XYP#NQMP_pP*FnyN>u2Q3HfG!(J6YWTr+x6wAuE#xH05YR zi04{KWj_haIlgKjq|2;t73$(bJ>~@R)KcR?2P5epf)a9&XMYV^HoX}YZOE+|$SsM4 z1Q&XqIp{Puf#ZqGkgW+e%P6@;reqR*|Y^b@c~-+>cR_Gy!p*baOSU1Pa}JRI+X-c5Ft|~BaOmE&Y!8us~0Ct>OK{i zr_?!JcM4B-p2{GR`GH{2zVt0A9rpOSB3q$&g{_v|`JwZBeHwRiUQJde`>?y!`PgNq zxQ2uBQ1IK^wr5*@bIn!TErMm`NyZZGWF?BdNr~Hx$-D#c98{Dw!LX$Woi_Y1U>j>V zfhLctBoFRvJmB7#ja?CM*F>e1%DEK--YaqGy@t&>{%3hC50~AY@WOTcrRsv^ZT6Fn zB#*@|{!sxtFNt>JS#K*A1z0dk)8^-j{@vvcX@xD;ZU58cKp%+z1>Z0{cVj!GYQ8Dt zrm{c^0o8pAy$_oVjGXHLzfQd-SW=}XyPT!fnWR-F%xXO-kqpwQZ%9ywgsN;R5Laa* z>Kz@6f$tTz99Aq7#%FXHDNAMv@&TIu_#iZYsqV>2A-dFJCtJ6L@o@6utJo_PvU6o- z(MtO6;Q?1MKpn=2hmY>RjS?ifa*p9vjm%?VH)jg)5c7~ovyHqQFI`+!o zU{k%Vdytcb!o^*@ZUX=IJ+Fh>iEBMsfxfL*Wi|QxRXtIWYUTAFvQF#I7Uzb}O;F@G zzfhCLyW5NPVW(C^oMn@5964rHwod{U^s$N_U#Y81SrW5<{UT2f5{ew}IFICFhWPLF z91JeTWbP!)?6LoXw;tDXiL_HMW8p=}D8&&>)U>-%){pv z<}kDt5|Z=70CDfcab%6qeIgpVYZ}b(zFd74-<%U%TeZWZD=(NrUY#nQuYP!^^~3Ge zQPCFh^R~SZuepSlQwVZ?{tAa_QDV)2PLRPmKXOIa>pTZY=;{1YfDcc1Z+<@IxNjdm zh?N0mpSEfhb{UdFCyJ_ds!TR0Nq*z)Oo10jcR+wFg9*Yk6 zwf@{J74#51_o8mLZay@cmq2;i4eD-;q4ob3Q#@hrH~M!nc!#)Rt*wla1MF`lTLJ zXAj-947Tx{za!ICl}n9zz`Ow@I=HE>U5Tzwqg9eklg3-#xn|FhzVh2UJZrmYr?!Fh zVCQowg1g>-!i6b832FPwUS)%qJ}ex>z|W>7DPE2qan4(k*JkUB1GTH}gXeWdWZH4(!(m2nb7hJBRH^o6UD^D3c{s!@GC&(|p(lR@ zBh=IM6OD!T&a;^+t5<)Pf8_&d5Y(ikez z+_Hg8`ceLp($q#fkFDu2749Ogeto>$K73RvZz%-YQD=~YxgjwxpZt(WnR7!&6D6#> zq5Md;a=9>LpjhcoVzWjXY;~~g`Mrr(!Jm!fUL~xzr-@^lJRc(yR-%Z}w;V%8QNbWh3NR7jBfd$+7Xc63AtRxck^FTy=i2L*}dX_sQ+&sb+!C*G``I3|c*Ugk&p} z3)B72`*YK?yzapED(~_aD&`H&;C+pQLrd-D7qn@txu%%0-4_eCA#{pR9a9AOt)3JOoK>4*FXZZ> zqH!?l?*e#TrEnR~mRu>1cxLZtUqo&U?a_#---LOOzi}^UScqALp?kBpyQ$^g^Nq4r z(y*r7N{&N#BWBjtUcZ$lLGk{C6P#Lv&CNbXB&T!WR!Ck|{6~4aXEfU1+DyAN%mz)87c$E=8XSJYixXU zKfg0Q&tYSHCqCjlDm_jo#>5Hg^PG+_SSg!pGERx6yGwpY_cL4D>~#;%M_^O^ng+-4 zLQ5|fqzHq{NFqq5|8`byBDMXg2&K3D!^dr^RAQ( z4LnM@;DF_e6n5$_@dCEIOx|1pHtPw$^;tPOPWcvFuqkh=;#U2Uc=$>FkA+RD)B5|V zXN5`bIn>quB#x#1AE@#W;4*gccK#pYn!LA+K>fz^dyl)bc<4ODPd}#pfHR@d&QEne zF7V{F)xriEe$h`FOUhb=KXwrwUNY}Q@=xZDpAhtA4j z3*<83EUF^uEhv@`&(aVF(o@`OPhu&s&s2E?+?n1ib3s{ysP^otk4y~SA{Nt@v0@hv z@(j)?^bcV%yu$P>-^-rSZ6F6kr z<_oKThJMoM5#iM0ANLTo|k->RnCN`oeqd`PDu1ikxaHhev4-_+ekSjJ7?4BXH7d)4Gr>E_r(Y-r~ z+^EDJN<#_?(L_Z^6}tUBkvl5 zBxIOgevtG68t2*{|2x}C?Tv|2m9U+{FafEK?~SkXr>Hg-pdChBw!_+yH#x!x^oPICD{$xlBIzWd<^Dh2wAz06 zzZ*n(@71rw>b^4c2B`(~_wNIOC)WSDgA?PuId&{suME`2djH(Oa{}4_v>LmdEdgXp zi1fx-Bgra3h4jbnphMUrsjuIsUgV@|6|2k~B6?ySQ1~7Dcul#*a-@Ukrd;3_dk~zL zxW;Zrkcx=Z^xqG7(j+>srnGQ zwumCu{2k-S&>b$!b$`Yc+h!!l@ZbD-m(n}oHd7Z;5>j}0p+vzw;YYS{pEY}>>Y&%A zTS-#Y7juP%qm@2|H@6V0v#4yhEWkO((9J$uN0~a=)0R_3PBXF$45)X5rRMda6%IH~ zw9@$>o#(hMQ7iVG^L+?1>7-YZ6s^_i8{~d`?8uaLQwYkue5AVs@H{>g4&6H=26*Xr zaI3sfxv_9;>ieJbDYpsMz(!B30@$TR9r5P}eWw3Bd4?Nuh?v?MCj_wnjY8$2lEA`x zHO7~(hK#=)T6Gw*Ob_@cfJf>4``Uy)Nj_bZf1L4IP_m3Qu*CcS^;+t;^_K!j1FhRz zhV$Xy0k8jZJ^mP#`0qjf9`rxgz@Yyb~GhR*KN$empb8_!WaN%lhFgPD0Z(keTQIg3~kl(?KcI0u*LW&~GLjBDeRu8K+ zm%BqO4;Fq}eB-3v72=`09g1%Px0)S%zEb~|&LQWLOlvRt|O2^xs-!(ptXpt4c6_c6aYJ z-8GIvab-O19dd z@ZtJ+qz)aTMX}bP?Cy*Iy6(;!Km1D=-fne zobZ;zlaE^UA~yRNmodT4+qWzNAFrJ%_^$uVd#_&IiL0+%n!Cod8I$iX+Al zEy}O#uB|!^giLH|ozwGMt$r?(9v5!EQsTF?DC=X5(8-<2xxA^tdaVrkjie^R*CwB| z<1QrfzkxZt}ja zMA^TZIH)3I0fd)|5ALchj=x4WiBG$zIfPf4LajmSXP@#mrKgC{*7andt0v5g$!%Y$P6!wv8!ArRPb3SL z_SJ6Xn0GY=akl9@aV)*hfZ($~jNM3(bx9+kqiQCN^=)9q$}CZl?kTHo4UYI(c!V)R|W4 zqV_t5*w^#3Zu3EZ1zE58&6W8!6huzXyf<2nxlgp2kR=8q4|IH_H==LmYI@p09$?p` z^*?Ph?^4edukK2e-Rje-pPxBP;H(sCdC65-x zYOeTvjzSVLmVy_B9U>M5g_w4<+F(ok6wF4`Q9QrR-f~ZO7?;;z7r50zwX`wSuSH&B zz8aJnUsONmCOU96=w2O^rFD4Srd4?2W@JuXn3Lk(msC!UcqQ_muLv&H9e}TMsg6! z@~;vOI?kI*%~ARTR7^Il7fnw)-dJLzS8hFx3lNz&9@>H2Ey$^`94B@X5aP`o8FG~n zR;c%oA}q6FZl(AQjjxqV%kdHaLmIfL-SIb`I-xD55W=wpzL9wdnL*vQof~31HN^)r zo>tdOn||57i{-Ke&=BuWD1|q6DckIUzB~8I$;Uwn#U&I3mj$axW|fQf6t7a| z1|{LvdZA;UUyicyy^sZ78@!L&o4Go332j7^%W}pA&Ou@+Gys<7d!DULY2-^t7`nej zn7%>2ehcSsax`#-Ir59TJ4fCrWm}wA(Q|YW34MP(43DI|Rl=0tsl(Zhzgm`S?txZ? zb34I^u@FsQFb;qQ)EVT zo(tS4cM*2FnK45As2&o^j<2_nQm)5^jqRpwKQlbF->ALxNuf)h6dG}EG}d>>u`t8_ z3HWt-f)yiAX__(}Gt^E)OO1KfQw_;kkmjaABeI>iZ{4el_5>s8plYg-#D+8h@b47S zMt|)qKx;M+;_qI z3Vv_O=9*Qjv#@zZ4b z*SA>4MEBQl3PQ~zU&UYv1DzwCDKSI%U5T3?{aQE<*_jh6yGG9NUb&(2%A$08Bz?Pq z0G&AG*cS_fx2VNHkm7MuBfm^L3!nBaiWzhnnYZ{r{>vWdiklfKa_s|Mb>>duStYJU z`}*NhNYmSRj_J3Sb*4NSgLQ5*ZcNTM>RF)ZN2M42Jc zarY9;z&!Ixs#j0DZ5cnGSsaKrj_q~y{cp3B{dLCqkd>O=!-V-@RTEcVh2A5V?S}-+ zURB@zjj-cIL%q#ZNACn!_7Xbr!$1#JxumBxoRO3Zom}XK&OwyqdtAB=3Io%$N9y=- zullQqvme!KGR48|qzxhG$LMX3pt86VML}%=LespN&r^Gop&Rd?&;-5pbz{D9%OcFt zj?&|NM+L+Lvp&9n=7m22qn{iLi?|IBn& zf=&3cJ-JNM6KosfKD6#39%@dOPXWWy(pRg+z(Ci7D1BJ9&fcS?D>zi9YOxUj5wSq) zMn1kvUVR|JT?qPe{J>;p+b|Ud58U78l%90fmR;(n>3lI{X(}I<#BObGWi% z3$4Mwk=OS>A1F+n80Y3Lb=A$6PDUoJN90y$e4&!y&2SV$O{jWmY^==haxZSnw55HH zohnoC-u#)~LqLlu7es9q^Q{VD*i*uSxS{v5cd+5)jfwl_5q&2U7dDPT{YqAau@H{( z*;12G*qcF`aT7x7tmGEWlqvqTy@QImpPlJR6Fkq4*P_^@*yq+IN$^P60dQ;D!;yC? zM;K;k0w|(I$d;=c)IKyDpe^}F5|m0N!)Ss}KI1j)5Z*u~2X6_4@!(O>tJ_8?mH zEqUgB&>I_CLHaaWB-YWohM_4o2wJLJ`BKFnwPvPR@lfybz^ zlDCc1oOBQjGL7xh-$>x+ol6@uA?oWJEB_`F@#o30a;zq8T4iVV9+PO%Mnksz+2n|H ze!G_nr$1$-0Zwh-=$OQi_BvGt(+RMYoQVwKdzs|Zj6MM z%ad=6>c@K0Xuo90Gstqh{%$)q+Rn%>#YL(;?N{zFRccZo3*VuhWcyVfspTU#=#Lo( z8fjm9U~;*TIlu&Xs458`vcF^sx}NC*VX|4KJ-SkkU`hy>?W#mJsg{|hj?^^L(g{d_ z3*}WEV=+IE0}$g}BY*zQ9_@lmM~Q-FlPhx`~DUG#6weBc~G9tx|W8)hw=Q~)|;kdiC<=792ITKzvs-vL2wdPM6`A@t~DQHXS zEFi$3{;|va0xx0$VeR_U;?OcwY^9~=XGUa5V$2IAI^{l#&adyDY99O+7|}iEY-l-K zXcSj?nNy!l3t<(?J<0((CGGah!%A#?p4P$F>0(i)6VZ94^JXKO{=$flGG5d3$Uu0y zoh2+h_N0?6a_iRID-+40{BQ4-Pve5xSR%~Mjv5;KdB=9zN}roes9tNGazDZeFB=`h( zv}c1}kN7%{9;ijYEEOKue)E%AJ4QEh0%dssh-eWX?fXzs1gJ#ja0x2o-4}2St zP&rF$Vva|&ScEYO?=RkP!1%O0_<|KK0uuDk-(hmV63EJeOc?r!lO>~5MSkP^kzP+& zxNh6G)rR0+yPl*vyI}qeaGaocdvx!a7$U0Ql`&$0sm#)m(`yQZ56g~-T8 zgC;ipPO9jc(v6z}C=OYq4cEaM}}F+5t6(aw&sBv?UpKVjbyptt=vJ?yz! z9%<3aB6}d-CpyTp>_7uc_7s2)@UL{MO;1V`vlbMQsi?95C?|2uO~MSb6q+`T*ypM~ z4OCZ&BAqq{`;fDeE6X7*A^NT;RV<~MA81PT4kJ(OvNq5II{pY(nRmJ zc%0Em>$?-}*5C+_E|XUihFS^#tMA+7s+A}TWqcyR6ie4nB#E~ZHT3|d4uiGzeqK0O z?{H7RXQ(yQ(?TbaXL;E6@L7O(`&x;N>GNiPz}y3SZ+mv- z4@u=u0m!{AQCkk7)?2^$(^Y#Vq+p>&g=ckt{a^gLYuj)K`}9Y_07^fd?|~I}sU4xh za>MDd+WVqhov~3E3>wHAf_BF&*1XxaC4{gL#n$;cI6}B!qQKFXQ#kbCL(>N~AoWG1 zUrYP)SImJd+R)fUU;>C~-IWS$P4`L|V?icsbgYCW&~oN`CN9C#hkEGvJRp(V)i$%f z5L%YJUe_L{bdQ1lU<)@zA=FUIg9YVRoT|~qabfoGy{Hdo8^X-!A^1uURdv6#YbI~G z=8~7uSSA+@yy40t4!&!7eSBF_@M<6+U@6f$&_TaR=h}w;e8;ik!@2dO3Ck?KAU$R* zyZL1uW^`GHS*o&u1Xb^X+~DR9r=x7Rt9o0zUKV(No2AN=Tw|&}7oXXMa?LaFCD@n@U zpdhJXi*=|7=pxPgP(5bf8M?0Q(4m~5u=BOyg)sjbOTfB8&|)~7c)Nv)s6vA-Ji%UZ zr*j8)_fVlu1pK5+8puLvl z)&KYt(~_($xRkZJPwwYuFDPXIv9?y<|KotX@~78d?5tGTk5`0f(|uGSjq2TQUN(~r zezykO5b!+YX4EwwLc$lyj&6ba(}A;<)3oP8>8fqXv8HVVC13vGZ6WQ3Czi z07wnk0WJEnbeE;K)P&!(y&SCI8!O$^2=yf-b+xX(DC=^0?8>Q9RMc|`{q>hc5zq2P zU$7Y7Mm4~3!UdH^676Y9y!x6LYuq~>z5Jzc`xK4!;6(1o0rAUiU4pU%CshtDB`@YR%~n^uEt{B#@tWHk2z>? zKTdrC-N>+iu?xxw8U6;X;3*NlN^uD(Km zzPX$SsC)AUPs&a#(7vvlwMhk&rLGwFL&fuhJ0giC7G56cGy`RPVqNzU^0}X0+TK#- zsMZhO05;ZLbu85$byboqxRn@Y<>6}?(GDk(g|_lOM$m~hz1oW>X0~>_EJ~=gG34~z}n zSSwCoXhG{+;#H4YpI}}8OZ?^P$^fpRsHV;T9_A*K9WP@v3W^xV#EOHMpl|dugfX%g zin@$?OWx-IuUX%_@e3T^(iYM$XZso7W}nTt?T=LCY&5cg9m5&a5NDRbJxMGf!V~w4 zdX?JqS7r!HC+tmDEpSIiOGfgw*S+8Dzl1ZtrRJUPLmwwG5wZ*An7d8vm7jLk+C&lT z7Yt4Rf%0`$u+La-&?QZ!tiu6?mH2q15g40{bQZ!%p}AQ@GFd4W2ZG905bG^y4Ib1#s0>iLMA}UyjN8i z2k0Ob!X;HS(s+g_9>^#LXdR6jeU6#>v#0YB04KvV`T5%m++eiw+@Arhz3p!NEKcR=67_m70!#)cQ|#2AoKZ#B*vKr&N+qFxi8W>{Iyi7 z>{z5%q}Act_;R$-0PfP>aWzgeZCj`V zpzsv$NiF|XF($5c>a}L0b@pm}m`D9v+*oS<3v3yO?#?Xg%!)j1vu}j}h}qp(zk;{B z8yiWN&zD;bURUuy%Mt_HR-3M`=NBfvju*NSbgOa?-17m;ei}w(9==q`Tf~s z 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 literal 0 HcmV?d00001 diff --git a/assets/CloudSIG-dependencies.png b/assets/CloudSIG-dependencies.png new file mode 100644 index 0000000000000000000000000000000000000000..ae9e3f4a6c1cf02d564a1e4cee0faa3cf2d171f0 GIT binary patch literal 80396 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�m4OtJea44 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%0AM*^>Gg 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

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

\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an + +

Centos Connect, Brussels, 2023

+ + +
+

User

+ +

Discuss

+

IRC channels

+

Come chat in real-time with RDO users on IRC on the OFTC server:

+
    +
  • +

    #rdo: Any general conversation about RDO, including developer issues and user questions. (Transcripts.)

    +
  • +
  • +

    #openstack: Remember that RDO is just a small part of a larger community. Questions about OpenStack in general, not specifically about RDO, should go to the upstream channel. (Transcripts.)

    +
  • +
+

Come chat in real-time with the CentOS Cloud SIG on IRC on the Libera Chat server:

+
    +
  • #centos-cloud: If you have questions about the CentOS Cloud Special Interest Group (SIG) and the parts of the RDO infrastructure that run in the CentOS Community Build System (cbs), this is where you're most likely to get answers.
  • +
  • #centos-devel: If you have questions about the CentOS Project
  • +
+

IRC meetings

+

We have weekly IRC meetings you can participate in:

+ +

Content writer

+ +

Additional sources

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/community/irc-etiquette/index.html b/community/irc-etiquette/index.html new file mode 100644 index 0000000..f8ebf0b --- /dev/null +++ b/community/irc-etiquette/index.html @@ -0,0 +1,1230 @@ + + + + + + + + + + + + + + + + + + + + + + + + IRC etiquette - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

IRC etiquette

+

See also the list of IRC channels, and the general mentors list for more suggestions of who you might ask.

+

IRC communication guidelines and etiquette

+

Guidelines

+

These are just some guidelines so you get a perspective of IRC culture, communication:

+
    +
  • Try to ask smart questions, let us try to think for ourselves first and not let some poor, good-intentioned soul to do all the thinking for us. [Pro-tip: Eric S. Raymond's guide referred in the Resources section]
  • +
  • Try (as humanly as possible) to be: clear, concrete, specific and complete with your statements/questions. People cannot read your mind.
  • +
  • Be patient: do not expect people will devote time for extreme hand-holding. If a URL is pointed, please try things yourself, do your home-work, use Google effectively.
  • +
  • Try to maintain a balance of taking vs giving from the community. Do not demand excessive attention.
  • +
  • IRC is a DIY environment, not a paid-support forum. If someone responds to you, that is a bonus.
  • +
  • Be reminded: respect people's time, always answering IRC questions isn't developers first priority. Someone could be knee deep in gdb/pdb investigating that time-critical bug.
  • +
  • When in a community environment, just post the question to the channel, you do not have to ping a specific person just because he/she answered your question before. Nor do you have to ask questions like "Anyone alive on this channel?" "Are you using ABC?" Stay channel topic related!
  • +
  • It is an international channel: you may get better responses in certain time-zones, be patient - don't count on instant reactions.
  • +
+

All of the above look dead obvious, but doesn't instantly come to mind when asking questions in a public IRC. And, sure - we also understand we are all human, already overwhelmed and sometimes, we Just Need that answer and not want to follow any heavy instructions. If you're lucky, you might even have the bonus of getting it answered instantly.

+

Pinging for attention (please avoid a 'naked ping')

+

If you're not aware of what a 'naked ping' is, please take 3 minutes to read this excellent post.

+

Do:

+

To save everyone's time, please try to ping with a specific request/question/comment.

+

Preferred:

+
<Bob> Alice: Ping,  re:  a certain topic (or a specific question)
+
+

Even better: if possible, a fully self-contained question requesting a clear action, so the person you pinged may come back 3 hours later and respond at her/his own pace:

+
<Bob> Alice: Ping, re: bug#1456234. Don't you think the reporter
+             should retest with that specific version of openstack-nova
+             mentioned in comment#4? It fixes the bug.
+
+    [3 HOURS LATER. . .]
+
+<Alice> Bob: Hi, you were right with that bug. I had an incorrect assumption.
+             I just closed the bug, adding a relevant rationale.
+
+

(Agreed -- not all questions can be that self-contained, but you get the drift.)

+

Don't:

+

In short: please avoid -- a-ping-followed-by-permission-to-ask-a-question-followed-by-long-silence. Or any similar variants.

+

i.e. do not do a naked ping with no request for any information or any question:

+
<Bob> Alice: Ping
+
+    [LONG SILENCE. . .]
+
+

nor this:

+
<Bob> Alice: Ping
+<Alice> Bob: Pong?
+<Bob> Alice: Can I talk to you now? I have a technical question to discuss
+
+    [LONG SILENCE. . .]
+
+<Alice> Bob: Sure.    (Inside Alice's head -- 'Sigh, will you already ask the question please?!')
+
+    [Again, in some cases, this interrupt is  followed by a long SILENCE. . . ]
+
+<Bob> Alice: A vague question with not so clear details.
+
+

You see what a time drain the above has become which has not led to any meaningful exchange? At this point, I'm sure you can clearly imagine what a test of mental sanity it'll be for Alice to have 10 to 12 pings like that each day. Let's not do that.

+

Resources

+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/community/mailing-lists/index.html b/community/mailing-lists/index.html new file mode 100644 index 0000000..26322f8 --- /dev/null +++ b/community/mailing-lists/index.html @@ -0,0 +1,1163 @@ + + + + + + + + + + + + + + + + + + + + + + + + Mailing lists - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Mailing lists

+

There are three main mailing lists for RDO discussion:

+

Users - users@lists.rdoproject.org

+

The main discussion list if you are looking for help on the RDO project.

+ +

Developers - dev@lists.rdoproject.org

+

The main discussion list for RDO project contributors.

+ +

Newsletter - newsletter@lists.rdoproject.org - inactive

+

A monthly update of what's going on at RDO. This list is read-only, and very low volume.

+ +

Other lists

+

A complete list of mailing lists may be found at RDO Mailing-lists.

+

You may also want to be on one or more of the OpenStack mailing lists.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/community/rdo-videos/index.html b/community/rdo-videos/index.html new file mode 100644 index 0000000..50b6a41 --- /dev/null +++ b/community/rdo-videos/index.html @@ -0,0 +1,1267 @@ + + + + + + + + + + + + + + + + + + + + + + + + RDO videos - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

RDO videos

+

Centos Connect, Brussels, 2024

+ + +

Centos Connect, Brussels, 2023

+ + +

OpenStack PTG, Atlanta, 2017

+ +

CentOS Dojo, Brussels, 2017

+ +

RDO BoF @ OpenStack Summit Austin

+ + +

FOSDEM 2016

+ +

OpenStack Summit Atlanta

+ +

OpenStack Networking Part II

+ + +

OpenStack Networking for Dummies

+ + +

Introducing RDO

+ + +

Installing OpenStack with PackStack and RDO

+ + +

Automating OpenStack with Red Hat & Puppet

+ + +

Heat, OpenStack and Red Hat

+
    +
  • Interview with Steve Hardy at Open World Forum 2013.
  • +
+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/add-packages/index.html b/contribute/add-packages/index.html new file mode 100644 index 0000000..3d6449b --- /dev/null +++ b/contribute/add-packages/index.html @@ -0,0 +1,1227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Adding new packages - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Adding new packages to RDO

+

How to add a new OpenStack package to RDO Trunk

+

When a new package is required in RDO, it must be added to RDO Trunk packaging. +To include new packages, following steps are required:

+
    +
  1. +

    Create a "Package Review" story in RDO Jira board. You can clone the new package template story. +Make sure you replace the title with the actual package name, and provide the reason and upstream code repository in the description. The story should be assigned to the Epic "RDO release name" and "Fix Version/s" field is also assigned to the desired RDO release. +Once the issue has been created, and an initial license check has been conducted, you can continue with steps 2 and 3.

    +
  2. +
  3. +

    Send a review adding the new project in rdo.yml to the rdoinfo project in +review.rdoproject.org. In +this change you must provide the project information and Package Review Jira story +ticket in the commit message (see this example). +Add the project definition in rdo.yml file and under-review tag in tags/under-review.yml file, +as for example:

    +
    # in rdo.yml
    +- project: octavia-lib
    +  conf: rpmfactory-lib
    +  maintainers:
    +  - nmagnezi@redhat.com
    +  - cgoncalves@redhat.com
    +  - bcafarel@redhat.com
    +
    +# in tags/under-review.yml
    +- project: octavia-lib
    +  tags:
    +    under-review:
    +
    +

    Note: Maintainers must be registered in review.rdoproject.org and use the registered email in the rdoinfo review. +This is required to set your permissions on your project.

    +

    Once the patch is merged, following tasks are done by RDO automation process:-

    +
      +
    • Patch is proposed to create project and assign permissions to maintainers to manage the project. +(as in this example)
    • +
    • Once the create project patch is merged, required projects will be created in https://review.rdoproject.org +with repo synched to github.com.
    • +
    • Patch is proposed to add new projects to rdo zuul configuration in review.rdoproject.org.
    • +
    • Patch is proposed to add check jobs to new projects in rdoproject.org. +(as in this example). CI jobs in this patch will fail +until the Patch to add new projects to rdo zuul configuration is merged.
    • +
    +
  4. +
  5. +

    Create a new review to the new distgit project with the needed content (spec +file, etc...) for the initial import as in this example. +This will trigger a CI job to test the package build. The spec will be reviewed by the +core RDO packagers, and cannot be approved by the requester.

    +
  6. +
  7. +

    Once the initial spec is considered ready to merge by the reviewers, go back to the Package Review +Story and update it with the final spec and SRPM. Then, the formal package +review will be conducted by the reviewer using fedora-review. Only after the fedora-review output is added +as a comment in the story, the initial spec review will be approved +in Gerrit.

    +
  8. +
  9. +

    Finally, send a new review to rdoinfo project to remove the under-review tag from tags/under-review.yml file +and add tags for which package needs to be build, For current release Train, 2 files need to be updated(tags/train.yml, +tags/train-uc.yml) (example). +This change can be sent before merging review in step 3 if a Depends-On: <gerrit-change-id step 3> +is added.

    +
  10. +
+

Once the change is merged in rdoinfo, a new package should be automatically built +and published in the RDO Trunk repos.

+

In order to track all review requests related to a new package process, it's recommended +to use the same topic (as add-octavia-lib in the above examples) for all these reviews.

+

RDO project is working to automate as much as possible this process. If you need +help to add new packages, you can ask on #rdo or rdo-list mailing list.

+

+

How to add a new puppet module to RDO Trunk

+

Adding a new puppet module to RDO Trunk is done using the same process as adding a new +package to RDO Trunk with a few small differences. Use the following steps referencing the above +How to add a new package to RDO Trunk +for details on submitting a new puppet module. The steps here correspond to the +steps above offering details specific to puppet modules.

+
    +
  1. +

    Submit the Package Review, instead of including a spec file reference that the +spec file will be generated.

    +
  2. +
  3. +

    Send a review to rdoinfo according to the package requirements. The under-review tag +is still required. Use this as example content:

    +
    # in rdo.yml
    +- project: puppet-congress
    +  conf: rpmfactory-puppet
    +
    +# in tags/under-review.yml
    +- project: puppet-congress
    +  tags:
    +    under-review:
    +
    +
  4. +
  5. +

    Generate the spec file to submit to the new distgit project using this script

    +
  6. +
  7. +

    Process is the same as standard packages

    +
  8. +
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/get_packages_ready/index.html b/contribute/get_packages_ready/index.html new file mode 100644 index 0000000..4584f49 --- /dev/null +++ b/contribute/get_packages_ready/index.html @@ -0,0 +1,1259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + New OpenStack release - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

New OpenStack release

+ +

Getting packages ready for new OpenStack releases

+

When a new OpenStack release is delivered upstream, there is a set of steps that +must be performed in RDO to build and publish new packages both in RDO CloudSIG and +RDO Trunk repos.

+

1. RDO infrastructure preparation

+

Some weeks before a new OpenStack release is published, some changes in RDO tools and +infrastructure are needed to get the delivery pipeline ready. These tasks are mostly done +by RDO core members, for example:

+
    +
  • Adding a new DLRN builder following stable/ branch.
  • +
  • Creating CI jobs for new branches.
  • +
  • Including new release in automation bots.
  • +
  • etc...
  • +
+

Once these tasks are done, it will be announced in rdo mailing lists so that package +maintainers can start carrying out the next steps.

+

2. Update package distgits.

+

Around RC1 time (check upstream schedule), package maintainers +should send required reviews to rpm-master branch to adjust distgits contents to the +changes occurred during the cycle. This typically includes updating minimal versions for +existing dependencies, removing not longer used requirements, etc... Note that +rdopkg reqcheck command can be used to check changes in dependencies.

+

3. Create new branch <release>-rdo in distgits.

+

Once the distgits content is ready for the new release, package maintainers must request a new +branch <release>-rdo for their packages. This can be done by sending a review to the corresponding package +resource in gerrit configuration following next steps:

+
    +
  1. +

    Clone config project:

    +
    git clone https://review.rdoproject.org/r/config
    +
    +
  2. +
  3. +

    RDO gerrit config project +contains a resource file for each managed package. Look for the one containing +the package where the new branch is needed:

    +
    cd config/resources
    +grep <project name>-distgit *
    +
    +

    i.e.:

    +
    $ grep novaclient-distgit *
    +openstack-novaclient.yaml:    openstack-novaclient-distgit:
    +openstack-novaclient.yaml:    openstack/novaclient-distgit:
    +openstack-novaclient.yaml:      acl: openstack-novaclient-distgit
    +
    +
  4. +
  5. +

    Edit the yaml file. Look for <project name>-distgit under repos section. +If it doesn't have a branches sub-section, add it. Inside branches add a new line +with the branch name:

    +
    <release>-rdo: <commit id for last commit in rpm-master in the project distgit>
    +
    +

    The commit id of the last commit in the project distgit must be specified as it +will be used as starting point for the new branch. For example:

    +
    repos:
    +  openstack/novaclient:
    +    acl: openstack-novaclient
    +    description: Mirror of upstream novaclient (mirror + patches)
    +  openstack/novaclient-distgit:
    +    acl: openstack-novaclient-distgit
    +    description: Packaging of upstream novaclient
    +    branches:
    +      pike-rdo: 71fafbb21c2dc8dd518a0c3d5f635b6b04100661
    +      queens-rdo: c2e115b3283fd776cabaf68d0eb7940030fc1821
    +      rocky-rdo: c0663f17adf0bc05999d8b2caabbe9270af93c27
    +      stein-rdo: 9d0b15be17c3aaf39dccd5a0ab8fe01801d6484d
    +
    +
  6. +
  7. +

    Commit the change and send the review using commands:

    +
    git commit -a -m "Create new branch <release>-rdo"
    +git review
    +
    +

    An example of a new branch request can be found here

    +
  8. +
+

4. Request new builds for CloudSIG repos.

+

After new branches are created in distgits and upstream projects have pushed tags for +new RC or final releases (depending on the release model adopted for each upstream +project), new builds are created using Centos Build System by sending a review to the +<release>-rdo branch as shown in this doc. +Note that RDO uses a bot to propose reviews for new releases automatically in most +cases, however it's recomended that package maintainers pay some attention on this process +and send a review if reviews have not been created on time.

+

5. Pin branchless projects in rdoinfo.

+

According to stable policies, RDO Trunk repos shouldn't follow master branch after GA. +By default, DLRN builders are configured to use stable/<release> branches for non-master +releases. However, some projects packaged in RDO don't create stable branches upstream +or use different ones. For example, some independent projects create a branch for +each supported major package version instead of OpenStack release. For those cases, packages +should be pinned to a specific git tag, commit or branch. This is done by sending +a review to rdoinfo project using source-branch parameter for the release tag as +in this example.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/how-to-fix-a-ftbfs-using-dlrn/index.html b/contribute/how-to-fix-a-ftbfs-using-dlrn/index.html new file mode 100644 index 0000000..a9f1cd2 --- /dev/null +++ b/contribute/how-to-fix-a-ftbfs-using-dlrn/index.html @@ -0,0 +1,1122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + How to fix a FTBFS using DLRN - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

How to fix a FTBFS using DLRN

+ +

DLRN is the tool used by the RDO project to build RPM packages for every commit from the OpenStack projects. See article for more details on how DLRN works. These commits from the upstream OpenStack projects can introduce changes that break the packaging. We call these FTBFS (Failure To Build From Source). +When we have a FTBFS reported by DLRN, someone needs to take care of fixing it. You can see these using gerrit at https://review.rdoproject.org/#/q/topic:rdo-FTBFS. +We’ll work on an example reported on the horizon package in https://review.rdoproject.org/r/#/c/1131/1/. Here are the steps to propose a correction:

+
First you need to install DLRN:
+git clone [https://github.com/openstack-packages/DLRN.git](https://github.com/openstack-packages/DLRN.git)
+cd DLRN
+tox
+. .tox/py27/bin/activate
+
+

Then let DLRN build the horizon project to be sure we reproduce the build issue locally: +dlrn --config projects.ini --package-name horizon --dev --head-only

+

Keep in mind that the default projects.ini file will try to create a package for the master branch using CentOS7 as a target. If the failure happens in a different branch, such as stable/mitaka, you will need to adjust the file as needed. +The dist-git repository is stored under data/_distro so extract the gerrit review in this directory:

+
cd data/horizon_distro
+git review -s
+git review -d 1131
+
+

Edit the spec file to fix the problem. Remember to remove the last line in the spec file, it was created by the dummy review. Here in this case, we just needed to remove files not distributed anymore and then archive the change in git resetting the author to take the ownership of the review:

+
git commit --amend -a --reset-author
+cd ../..
+
+

To test your change use the same build command as before with the addition of –local to use your modifications:

+
dlrn --config projects.ini --package-name horizon --dev --head-only --local
+
+

If everything is fine, just submit the change using the rdo-FTBFS topic:

+
cd data/horizon_distro
+git review -t rdo-FTBFS
+
+

Then you’ll need to have the review accepted by a core reviewer. In our example, here is the proposed changeset to fix the problem: https://review.rdoproject.org/r/#/c/1131/2/

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/index.html b/contribute/index.html new file mode 100644 index 0000000..3c78a9b --- /dev/null +++ b/contribute/index.html @@ -0,0 +1,1186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Contribute to RDO - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Contribute to RDO

+

If you are interested in contribute to RDO project, here you can find all documentation related to this process.

+

Our community strives to operate according to the terms of the +OpenStack Code of Conduct.

+

If you're just getting started, and are looking for a little help, +consult our mentors list.

+

Packager

+ +

Tester

+ + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/intro-packaging/index.html b/contribute/intro-packaging/index.html new file mode 100644 index 0000000..8609944 --- /dev/null +++ b/contribute/intro-packaging/index.html @@ -0,0 +1,1662 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + RDO Packaging Introduction - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

RDO OpenStack Packaging

+

Packaging overview

+

RDO produces two set of packages repositories:

+
    +
  • +

    RDO CloudSIG repositories provide packages of upstream point +releases created through a controlled process using CentOS Community Build +System. This is kind of "stable RDO".

    +
  • +
  • +

    RDO Trunk repositories provide packages of latest upstream code without any +additional patches. New packages are created on each commit merged on upstream +OpenStack projects.

    +
  • +
+

Following diagram shows the global packaging process in RDO.

+

RDO packaging workflow

+

+

distgit - where the .spec file lives

+

distgit is a git repository which contains .spec file used for building +a RPM package. It also contains other files needed for building source RPM +such as patches to apply, init scripts etc.

+

RDO packages' distgit repos are hosted on +review.rdoproject.org +and follow $PROJECT-distgit naming. You can navigate the full list of distgit repos using this +link.

+

You can use rdopkg to clone a RDO package distgit and also setup related +remotes:

+
$> rdopkg clone openstack-nova
+Cloning distgit into ./openstack-nova/
+git clone http://review.rdoproject.org/r/p/openstack/nova-distgit.git openstack-nova
+...
+
+

Inspect package history using git:

+
$> cd openstack-nova
+$> git checkout mitaka-rdo
+$> git log --oneline
+ded74f2 Add privsep-helper to nova sudoers file
+55981cf Add python-microversion-parse dependency
+39d576a Update .gitreview
+4e53ad0 Add missing python-cryptography BuildRequires
+
+

See what rdopkg thinks about current distgit:

+
$> rdopkg pkgenv
+
+Package:   openstack-nova
+Version:   13.0.0
+Upstream:  13.0.0
+Tag style: X.Y.Z
+
+Patches style:          review
+Dist-git branch:        mitaka-rdo
+Local patches branch:   mitaka-patches
+Remote patches branch:  patches/mitaka-patches
+Remote upstream branch: upstream/master
+Patches chain:          http://review.rdoproject.org/r/631
+
+

Submit distgit changes for review:

+
$> rdopkg review-spec
+
+

+

Branches in distgits

+

Because of the different build tools used for RDO CloudSIG and Trunk repos and +the differences in dependencies and content in packages for each OpenStack +release, RDO maintains several branches in distgits:

+
    +
  • rpm-<release>: is used to package RDO trunk (version can be master, + mitaka or liberty )
  • +
  • <release>-rdo: is used for RDO CloudSIG.
  • +
+

There are a number of expected differences between the spec files in +rpm-<release> and <release>-rdo branches:

+
    +
  • +

    For RDO trunk, packaging has had Version: and Release: fields + both set to XXX as dlrn takes both of + these from the tags set on the git repositories. For <release>-rdo branches + they must be manually set to the right version and release.

    +
  • +
  • +

    %changelog section is empty in rpm-<release>.

    +
  • +
  • +

    Because we are packaging vanilla upstream code, patches aren't backported into the RDO Trunk repositories.

    +
  • +
  • +

    All of the specs in rpm-<release> branches contain a reference to %{upstream_version} + in the %setup macro, this is because the subdirectory contained in + the source tarball contains both the version and release, this is + being passed into rpmbuild. In the Fedora packaging, spec can + include compatibility macro e.g. Nova + to avoid conflicts when backporting change from master packaging.

    +
  • +
  • +

    The files sources and .gitignore have been truncated in the + master packaging

    +
  • +
  • +

    In %files avoid using %{version} and use instead wildcard *

    +
  • +
+

rpm-master and rpm-master-head branches

+

As previously stated, the rpm-master branch is used to package RDO Trunk using +the master source branch. However, There are two RDO Trunk builder building +packages from that branch:

+
    +
  • +

    The main builder, which pins libraries and clients to the versions included + in upper-constraints.

    +
  • +
  • +

    The master-head, that chases master in all packages, including libraries, clients, etc.

    +
  • +
+

Initially, both builders use the rpm-master distgit branch. However, we may +find an issue for a client or library in master-head that does not show up +on the main builder yet. In those cases, we will create a temporary distgit +branch called rpm-master-head, where the fix will be merged.

+

Having this temporary rpm-master-head branch will allow us to fix the build +for the package, and once the change in the master repo reaches a tagged release +used by the main builder, we can simply cherry-pick the change and remove +the temporary branch.

+

Patches branch

+

Because we rebase often in RDO CloudSIG repos, manual management of patch files in +distgit would be unbearable. That's why each distgit branch +has an associated patches branch which contains upstream git tree with +extra downstream patches on top.

+

A distgit can be automatically updated by rdopkg to include patches from +associated patches branch and thus RPM patches are managed with git.

+

Individual RDO patches are maintained in form of gerrit reviews on +review.rdoproject.org.

+

+

rdopkg

+

rdopkg is a command line tool +that automates many operations on RDO packages including:

+
    +
  • cloning package distgit and setting up remotes
  • +
  • introducing patches
  • +
  • rebases to new versions
  • +
  • sending changes for review
  • +
  • querying rdoinfo metadata
  • +
  • modifying .spec file: bumping versions, managing patches, writing + changelog, producing meaningful commit messages, ...
  • +
+

rdopkg is a Swiss army knife of RDO packaging and it automates a number of +repetitive and error prone processes involving several underlying tools, each +with its own quirks.

+

Install rdopkg from Fedora/EPEL repos:

+
$> dnf install rdopkg
+
+

rdopkg source lives at +softwarefactory-project.io +but it's also mirrored to +github.

+

Bugs are tracked as +github issues.

+

Poke jruzicka on #rdo for help/hate/suggestions about rdopkg.

+

See also man rdopkg.

+

+

rdoinfo metadata

+

rdoinfo is a git repository containing RDO packaging metadata such as +releases, packages, maintainers and more.

+

rdoinfo lives at +review.rdoproject.org +and is also mirrored to github.

+

Most of the metadata is stored in rdo.yml and deps.yml, tags and buildsys-tags +are stored in multiple YAML files as described below:

+ +

The files under tags and buildsys-tags directories are named based on names of tags and buildsys-tags, +this is defined as follows:-

+
    +
  • release: is a the OpenStack release name, as queens, rocky or stein.
  • +
  • tag: tag for which project is build, like queens, rocky, stein, train, train-uc, etc.
  • +
  • phase:
  • +
  • candidate phase is assigned to packages to be rebuilt in + CBS but not pushed to any RDO repository.
  • +
  • el7-build (only available for Rocky and newer releases) + is assigned to packages that only required to build other + packages but are not a runtime requirement for any other package.
  • +
  • testing phase means that the package is used in deployments using RDO Trunk + repo and published in a testing repo, but not official CloudSIG repository.
  • +
  • release phase means that is published in the official CloudSIG repository. + This phase is only available after a RDO version has been officially released + not for the one currently under development.
  • +
+

To query rdoinfo, use rdopkg info:

+
$> rdopkg info
+$> rdopkg info openstack-nova
+$> rdopkg info maintainers:jruzicka@redhat.com
+
+

To integrate rdoinfo in your software, use rdopkg.actionmods.rdoinfo +module.

+

DLRN

+

DLRN is a tool used to build RPM +packages on each commit merged in a set of configurable git repositories. DLRN +uses rdoinfo to retrieve the metadata and repositories associated with each +project in RDO (code and distgit) and mock to carry out the actual build in an +isolated environment.

+

DLRN is used to build the packages in RDO Trunk repositories that are available +from http://trunk.rdoproject.org.

+

NVR for packages generated by DLRN follows some rules:

+
    +
  • Version is set to MAJOR.MINOR.PATCH of the next upstream version.
  • +
  • Release is 0.<timestamp>.<short commit hash>
  • +
+

For example openstack-neutron-8.1.1-0.20160531171125.ddfe09c.el7.centos.noarch.rpm.

+

RDO Trunk Packaging Guide

+

In RDO Trunk packages are built automatically by DLRN from +.spec templates residing in rpm-master and rpm-$RELEASE distgits.

+

In order to build an RPM with the master packaging you'll need to +install DLRN, +following the instructions described in this +README.

+

Run DLRN

+

Once DLRN is installed, run dlrn for the package you are trying to build.

+
$> dlrn --config-file projects.ini --local --package-name openstack-cinder
+
+

This will clone the distgit for the project you're interested in into +data/openstack-cinder_distro, you can now change this packaging and +rerun the dlrn command in test your changes.

+

If you have locally changed the packaging make sure to include --dev +in the command line. This switches dlrn into "dev mode" which +causes it to preserve local changes to your packaging between runs so +you can iterate on spec changes. It will also cause the most current +public master repository to be installed in your build image(as some +of its contents will be needed for dependencies) so that the packager +doesn't have to build the entire set of packages.

+

The output from dlrn is a repository containing the packages you +just built along with the most recent successfully built version of +each package. To find the most recent repository follow the symbolic +link ./data/repos/current

+

Submitting distgit changes to gerrit

+

When modifying spec files for RDO Trunk keep in mind the considerations shown +in Branches in distgits and follow the recommendations +in the RDO Packaging Guidelines. +Once you are happy that you have your changes in distgit ready to be reviewed, +create a git commit with an appropriate comment, add a git remote +pointing to gerrit and then submit your patch

+
$> git review -s
+$> git commit -p
+$> git review rpm-master
+
+

Browsing gerrit for reviews

+

To look at all open patches for the upstream packaging simply use the this +link and look for your +desired project, for example openstack/cinder-distgit.

+

RDO CloudSIG Packaging Guide

+

Packaging files for CloudSIG repos live in $RELEASE-rdo branches of +distgit. Patches can be introduced as needed through associated +patches branch.

+

Initial repository setup

+

rdopkg clone takes care of getting the package distgit and +also setting up all relevant git remotes defined in rdoinfo. +Use -u/--review-user option to specify your github username if it differs +from $USER.

+
$> rdopkg clone openstack-nova -u github-username
+Cloning distgit into ./openstack-nova/
+git clone http://review.rdoproject.org/r/p/openstack/nova-distgit.git openstack-nova
+Adding patches remote...
+git remote add patches http://review.rdoproject.org/r/p/openstack/nova.git
+Adding upstream remote...
+git remote add upstream git://git.openstack.org/openstack/nova
+...
+
+

Check output of rdopkg pkgenv to see what rdopkg thinks about your +package:

+
$> cd openstack-nova
+$> git checkout mitaka-rdo
+$> rdopkg pkgenv
+
+

Simple .spec fix

+

The simplest kind of change that doesn't introduce/remove patches or +different source tarball.

+
    +
  • Make required changes.
  • +
  • Bump Release.
  • +
  • Provide useful %changelog entry describing your change.
  • +
  • Commit the distgit changes with meaningful commit message.
  • +
  • Send the change for review.
  • +
+

Although this change is simple, rdopkg fix can still make some string +manipulation for you. In following example, I add a new dependency to nova +package:

+
$> cd openstack-nova
+$> git checkout mitaka-rdo
+$> rdopkg fix
+
+Action required: Edit .spec file as needed and describe changes in changelog.
+
+Once done, run `rdopkg -c` to continue.
+
+$> vim openstack-nova.spec
+# Add Requires line and describe the change in %changelog
+$> rdopkg -c
+
+

After this, rdopkg generates new commit from the %changelog entry you +provided and displays the diff:

+
    Epoch:            1
+    Version:          13.0.0
+   -Release:          1%{?dist}
+   +Release:          2%{?dist}
+    Summary:          OpenStack Compute (nova)
+
+    ...
+
+    Requires:         bridge-utils
+    Requires:         sg3_utils
+    Requires:         sysfsutils
+   +Requires:         banana
+
+    %description compute
+    OpenStack Compute (codename Nova) is open source software designed to
+
+    ...
+
+    %changelog
+   +* Mon May 09 2016 Jakub Ruzicka <jruzicka@redhat.com> 1:13.0.0-2
+   +- Require banana package for the lulz
+   +
+    * Thu Apr  7 2016 Haïkel Guémar <hguemar@fedoraproject.org> - 1:13.0.0-1
+    - Upstream 13.0.0
+
+

Finally, send the changes for review:

+
$> rdopkg review-spec
+
+

Introducing/removing patches

+

See patches branch for introduction.

+

Following schema shows the workflow to maintain patches applied in the packaging process.

+
     +------------------------+
+     |        upstream        |
+     |  github.com/openstack  |
+     +------------------------+
+                 |
+ git cherry-pick | rdopkg review-patch
+                 V
+     +-------------------------+
+     |      patches branch     |
+     |  review.rdoproject.org  |
+     +-------------------------+
+                 |
+    rdopkg patch | rdopkg review-spec
+                 V
+     +-------------------------+
+     |        distgit          |
+     |  review.rdoproject.org  |
+     +-------------------------+
+
+

First, use rdopkg get-patches to get a patches branch +associated with current distgit, cherry pick your patch(es) on +top, and send them for review with rdopkg review-patch:

+
$> git checkout mitaka-rdo
+$> rdopkg get-patches
+$> git cherry-pick YOUR_PATCH
+$> rdopkg review-patch
+
+

Once the patch gets approved (not merged), you can tell rdopkg to update the +distgit and send the .spec change for review:

+
$> git checkout mitaka-rdo
+$> rdopkg patch
+$> rdopkg review-spec
+
+

For more specific example, please see +Introducing patches to RDO CloudSIG packages RDO blog post.

+

Rebasing on new version

+

tl;dr rdopkg new-version should take care of that:

+
$> git checkout mitaka-rdo
+$> rdopkg new-version
+
+

or rdopkg new-version 1.2.3 to select specific version.

+

Inspect resulting distgit commit and if you need to adjust anything, use +rdopkg amend to amend and regenerate commit message from changelog.

+

Finally, once happy with your change submit it for review with

+
$> rdopkg review-spec
+
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/mentors.html/index.html b/contribute/mentors.html/index.html new file mode 100644 index 0000000..624a17a --- /dev/null +++ b/contribute/mentors.html/index.html @@ -0,0 +1,1223 @@ + + + + + + + + + + + + + + + + + + + + + + + + RDO Mentors - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

RDO Mentors

+

It can sometimes be a little intimidating when you first start +contributing to OpenStack. Most of the RDO related tickets are in the +Jira and have a +designated asignee, you may also wish to find a mentor based on the area +that you're interested in working on.

+

Or, when you arrive on IRC, and ask a question and are greeted with +silence, it can be very useful to know who to ping to get their +attention.

+

The following people have indicated that they're willing to mentor you +through your first contributions, or answer your questions on particular +topics on IRC. Please don't hesitate to ask. (And, if +you're willing to be on the list, please add your name and/or +IRC nick below.)

+

Finally, if you want to contribute to the upstream OpenStack community, +there's a similar list called the OpenStack Upstream +Institute.

+

Who to ask

+

General

+
    +
  • Alfredo Moralejo – amoralej
  • +
  • Alan Pevec – apevec
  • +
  • Amy Marrich – spotz
  • +
  • Joel Capitao – jcapitao
  • +
  • Jon Schlueter – jschlueter/yazug
  • +
  • Karolina Kula – kkula
  • +
+

Installation

+
    +
  • Alfredo Moralejo – amoralej
  • +
  • Joel Capitao – jcapitao
  • +
  • Amy Marrich – spotz
  • +
+

Packaging

+
    +
  • Alfredo Moralejo – amoralej
  • +
  • Joel Capitao – jcapitao
  • +
  • Karolina Kula – kkula
  • +
+

Infrastructure

+
    +
  • Alfredo Moralejo – amoralej
  • +
  • Joel Capitao – jcapitao
  • +
+

Documentation

+
    +
  • Amy Marrich – spotz
  • +
+

Where to ask

+

Conversations about RDO happen a number of different places on IRC. For a full list of IRC channels related to RDO, see the IRC section in Contribute to RDO.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/new_release_guide/index.html b/contribute/new_release_guide/index.html new file mode 100644 index 0000000..66954a8 --- /dev/null +++ b/contribute/new_release_guide/index.html @@ -0,0 +1,1424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Step by step RDO release guide - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Step by step RDO release guide

+

Creating a new release in RDO is a complex process with multiple dependencies. This overview provides users and contributors information on +what leads up to a release and what detailed steps are to be performed before a new release. Not all steps are frozen in the sequence, but +our experience shows that this is the most efficient way of working and some steps may be done in parallel.

+

These steps follow the processes found in OpenStack releases - +typically for the cycle-with-intermediary type of releasing - which is repeatable every 6 months. First there are provided non-client +libraries, followed by client libraries, then services and lastly there are provided release-trailing deliverables.

+

1. Create CBS tags for next release

+

At the very beginning, a new CBS tag for the next release should be created. This is needed before performing a switch to the new master. +This operation is performed by creating a bug on pagure.io/centos-infra. An example can be found +here.

+

2. Create a DLRN builder for the new OpenStack release in RDO Trunk servers.

+

Prepare new DLRN trunk builder.

+

DLRN builder is an instance used to build RDO Trunk repos (follow articles about RDO Trunk repos +and RDO CloudSIG repos). Before we start working on new packages, we have to set the builder. +The first step is a change in rdo-infra/ansible-role-dlrn, where we define new repositories for +the builder, as an example. The second step is to define the +new builder in sf-infra. A patch to sf-infra will to depend on +the previous one from ansible-role-dlrn.

+

Before starting the building process, some steps have to be performed on the builder: +1. Create the database, users and tables +2. Set up authentication from trunk-centos8.rdoproject.org host to trunk.rdoproject.org +3. Synchronize deps

+

Bootstrapping

+

Once the DLRN builder is ready, the bootstrap process can be started. This process is about building all DLRN packages in the proper sequence. +Building is automated, but due to dependencies it may need to be restarted several times, and sometimes requires fixes in spec files.

+

Enable usual operations for the new DLRN Trunk builder

+

The new builder, to be fully operated, needs to have enabled operations which were not possible before bootstrapping. Examples can be +found in sf-infra and ansible-role-dlrn.

+

This operation enables building new packages in the builders with any new commit in the projects (operated by cron), enables triggering +automated gerrit reviews in case of FTBFS and sets the new +builder visible on trunk.rdoproject.org website.

+

Enable distgit CBS builds for next release branch

+

When reviews appear in the new release branch, appropriate jobs and builds have to be triggered.

+

3. Requirement check - reqcheck

+

Most of the projects we are packaging are constantly being developed on, so their requirements can change - added, removed, in the new version or +constrained. This check is being done manually, using the rdopkg reqcheck tool. First libraries +and client packages are rechecked, then the core packages (like openstack-nova).

+

Even though the process seems to be not complicated, the appearing issues are often connected with missing dependencies. +An example requirement check can be found here.

+

4. Build libs, clients and core projects in CloudSIG repos on CBS.

+

Once the requirement check is completes, the next step can be performed - building. To proceed with this, the new releases has to be created upstream. +This step requires following steps:

+
    +
  1. Cut rpm-master branch of distgit repo to create the \<release>-rdo branch. This can be done with branching +script from releng tooling, as an +example, or manually by modifying config repo.
  2. +
  3. Submit review with new version - a helpful script.
  4. +
+

5. Pin, branch and build non-OpenStack puppet modules in CloudSIG repos

+

Non-OpenStack modules have to be pinned to the last promoted hash at branching time, since they don't follow the OpenStack lifecycle +and RDO stable releases do not follow the master branches for them. The package has to be built based on the commit snapshot. +This operation is done with the cooperation of the Puppet OpenStack team - +these modules can be pinned after p-o-i team confirmation.

+
    +
  1. Pin non OpenStack puppet modules, as example, using releng script.
  2. +
  3. Cut branches, as in this review.
  4. +
  5. Build, with releng script.
  6. +
+

6. Move master RDO Trunk to next release tags

+

Rdoinfo buildsys-tags and tags can be moved to the next-release after openstack/requirements is branched. +As in review and review. +This action has to be coordinated with the reviews mentioned in the "Prepare new DLRN trunk builder" section above.

+

7. Branch OpenStack puppet modules and build them in CloudSIG repos

+

There is a bot which will automatically send the update reviews, when the tagged releases are created upstream. +To trigger this step, we have to branch the distgit projects before +the upstream p-o-i project creates the releases for the OpenStack puppet modules.

+

8. Pin, branch and build tempest and tempest plugins in CloudSIG repos

+

Following steps are required to perform this operation:

+
    +
  1. Branch and build the tempest package with bootstrap mode enabled, as here
  2. +
  3. Disable the bootstrap mode without bumping release, to have other Openstack-tempest packages in RDO Trunk - example
  4. +
  5. Cut branches, as in this review
  6. +
  7. Pin tempest plugins in rdoinfo
  8. +
  9. Review automatically created reviews
  10. +
  11. Update version of tempest plugin project
  12. +
+

9. Create the puppet promotion pipeline

+

The Puppet promotion pipelines have to be defined as in patchset. Tests +can be performed using testinfo. +Newly defined jobs have to be assigned to the project - example.

+

10. Create the next release branch for dependencies

+

As development of dependencies is still ongoing, the new branch has to be prepared for featuring builds - as in this +review.

+

New branches have to be created in the upstream requirements repo to complete this task.

+

11. Add support of the new release in ansible-role-weirdo-puppet-openstack

+

This is an example review of this operation.

+

12. Create the rdo-release RPM

+

Following step needs to be performed: +1. Create next release branch in distgit repo, as in example +2. Edit specification file +3. Trigger CBS build +4. Publish the RPM on repos.fedorapeople.org

+

More details about used commands can be found in task description.

+

13. Create weirdo jobs to promote to -release tag

+

The following jobs have to be defined in rdo-jobs repo. Such jobs will be +triggered whenever promoting the package to -release tag.

+

14. Add the new release to dashboards

+

Currently there are three dashboards to update with new release:

+
    +
  1. rdo-dev dashboard
  2. +
  3. Promotion dashboard
  4. +
  5. FTBFS dashboard
  6. +
+

15. Create the new centos-release-openstack-

+

To prepare for final release, the new release rpm has to be created + for CentOS CloudSIG in extras9s-extras-common-el9s, and later tagged in extras9s-extras-common-testing, -release, and finally build.

+

16. Promote GA builds to -testing and -release

+

The final step to publish the next RDO release is performed by review as following one and another, + which can be done only after completing previous step.

+

17. Enable remaining monitoring on Grafana

+

Also monitoring, other than dashboards, should be activated for the new release: Prometheus and Grafana.

+

18. Unpin non OpenStack puppet modules and tempest plugins in master release

+

After the release, these projects can go back to active master. To do so, they have to be unpinned in rdoinfo.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/onboarding/index.html b/contribute/onboarding/index.html new file mode 100644 index 0000000..abb510e --- /dev/null +++ b/contribute/onboarding/index.html @@ -0,0 +1,1625 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Onboarding - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Let's Contribute to the RDO Project!

+

Welcome on board! As a new contributor there are some things you'll want to do +to get ready:

+

Let's get prerequisites ready.

+ +

What's Next!

+ +

+

Join the RDO Mailing List

+
    +
  • Go to RDO mailing list + and enter your email address and password and click on subscribe. Once + done, open your mailbox, you will get a confirmation email, click on the + verification link and you are subscribed to the RDO List.
  • +
  • You can introduce yourself by sending a mail to the mailing list. Tell us + what your interests are and how you plan to participate.
  • +
+

+

Join the IRC channel #rdo on OFTC

+
+

+

Create a GitHub account

+

Go to the GitHub Sign Up page and enter your +username, email address, and password, and you are done. If you already have a +GitHub account, you can skip this step.

+

+

Sign up to review.rdoproject.org

+

Sign-in to review.rdoproject.org +using your GitHub account.

+

+

Add an SSH key to review.rdoproject.org

+
+

+

Create a RDO Jira board account

+

All the bugs related to RDO packages are tracked on Red Hat Jira under the +RDO project. +OpenStack project bugs are tracked on Launchpad.

+
    +
  • You can create a RDO Board account by clicking on the "Log In" button on the + RDO Board page then following the + "Register for a Red Hat account" link.
  • +
+

+

Configure git and git review

+
    +
  • Run these steps to let git know your email address:
  • +
+
$ git config --global user.name "Firstname Lastname"
+$ git config --global user.email "your_email@youremail.com"
+
+
    +
  • To check your git configuration:
  • +
+
$ git config --list
+
+
    +
  • Install the git-review tool
  • +
+

RHEL-based systems (e.g. CentOS Steam 8+ with EPEL repo enabled)

+
$ sudo dnf install git-review
+
+

Fedora-based systems (after F24)

+
$ sudo dnf install git-review
+
+

+

Install the rdopkg tool

+

Follow this link to install +rdopkg, and +you are set for making contributions to the RDO Project.

+

+

Make your first contribution

+
+

For example, cloning keystone-distgit, we need to pass the source code URL.

+
$ git clone https://review.rdoproject.org/r/openstack/keystone-distgit
+
+

You can also use rdopkg to clone an RDO package.

+
$ rdopkg clone package-name
+
+
    +
  • Go inside the project directory, create, and checkout a new branch. + Note: Always create a new branch to work on any issue.
  • +
+
$ cd <project_name>
+$ git checkout -b <issue name>
+
+
    +
  • Make changes in the code and add the changed files to git.
  • +
+
$ git add <changed files>
+
+
    +
  • Commit the changes
  • +
+
$ git commit -m "Add the commit message"
+
+

You can check this link on how to write +proper commit messages.

+
    +
  • If something went wrong in the commit message, or you need to adjust it, run + the following command:
  • +
+
$ git commit --amend
+
+
    +
  • Now push the changes for review using git-review.
  • +
+
$ git review
+
+

Running git review will create an RDO Gerrit review link, and someone from +RDO project will review the changes. Once everything looks fine, and is +approved, your changes will get merged, and you'll have made your first +contribution. Thanks!

+

+

How to fix git Merge conflicts?

+

You have submitted a patch and got merge conflict on your patch. +You can check this link on how to resolving merge conflicts.

+

+

Review RDO patches

+
+

+

Become an RDO package maintainer

+

If you want to become a maintainer for one or more packages, you can request to +be added to the core group for them by sending a review to +rdoinfo as in +this example.

+

Being a maintainer for a package provides the ability to approve reviews for it +(grants +2 and +W in Gerrit terms).

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/package-building-overview/index.html b/contribute/package-building-overview/index.html new file mode 100644 index 0000000..56fb0a1 --- /dev/null +++ b/contribute/package-building-overview/index.html @@ -0,0 +1,1351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Package building - overview - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Package building process – overview

+

In the RDO Project, we maintain two kinds of repos: RDO Trunk repositories and RDO CloudSIG repositories. +RDO Trunk repositories have no-deps Openstack packages, which contain client, core, libs, puppet and tempest packages, while +CloudSIG packages are a set of packages built by CentOS Community Build System. +For Centos9 Stream master Trunk (DLRN) packages are stored in trunks and +CloudSIG packages ends up in CentOS mirror.

+

During the cycle of a given OpenStack release, we have the following recurring activities:

+
    +
  • New packages are created when needed.
  • +
  • Each package is rebuilt anytime a new commit is available in the repository upstream on the RDO Trunk builder.
  • +
  • If the package build fails, a review is automatically opened in our Gerrit review system, so the package maintainers can work on a fix.
  • +
  • Periodically, the latest repository where all packages had been successfully built goes through a number of CI jobs. If all jobs are successful, the repository is promoted, meaning it is considered as good enough for other upstream CIs to rely on it for their jobs.
  • +
+

What is DLRN?

+

In simplest words, DLRN is a tool which builds packages. In automated way DLRN is building package every time when new +commit is merged in observed upstream repos, creating individual, separated environment basing on code, distgit and +rdoinfo repo. DLRN can be also used to manually debug failing +packages.

+

FTBFS

+

If build succeeds, package appears in trunk. If fails, automatic +FTBFS (Fail To Build From Source) review is created in gerrit, providing building +logs and information which commit caused FTBFS, like in example. +All FTBFS’ have to be reviewed and fixed. Current FTBFS can be easily spotted on RDO dashboard. +Other way to check statuses of last builds is checking Latest Build Reports, for example for Centos 9 master.

+

Trunk packages – branching and debugging

+

Each trunk distgit has multiple branches. Under development one is rpm-master and the stable ones are named +\<release>-rdo. The rpm-master branch has Version: and Release: fields filled with XXX, which are automatically +replaced with proper values during the DLRN building process. In \-rdo branch, those values are filled while +cutting the branch: master -> stable/\<release> during the release process. +Having such situation, a different procedure of bug/FTBFS reproduction is needed.

+

Debugging with DLRN

+

Most reliable way to create a debugging or testing environment is Centos 9 container or vm usage. +Steps to reproduce FTBFS:

+
    +
  1. Clone DLRN repo:
  2. +
+
        git clone https://github.com/softwarefactory-project/DLRN.git
+
+
    +
  1. +

    Follow setup procedure from README.

    +
  2. +
  3. +

    Clone rdoinfo repository:

    +
  4. +
+
        git clone "https://review.rdoproject.org/r/rdoinfo"
+
+
    +
  1. Edit projects.ini files with desired data. If you don’t know how to reproduce a remote DLRN build, check logs from +building in FTBFS review. Below you can see example of projects.ini preparation for Centos 9 master.
  2. +
+
        sed -i 's%target=.*%target=centos9-stream%' projects.ini
+        sed -i 's%source=.*%source=master%' projects.ini
+        sed -i 's%baseurl=.*%baseurl=https://trunk.rdoproject.org/centos9/%' projects.ini
+        sed -i 's%tags=.*%tags=%' projects.ini
+
+
    +
  1. Run DLRN command (example package name):
  2. +
+
        dlrn --head-only --dev --local --verbose-build --package-name openstack-tacker --info-repo ../rdoinfo
+
+

You can find more information and explanation of DLRN usage in the documentation.

+
    +
  1. +

    Edit the package distgit or package code directly if needed. Both of them are now created inside DLRN directory, +like data/openstack-tacker_distro for distgit and data/openstack-tacker for code.

    +
  2. +
  3. +

    Run dlrn command once again. You should now be able to see reproduced error.

    +
  4. +
+

Dependencies

+

CloudSIG packages have different workflow of creating, maintaining and storing. They are finally placed in this repo. +Describing CloudSIG packages, it is crucial to explain two packages building systems taking part in whole process. +DLRN is for trunk packages, while for CloudSIG ones there are Koji and CBS. +Whole package process building starts in Fedora. The packages exist in Fedora Package Sources repository, +maintained by packagers an builded by Koji. +If the package is needed in RDO project, it has to be rebuild for RDO. Process of building Fedora package for RDO +using repo gating_script is well described in this document. +Creating such review will effect with rebuilding package in CentOS Build System. +On this level, there may occur some errors or misconfigurations, caused by different environment.

+

Debugging package building failures

+

Logs

+

After pushing your change to code review system, CI will trigger a bunch of tests on it and give results as vote +or/and logs. If +1 is given by Zuul, everything went well. If -1 appears, it means that tests didn’t pass, +so debugging is needed.

+

Find CBS task number in your Zuul job output

+

First step is to check job logs. They are available after clicking on job name in Gerrit. Depending on which point of +building failure happens, the true cause of it may be found in this job output or has to be found directly in CBS +building job. In this example build failure reason can be found in Zuul job output, +but in this one, the real reason has to be looked for in CBS logs, +because Zuul jobs one doesn’t provide anything useful. This is happening when the error doesn’t refers to spec file, +but the building process itself. The easiest way to find proper link to CBS build is to find “taskID” word +in job_output.txt, the result should looks like: Task console is: https://cbs.centos.org/koji/taskinfo?taskID=2800330. +Note, that each job and each patchset has its own individual build number.

+

How to read CBS build logs?

+

After going to the provided URL, general information about build will appear. The logs can be find by clicking on red +hyperlink “buildArch“. Provided output is placed in following files: +* build.log +* hw_info.log +* mock_output.log +* root.log +* state.log

+

If the error refers to dependencies, it will be placed in root.log. +Also some errors may occur in other files, especially in build.log.

+

Common package building issues

+
    +
  • Missing dependency
  • +
+

In a root.log file:
+DEBUG util.py:444: No matching package to install: 'python3dist(xxx)'
+DEBUG util.py:444: Not all dependencies satisfied

+

Solution: The dependency is not tagged yet in our repo or not available. +Contact RDO maintainers to discuss adding a new dependency.

+
    +
  • +

    SPEC file syntax error

    +
  • +
  • +

    Infra issue (timeout)

    +
  • +
+

Solution: If there are timeouts in refreshing repo metadata or other steps, it’s good idea to recheck tests, +by typing comment “recheck” in Gerrit review.

+
    +
  • failing %check phase
    +Some unit tests failed during package building, like in example.
  • +
+

Solution: Create testing environment and try to reproduce the error. Then, try to figure out and fix failing reason. +It is possible to exclude failing test(s), but we only use that solution if it’s strongly +justified (like issue created in bugzilla or other bug tracker).

+
    +
  • missing macro
  • +
+

in build.log file:
+RPM build errors: +/var/tmp/rpm-tmp.s6H1EG: line 32: fg: no job control
+error: Bad exit status from /var/tmp/rpm-tmp.s6H1EG (%generate_buildrequires)
+Bad exit status from /var/tmp/rpm-tmp.s6H1EG (%generate_buildrequires)
+Child return code was: 1

+

Solution: + add BuildRequires: pyproject-rpm-macros to build requirements.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/packager/index.html b/contribute/packager/index.html new file mode 100644 index 0000000..11dfceb --- /dev/null +++ b/contribute/packager/index.html @@ -0,0 +1,1270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Packaging - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/rdo-packaging-guidelines/index.html b/contribute/rdo-packaging-guidelines/index.html new file mode 100644 index 0000000..cb1780c --- /dev/null +++ b/contribute/rdo-packaging-guidelines/index.html @@ -0,0 +1,1349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + RDO OpenStack Packaging Guidelines - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

RDO OpenStack Packaging Guidelines

+

Introduction

+

This document collects guidelines and practical tips

+

Packaging Guidelines

+

RDO packages mostly follow Fedora Packaging Guidelines. +There are two exceptions:

+
    +
  • Override rules listed in this document.
  • +
  • Exceptions granted by RDO Packaging Group (e.g. bundling)
  • +
+

A set of examples for spec and other useful files can be found in +openstack-example-spec github repository. These files can be used as templates for new packages although +some adjustments may be needed for each particular case.

+

Package Naming Guidelines

+

RDO packages mostly follow Fedora Package Naming Guidelines. +On top of it to maintain consistency in package names across different sets of RDO packages we follow:-

+
    +
  • For service package: name it like 'openstack-', ex. openstack-nova, openstack-cinder, etc.
  • +
  • For python library: name it like 'python-', ex. python-oslo-cache, python-novaclient, etc.
  • +
  • For puppet package: name it like 'puppet-', ex. puppet-nova, puppet-cinder, etc.
  • +
  • For tempest plugin: name it like 'python--tests-tempest', ex. python-heat-tests-tempest, python-mistral-tests-tempest, etc.
  • +
  • For ui package: name it like 'openstack--ui', ex. openstack-heat-ui, openstack-octavia-ui, etc.
  • +
  • For ansible role: name it like 'ansible-role-', ex. ansible-role-container-registry, ansible-role-chrony, etc.
  • +
  • For ansible collection: name it like 'ansible-collection-, ex. ansible-collection-containers-podman, etc.
  • +
+

NOTE: In case of python packages, srpms names should be prefixed with 'python-' and sub packages with 'python2-' or 'python3-'.

+

RDO Guidelines

+

Systemd packaging

+
    +
  • All services must be configured to allow automated restart
  • +
+
Restart=[on-failure|always]
+
+
    +
  • If a service depends on other for proper start, you can use the After= and +optionally Requires= parameters in unit configuration file. An example of +dependencies for neutron-openvswitch-agent service:
  • +
+
After=syslog.target network.target network.service openvswitch.service
+Requires=openvswitch.service
+
+
    +
  • The systemd package provides a set of rpm macros to handle systemd operations +on %post, %preun and %postun (more details here).
  • +
+

python packaging guidelines

+
    +
  • Remove requirements files used by pip to download dependencies from the network. +That may hide missing dependencies or integration issues (e.g. a dependency package only available in an incompatible version)
  • +
+
  rm -rf {,tests-}requirements.txt
+
+
    +
  • Use versioned python macros everywhere.
  • +
+

Packages requirements

+
    +
  • +

    Check your package dependencies with rdopkg reqcheck.

    +
  • +
  • +

    Versions for build requirements are not needed as the latest available version +will be always installed at build time by the packaging tools.

    +
  • +
  • +

    Actual requirements for default or common configurations of services must be +added as explicit requires.

    +
  • +
  • +

    Optional requirements for specific configurations must not be added as explicit +requires.

    +
  • +
  • +

    When versioning of explicit requires is needed be aware that epoch is used in +some RDO packages. In those cases remember to add the epoch in the required +version as in:

    +
  • +
+
Requires:         python-oslo-config >= 2:2.6.0
+
+

Configuration files

+
    +
  • Use oslo-config-generator to generate configuration files.
  • +
+
oslo-config-generator --config-file=config-generator/keystone.conf
+
+
    +
  • Configuration files must be in /etc and not /usr/etc.
  • +
+

Tests packaging

+

OpenStack projects provide different tests including unit tests and functional +tests, typically using the tempest framework.

+
    +
  • +

    Core packages shouldn't include tests as are not required in runtime.

    +
  • +
  • +

    Unit tests should be included in a <package name>-tests-unit package that +should depend on the test requirements.

    +
  • +
  • +

    Tempest tests should be included in a <package name>-tests-tempest package +which should depend on the dependencies to run the provided tests. Note that +some projects include tempest tests in the main project git repository (so tempest +package would be a subpackage in the same spec file) while others use a separate +git repository (so a specific distgit and spec will be needed).

    +
  • +
  • +

    <package name>-tests: includes all tests, and should be a virtual package +requiring <package name>-tests-tempest and <package name>-tests-unit.

    +
  • +
+

Other considerations

+
    +
  • To enforce consistency accross OpenStack services packages, use the following snippet to set upstream project name.
  • +
+
%global service keystone
+
+

RDO project provides different examples specs in +openstack-example-spec +for the different package types (OpenStack service, library, client, dashboard +plugin, etc...). This examples can be used as templates for new packages being +added to RDO repositories.

+

Patches

+

RDO is and intends to remain a vanilla distribution of OpenStack. +Our default policy is to refuse downstream patches, but RDO Packaging Group may grant +exceptions on per-case basis

+
    +
  • +

    Feature patches: must be submitted upstream

    +
  • +
  • +

    Security patches: requires RDO Security team clearance.

    +
  • +
  • +

    FTBFS patches: requires peer review, and must be submitted upstream when possible.

    +
  • +
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/release/index.html b/contribute/release/index.html new file mode 100644 index 0000000..13cee14 --- /dev/null +++ b/contribute/release/index.html @@ -0,0 +1,1231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Releasing - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Releasing

+ +

Step by step RDO release guide

+

Here you can find detailed information about what are the steps we are doing one by one (with explanation) to create new RDO release. This documentation is basen on our Jira board.

+

Getting ready for new OpenStack release

+

This document describes how RDO builds and publishes new packages both in RDO CloudSIG and RDO Trunk repos around new release.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/requirements/index.html b/contribute/requirements/index.html new file mode 100644 index 0000000..78b31e7 --- /dev/null +++ b/contribute/requirements/index.html @@ -0,0 +1,1487 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + General purpose requirements - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Requirements management in RDO

+

Introduction

+

OpenStack services usually need some pieces of software which are not developed as +part of the project. They are are general purpose libraries (typically python +modules) or services used in some way to run or build OpenStack packages as databases, messaging brokers, etc...

+

OpenStack requirements project +defines the policies and processes to manage requirements in upstream projects from +a global perspective.

+

Managing OpenStack requirements in RDO

+

RDO provides all requirements for packaged services in RPM format from their own repos, +so that no software should be installed from external repositories. This packages can +be provided by:

+
    +
  • +

    CentOS base repositories, which is the preferred source of packages whenever possible:

    + +
  • +
  • +

    Other CentOS SIG repositories (Virtualization, +Storage, NFV, etc...). When a required package is being maintained by other CentOS SIG, it +will be reused for RDO repos.

    +
  • +
  • RDO CloudSIG repositories. When a package is not available from previous repos, it will +be provided in RDO repositores. Note that it's required that these packages exist previously +in Fedora so that they can be rebuilt with minimal changes (if any).
  • +
+

If you have questions or special requests, don't hesitate in contacting RDO using our +mailing lists or #rdo channel on OFTC.

+

Adding a new requirement to RDO

+

When a new requirement is needed for an OpenStack project included in RDO, package maintainers +must follow this workflow:

+

RDO dependencies

+

Note that, typically new requirements are added only for the release of OpenStack under +development, not for stable releases, although they may be accepted in previous releases +if it's properly justified. +Also, as we're currently maintaining releases on CentOS Linux 7, CentOS Stream 8 & 9, there +are particularities in adding new requirements for each of them.

+
    +
  1. +

    If the project follows global-requirements processes, make sure that the requirement has been +added to global-requirements.txt and upper-constraints.txt files as described in the upstream +documentation +

    +
  2. +
  3. +

    Check if the new requirement is present in CentOS base channels. The easiest way to do this +is using 'repoquery' command from a system running RPM based OS(CentOS/RHEL/Fedora):

    +
    # For CentOS Stream 9:
    +repoquery --repofrompath=tmp,http://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os \
    +--repofrompath=tmp2,http://mirror.stream.centos.org/9-stream/AppStream/x86_64/os \
    +--repofrompath=tmp3,http://mirror.stream.centos.org/9-stream/CRB/x86_64/os \
    +--repofrompath=tmp4,http://mirror.stream.centos.org/9-stream/HighAvailability/x86_64/os \
    +--disablerepo=* --enablerepo=tmp* "*<dependency>"
    +
    +# For CentOS Stream 8:
    +repoquery --repofrompath=tmp,http://mirror.centos.org/centos/8-stream/BaseOS/x86_64/os \
    +--repofrompath=tmp2,http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os \
    +--repofrompath=tmp3,http://mirror.centos.org/centos/8-stream/PowerTools/x86_64/os \
    +--repofrompath=tmp4,http://mirror.centos.org/centos/8-stream/HighAvailability/x86_64/os \
    +--disablerepo=* --enablerepo=tmp* "*<dependency>"
    +
    +

    If it's present, the desired package is already available to RDO users. +

    +
  4. +
  5. +

    If the package is not in CentOS base repos, you can check if it has been already built by +the CloudSIG using rdopkg:

    +
    rdopkg findpkg <package name>
    +
    +

    as, for example:

    +
    $ rdopkg findpkg python-eventlet
    +name: python-eventlet
    +project: python-eventlet
    +conf: fedora-dependency
    +upstream: https://src.fedoraproject.org/rpms/python-eventlet
    +patches: None
    +distgit: http://review.rdoproject.org/r/deps/python-eventlet.git
    +buildsys-tags:
    +  cloud7-openstack-ocata-release: python-eventlet-0.18.4-2.el7
    +  cloud7-openstack-ocata-testing: python-eventlet-0.18.4-2.el7
    +  cloud7-openstack-pike-release: python-eventlet-0.20.1-2.el7
    +  cloud7-openstack-pike-testing: python-eventlet-0.20.1-2.el7
    +  cloud7-openstack-queens-release: python-eventlet-0.20.1-6.el7
    +  cloud7-openstack-queens-testing: python-eventlet-0.20.1-6.el7
    +  cloud7-openstack-rocky-release: python-eventlet-0.20.1-6.el7
    +  cloud7-openstack-rocky-testing: python-eventlet-0.20.1-6.el7
    +  cloud7-openstack-stein-release: python-eventlet-0.24.1-3.el7
    +  cloud7-openstack-stein-testing: python-eventlet-0.24.1-3.el7
    +  cloud7-openstack-train-release: python-eventlet-0.25.1-1.el7
    +  cloud7-openstack-train-testing: python-eventlet-0.25.1-1.el7
    +  cloud8-openstack-train-release: python-eventlet-0.25.2-3.1.el8
    +  cloud8-openstack-train-testing: python-eventlet-0.25.2-3.1.el8
    +  cloud8-openstack-ussuri-release: python-eventlet-0.25.2-3.el8
    +  cloud8-openstack-ussuri-testing: python-eventlet-0.25.2-3.el8
    +  cloud8-openstack-victoria-candidate: python-eventlet-0.25.2-3.el8
    +  cloud8-openstack-victoria-release: python-eventlet-0.25.2-3.1.el8
    +  cloud8-openstack-victoria-testing: python-eventlet-0.25.2-3.1.el8
    +  cloud8s-openstack-train-testing: python-eventlet-0.25.2-3.1.el8
    +  cloud8s-openstack-ussuri-release: python-eventlet-0.25.2-3.1.el8
    +  cloud8s-openstack-ussuri-testing: python-eventlet-0.25.2-3.1.el8
    +  cloud8s-openstack-victoria-release: python-eventlet-0.25.2-3.1.el8
    +  cloud8s-openstack-victoria-testing: python-eventlet-0.25.2-3.1.el8
    +  cloud8s-openstack-wallaby-release: python-eventlet-0.30.0-1.1.el8
    +  cloud8s-openstack-wallaby-testing: python-eventlet-0.30.0-1.1.el8
    +  cloud8s-openstack-xena-candidate: python-eventlet-0.31.1-1.el8
    +  cloud8s-openstack-xena-release: python-eventlet-0.31.1-1.el8
    +  cloud8s-openstack-xena-testing: python-eventlet-0.31.1-1.el8
    +  cloud8s-openstack-yoga-testing: python-eventlet-0.31.1-1.el8
    +  cloud9s-openstack-wallaby-testing: python-eventlet-0.30.2-1.el9s
    +  cloud9s-openstack-xena-testing: python-eventlet-0.31.1-1.el9s
    +  cloud9s-openstack-yoga-testing: python-eventlet-0.31.1-1.el9s
    +centos-distgit: https://git.centos.org/rpms/python-eventlet
    +master-distgit: http://review.rdoproject.org/r/deps/python-eventlet.git
    +review-origin: null
    +review-patches: null
    +tags:
    +  dependency: null
    +maintainers:
    +- amoralej@redhat.com
    +- jcapitao@redhat.com
    +- ykarel@redhat.com
    +
    +

    Note that the version of the package included in repositories is given by the +CBS tags applied to each package (shown under buildsys-tags section for each package). +Tags have a format cloud9s-openstack-<release>-<phase> where:

    +
      +
    • release: is the OpenStack release name, as Wallaby, Xena or Yoga.
    • +
    • phase:
    • +
    • candidate phase is assigned to packages to be rebuilt in + CBS but not pushed to any RDO repository.
    • +
    • el<centos_version>-build is assigned to packages that only required to build other + packages but are not a runtime requirement for any other package. (e.g centos_version + can be '9s' or '8')
    • +
    • testing phase means that the package is used in deployments using RDO Trunk + repo and published in a testing repo, but not official CloudSIG repository.
    • +
    • release phase means that is published in the official CloudSIG repository. + This phase is only available after a RDO version has been officially released + not for the one currently under development.
    • +
    +

    For example, the package included in cloud8s-openstack-xena-release will be published +in the CloudSIG repo for xena. The CBS tags flow will be: +- Runtime requirements: candidate -> testing -> release +- Build requirements: candidate -> el8-build or el9s-build

    +

    Note that, for the release currently under development (Yoga right now), testing and +el9s-build phase will be available. The package included in cloud9s-openstack-yoga-testing +will be the one used to deploy from RDO Trunk Master repositories and it will be +automatically pushed to cloud9s-openstack-yoga-release at RDO Yoga is officially +released and published.

    +

    If the package is found for the required CBS tag, it's already in RDO repositories +and no more actions are needed to add it to the repos. +

    +
  6. +
  7. +

    In case that the dependency is not in CentOS base or CloudSIG repo, you can check if it has been built +by other SIGs in CBS web interface. You can use wildcards in the packages +search expression. If you find the desired dependency, you can open a ticket in RDO +Jira board requesting +the inclusion of the package in RDO repos. RDO Core members will handle the request. +

    +
  8. +
  9. +

    If the new package is not in CBS, you must check if it's packaged in Fedora using the Koji Web +Interface. If the package exists, you need to open +a review to rdoinfo project in RDO gerrit instance.

    +

    For CentOS Stream 8 and 9, you need to add the new dependency to deps.yml file as in this example:

    +
    # in deps.yml
    +- project: python-ssh-python
    +  name: python-ssh-python
    +  conf: fedora-dependency
    +
    +

    For CentOS Stream 8 only, you also need to add buildsys-tag in buildsys-tags/cloud8s-openstack-yoga-candidate.yml

    +
    # in buildsys-tags/cloud8s-openstack-yoga-candidate.yml
    +- project: python-ssh-python
    +  buildsys-tags:
    +    cloud8s-openstack-yoga-candidate: python-ssh-python-0.9.0-1.el8
    +
    +

    Where: +- project and name must be the name of the main package (the same as in fedora). +- conf must be fedora-dependency. +- In buildsys-tags section a new line for the candidate tag in the OpenStack +release in development (cloud8s-openstack-yoga-candidate) with the required +NVR (name-version-release), which must be the same one found in Fedora +replacing fcXX part in release by el8. For example, for python-ssh-python +the build is python-ssh-python-0.9.0-1.fc36, so in buildsys-tags/cloud8s-openstack-yoga-candidate.yml, +cloud8s-openstack-yoga-candidate must point to python-ssh-python-0.9.0-1.fc36.

    +

    Once merged this review will be enough to rebuild the Fedora package in the CentOS Build System for CentOS Stream 8.

    +

    For CentOS Stream 9, a few more steps are required to be able to rebuild the patch in CentOS Build System. +After the review in rdoinfo repo is merged, some changes in config need to be done in the config which will be +automatically triggered. +You can check when the distgit for the new dependency is created by monitoring if it +appears in https://review.rdoproject.org/r/admin/repos/deps/.

    +

    Once the repo is available, you can propose a review to build the package. +We have a tool which does the work: setup_distgit.sh

    +
    $ git clone https://review.rdoproject.org/cgit/gating_scripts
    +$ cd gating_scripts
    +$ bash -x setup_distgit.sh google-benchmark google-benchmark-1.6.0-1.fc36 yoga 9s
    +$ cd workdir/<project_name>
    +$ git diff
    +
    +

    Basically, the script clones the new repo, downloads the Fedora build and dispatches SPEC +and sources files to the right place.

    +

    If you’re ok with the change, submit it. +Note: this last step is for CentOS Stream 9 only.

    +

    This review will rebuild the Fedora package in the CentOS Build System for CentOS Stream 9 +and make it available to be pushed to the next CBS phase. +

    +
  10. +
  11. +

    When the packages doesn't exist even in Fedora you need to add the package following the New package +process. Note that a Fedora +packager needs to participate in this process. While RDO core members may maintain the new package for +common requirements used by different projects, dependencies for specific project must be maintained in +Fedora by the project team. Once the package is included in Fedora repos you can +create a gerrit review as explained in step 5. +

    +
  12. +
  13. +

    Once the package is rebuilt in CBS (review in step 5 is merged) you can push +it to the next phase, this means testing (for runtime dependencies) or el9s-build (for build-time dependencies). +This is done by sending a new review to rdoinfo project +adding a new line under buildsys-tags to both buildsys-tags/cloud9s-openstack-yoga-testing.yml and +buildsys-tags/cloud8s-openstack-yoga-testing.yml file for the new tag as in +this example:

    +
    # in buildsys-tags/cloud8s-openstack-yoga-testing.yml
    +buildsys-tags:
    +  cloud8s-openstack-yoga-testing: python-stestr-3.2.0-3.el8
    +
    +# in buildsys-tags/cloud9s-openstack-yoga-testing.yml
    +buildsys-tags:
    +  cloud9s-openstack-yoga-testing: python-stestr-3.2.0-3.el9s
    +
    +

    Once this review is merged, the tag will be applied to this build and the package + will be added to the testing repo for Yoga (note that some delay, up to 30 minutes + is expected). +

    +
  14. +
  15. +

    After the package is available in the repos, you can add it to the list of Requires or BuildRequires in +your package spec file. Note that optional dependencies not used in default or common configurations should +not be added as Requires but installed only when needed.

    +
  16. +
+

Updating a requirement in RDO CloudSIG repositories

+

There are some rules to follow when a requirement update is needed by a OpenStack project. Following diagram summarizes the considerations to update +the dependencies in RDO.

+

CloudSIG dependencies

+

If the dependency is included in upstream OpenStack global requirements project, the required version should be equal (exceptions will be shown below) to +the version in upper-constraints file +for the appropiate OpenStack release (requirements project has stable/\ branches). +For the master branch, RDO provides a report to quickly check the state of dependencies compared to upper-constraints.

+

Packages provided in CentOS Stream OS repos

+
    +
  • For packages provided in CentOS Stream OS repos, the preferred option is to consume those packages from OS whenever possible, even if versions are below the ones in upper-constraints.txt file. +If OpenStack requires newer versions of those packages to work properly (for example, an OpenStack project requires a minimal version of the dep which is newer that the one in CentOS) +there are two options:
  • +
  • Request a package update in CentOS by opening a bug in RHEL product. +This bug will be evaluated following the RHEL process.
  • +
  • Add it to RDO repository following the process described in Adding a new requirement to RDO. Note that this may impact other packages using it in the Operating System so this option should be minimized.
  • +
+

Packages not provided in CentOS Stream OS repos

+
    +
  • The required dependencies not included in the CentOS OS are provided in the RDO repos. Before updating a dependency in RDO, the package must be updated +to the required version in Fedora. If it has not been updated first you can:
  • +
  • Contact Fedora package maintainer or search for open bug against component, example component:python-migrate, +if bug does not exist, open a bug for Fedora product requesting the update.
  • +
  • +

    Or you can directly propose to update fedora package by creating your own pull request, following +Fedora packaging guide and Fedora CI - Pull Requests. +Once the pull request merged, the package must be built by its maintainer. Building Fedora’s packages can be monitored on Koji.

    +
  • +
  • +

    Once the package is build in Fedora, you can update the requirement in RDO. For CentOS Stream 9, you need to rebuild the package first by sending + a review to the RDO Gerrit instance in the distgit project deps/<package name> in the branch c9s-<openstack version>-rdo. +RDO provides the script setup_distgit.sh to ease the preparation of the +dependency update review by importint content from Fedora. i.e. if you need to update python module foo to version 1.0.0 in OpenStack Zed and +the package is ready in fedora as python-foo-1.0.0-1.fc37 you should execute:

    +
    $ git clone https://review.rdoproject.org/cgit/gating_scripts
    +$ cd gating_scripts
    +$ bash -x setup_distgit.sh python-foo python-foo-1.0.0-1.fc37 zed 9s
    +$ cd workdir/python-foo
    +$ git diff
    +
    +

    Basically, the script clones the new repo, downloads the Fedora build and dispatches SPEC +and sources files to the right place.

    +

    If you’re ok with the change, commit it and send the review. Note that, in some cases, changes are required to build fedora packages for CentOS. +It is usually a good idea to test new package with mock or rpm-build.

    +
  • +
  • +

    Once the patch in deps/<dependency> is merged, the package is built and tagged in CBS but will not be available +in the RDO repositories. The next step is to include the package in RDO Testing repo for the appropiate OpenStack release. This is done by sending +a patch to the rdoinfo project, adding it to the file buildsys-tags/cloud9s-openstack-<openstack release>-testing like this example.

    +
  • +
  • +

    Once the package exist in testing tag it will be available in the RDO Trunk repositories to be used in jobs or update in rpm spec. For stable releases (non master) +an automatic task will also propose review to rdoinfo to upddate the package the corresponding release tag in the same OpenStack release in rdoinfo repo. +Once that patch is merged, the update will also appear in the CloudSIG official CentOS mirror.

    +
  • +
+

Contact us

+

If you have questions or special requests about requirements, don't hesitate to contact RDO community members using our +mailing lists or #rdo channel on OFTC.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/contribute/retire-packages/index.html b/contribute/retire-packages/index.html new file mode 100644 index 0000000..5b70845 --- /dev/null +++ b/contribute/retire-packages/index.html @@ -0,0 +1,1160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Retiring a package - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Retiring a package from RDO

+

What does retiring a package means

+
    +
  • The package will not be build and published to RDO Trunk repo
  • +
  • The package will not be build in CBS and published to next CloudSIG repo
  • +
+

NOTE: The package can be retired only from the current development release.

+

How to remove an OpenStack package from RDO Trunk

+

Package for a project can exist across different releases. So retiring it in RDO needs to go via stages.

+

To remove a package, following steps are required:-

+

Stage 1:- Project Source is retired/deleted upstream, but it's package still need to be maintained because it's required by other projects

+
    +
  • +

    Send a review to rdoinfo like Example review to pin(add source-branch: <good commit>) the project against the tag or commit, so package get's build from pinned commit rather than latest commit(deleted source code).

    +

    ```

    +

    Need to add source-branch like below

    +
      +
    • project: oslo-sphinx + tags: + train-uc: + source-branch: f92583cfc34292ec1441368f984c9692346946c4 + ```
    • +
    +
  • +
  • +

    Send a review to config project like Example review to run DLRN-pinned jobs(legacy-DLRN-rpmbuild-pinned, legacy-DLRN-rpmbuild-fedora-pinned) so package get's build from pinned commit rather than from latest, This is required so that spec changes can be done like https://review.rdoproject.org/r/#/c/20383/.

    +
  • +
+

Stage 2:- Package is no longer needed by other projects:-

+ +

Once the change is merged in rdoinfo, package will no longer exist in RDO trunk repo, but it will still be built for previous releases(for which +tag is defined in rdoinfo):- +RDO Trunk repos.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deliverables/general_concept_comparison/index.html b/deliverables/general_concept_comparison/index.html new file mode 100644 index 0000000..f36af6b --- /dev/null +++ b/deliverables/general_concept_comparison/index.html @@ -0,0 +1,1460 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Comparison of RDO's deliverables - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Overview and comparison of RDO's deliverables

+

The RDO project has turning around two main concepts of deliverables: packages and repositories. Differences between them and their purpose may be confusing, so this documents is created to summarize the knowledge and emphasise divergences to help fully understand them.

+

Packages

+

Packages in RDO are the most atomic unit in RDO and there are basically two kinds of them:

+
    +
  • OpenStack RDO packages (i.e. openstack-nova, openstack-neutron, python-osprofiler)
  • +
  • dependencies (i.e. python-hatchling, python-eventlet)
  • +
+

Both types of package have distgits (repositories containing spec files) in common, as necessary part of package building process.

+

The table below shows main characteristic of each kind of package.

+

  + 

+ + + + + + + + + + + + + + + + + + + + + + + + + +
OpenStack RDO packagesdependencies
1.Code comes from upstream OpenStack projectCode comes from any upstream project
2.Created in RDOComes from Fedora
3.Build by DLRN (Trunks) or CentOS CBS (CloudSIG)Build by CentOS Community Build Service
+

The first row of the table compares the origin of each kind of package.

+

The second row describes how packages land in RDO projects. In other words, each dependency's distgit has to be present in Fedora first, while distgits for OpenStack packages are created by package maintainers, as in this example review.

+

The third row compares how packages are built.

+

These two kinds of packages are what composes the RDO repositories, in addition RDO project also takes part in maintaining and developing Fedora OpenStackSIG packages. The purpose of this special interest group is to maintain and ship latest packages such as: OpenStack clients, libraries and dependencies in Fedora.

+

Repositories

+

In RDO we deliver two types of repositories:

+
    +
  • RDO Trunks
  • +
  • RDO CloudSIGs
  • +
+

Each of them is managed and delivered in different way. Both of them are composed from OpenStack packages and dependencies, but they are shipped differently.

+

  + 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RDO TrunksRDO CloudSIGs
1.build by DLRNbuild by CentOS Community Build Service
2.new package with every new commitnew package with every new tag released upstream
3.Delivered very close in time after new commitDelivered in days
4.Fetch source code through involved repoFetch tarball for point release
5.Continuous delivery of master branchRepo released after OpenStack GA
6.Unsigned packagesSigned packages
7.Delivered in trunk.rdoproject.org serverDelivered in official Centos mirrors in CloudSIG
+

Building

+

The first row shows that each repository is build by different system. All trunk repos are created and managed by DLRN, while CloudSIGs is managed by CBS.

+

Handling new packages

+

The second and third row compare ways of handling new packages. In trunks, any time a new commit is merged in upstream project, the package building process is triggered and new repositories containing this package are published, so the time of publishing new deliverable is very short. For RDO CloudSIGs the process in slightly longer, because publishing new repo is happening when new tag is released in upstream, as in example review.

+

Origin of sources

+

Package process building is fetching project source code directly from repository, while RDO CloudSIGs are basing on tarballs.

+

Frequency of releasing

+

Trunk repositories are constantly following master branch for all projects, so new packages and repositories are delivered in continuous way. RDO CloudSIGs are released only after OpenStack GA.

+

Security

+

Trunks contains only unsigned packages on the contrary to RDO CloudSIGs.

+

Distribution

+

Trunks are distributed by trunk servers. RDO CloudSIGs are delivered in official Centos mirrors.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deliverables/how-to-install-rdo-repo/index.html b/deliverables/how-to-install-rdo-repo/index.html new file mode 100644 index 0000000..a47e01b --- /dev/null +++ b/deliverables/how-to-install-rdo-repo/index.html @@ -0,0 +1,1149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + How to install RDO repositories - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

How to install RDO repositories

+ +

TBD

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deliverables/index.html b/deliverables/index.html new file mode 100644 index 0000000..c43c2c9 --- /dev/null +++ b/deliverables/index.html @@ -0,0 +1,1144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + What we deliver? - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

What we deliver?

+

This section contains information what and how RDO is releasing. Also you can find here description and differences of deliverables documented and find out, how the process of releasing looks like.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deliverables/release-cadence/index.html b/deliverables/release-cadence/index.html new file mode 100644 index 0000000..dac4412 --- /dev/null +++ b/deliverables/release-cadence/index.html @@ -0,0 +1,1429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Release cadence - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + +

Release cadence

+

RDO packaging release cadence

+

This page describes the release cadence of RDO packages in relation to different community distributions, giving an approximate idea of community support status of any given OpenStack release.

+

CentOS Versions

+

Due to the slower release cadence of RHEL and therefore CentOS, only the most recent release plus the previous one are supported, in keeping up with upstream policy. Older versions of the operating system such as CentOS 7 do not receive later releases.

+

When there is a new major CentOS release, the following OpenStack version is packaged for both for the new and the previous version of CentOS. The purpose of this policy is to ease the trasition between them.

+

Maintained RDO versions in CloudSIG repos

+

RDO CloudSIG repositories are based on tag releases provided by OpenStack project. According to the definition of maintenance phases of OpenStack, RDO will not update CloudSIG repos after a release is transitioned to Extended Maintenance status.

+

Current maintained CloudSIG releases are:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CentOS Stream 9Caracalsupported
CentOS Stream 9Bobcatsupported
CentOS Stream 9Antelopesupported
CentOS Stream 9Zedunmaintained
+

Maintained RDO versions in RDO Trunk repos

+

In order to provide patches merged in OpenStack releases in Extended Maintenance state, RDO mantains RDO Trunk repositories following stable branches or pinned releases until they are EOL.

+

Currently, RDO maintains following RDO Trunk repositories:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CentOS Stream 9Bobcatsupported
CentOS Stream 9Antelopesupported
CentOS Stream 9Zedunmaintained
CentOS Stream 9Yogaunmaintained
CentOS Stream 9Xenaunmaintained
CentOS Stream 9Wallabyunmaintained
+

RHEL compatibility

+

Although it is expected that RDO works fine in Red Hat Enterprise Linux (RHEL) OS, it is currently not tested on it. Note that CentOS Stream is a continuosly delivered distribution that tracks just ahead of RHEL and differences between both distributions at a certain point are expected.

+ +

Fedora

+

The RDO team, in coordination with the Fedora OpenStack SIG maintains the OpenStack Clients in Fedora repositories.

+ +

References

+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deliverables/repos/index.html b/deliverables/repos/index.html new file mode 100644 index 0000000..05acf01 --- /dev/null +++ b/deliverables/repos/index.html @@ -0,0 +1,1342 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Overview of available RDO repos - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + +

Overview of available RDO repos

+

There are a number of different repos that the RDO project works out of. +This is an overview of each of them.

+

NOTE: Overview and comparison of RDO's deliverables can be found in this article.

+

RDO CloudSIG repositories

+

Provide a set of stable OpenStack packages through CentOS CloudSIG repos based on CBS, CentOS Community Build System:

+
    +
  • The RDO CloudSIG repos are only published after GA of a upstream release (only stable branches are used, not master).
  • +
  • New packages are created only when a new point release is published (release tag created) on upstream stable repositories.
  • +
  • In addition to the vanilla upstream code, some patches may be applied during packaging:
  • +
  • Fixes for security issues or critical bugs not backported upstream. Note that an upstream-first policy is applied so these patches will be applied only after merged in upstream master.
  • +
  • Patches required for the packaging process.
  • +
+

For each OpenStack release RDO provides two repos:

+

CloudSIG GA repo

+

The GA repository is the one you should be using for your production environment. It contains tested, digitally signed packages.

+

To enable this repository on a CentOS system, run the following command:

+
For CentOS Stream 9:
+$ sudo dnf install centos-release-openstack-<release>
+
+

Where <release> is the name of the OpenStack release you want to install. The RDO community supports the same OpenStack releases supported by upstream.

+

On a non-CentOS system (e.g. RHEL), you can run the following command to setup the RDO GA repositories:

+
For CentOS Stream 9:
+$ sudo dnf install https://www.rdoproject.org/repos/rdo-release.el9.rpm
+
+

This will configure the repositories for the most recent version of RDO. RPMs for previous releases are accessible from this location.

+

CloudSIG Testing repo

+

The testing repository contains packages that have not gone through our complete test suite. These packages can be useful to test newer versions of the code, or when you need to quickly deliver a hotfix to your production environment. Please keep in mind that packages from the testing repository are not digitally signed.

+

If you enabled the RDO repositories using the centos-release-openstack-* RPM, run the following command to enable the testing repository:

+
$ sudo yum-config-manager --enable centos-openstack-<release>-test
+
+

If you used the rdo-release RPM, run the following command:

+
$ sudo yum-config-manager --enable openstack-<release>-testing
+
+

Comparison of CloudSIG GA repo and testing repo

+

+

RDO Trunk repositories

+

RDO Trunk repositories are built using the most recent commit from each of the OpenStack projects. They are used in different ways:

+
    +
  • By several OpenStack CI jobs, to test packages built from the current under-development branch.
  • +
  • Internally by the RDO community, to ensure that our packaging pipeline is always up to date.
  • +
  • They can also be used to deliver hotfixes for stable releases, as soon as the relevant patch has been merged in the upstream repos.
  • +
+

The RDO Trunk packages are not digitally signed, and have gone through some minimal CI. You can enable the CI-passed RDO Trunk repo using the following command:

+
$ sudo yum-config-manager --enable rdo-trunk-newton-tested
+
+

If you need a package using the latest commit, even before it passes CI (be aware this is bleeding edge!), go to the RDO Trunk web.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deliverables/trunk-repos/index.html b/deliverables/trunk-repos/index.html new file mode 100644 index 0000000..c53da43 --- /dev/null +++ b/deliverables/trunk-repos/index.html @@ -0,0 +1,1262 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + RDO Trunk repos - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

RDO Trunk repos

+

RDO Trunk repositories are built using the most recent commit(or from the pin to a commit/tag/branch if source-branch is set for a release in rdoinfo) from each of the OpenStack projects defined for a release. We host the RDO Trunk repositories at https://trunk.rdoproject.org/. On that server, you will find several repositories:

+ +

These repos contain packages build for each OpenStack project defined for a particular release in rdoinfo. This mapping of repo and release is as follows:-

+
    +
  • CentOS Stream 9 master, using versions from upper-constraints with current release rdoinfo tag i.e zed-uc
  • +
  • CentOS Stream 9 stable releases for the currently supported versions with stable release rdoinfo tag other than current release zed-uc
  • +
+

The upper-constraints based repositories

+

The gate jobs for each OpenStack project use a common set of dependencies, defined by the requirements repository. One of the files on that repository is upper-constraints.txt, which contains the supported version for each library on each OpenStack release.

+

Why is this file important? It defines an upper cap for every gate job, meaning those are the versions all OpenStack projects are being tested against. For example, if the specified version for python-novaclient in the file is X.Y.Z, we can safely assume that this version will work fine for all projects, but we cannot say the same for any commit beyond that point.

+

This is also important when packaging, because we want our generated repositories to be usable by upstream CIs, so we need to provide a set of packages that matches the versions available in the upper-constraints.txt file. For this reason RDO builds all libraries and clients from the latest versions in upper-constraints.txt, and every other project is built from the master or stable branch.

+

Hashed repos and special repos

+

When each new upstream commit is built, a repository is created with the new package and the latest versions from every other package built by RDO Trunk. This new repository is located in a hashed URL. This URL is built using:

+ +

With that info we can figure out the repo URL:

+

https://trunk.rdoproject.org/centos9-master/component/network/58/48/5848c0dd1c951e916c0b769f711d8aafa6aa72b1_21f87ec3/

+

Note the pattern:

+

https://trunk.rdoproject.org/centos<centos version>-<release>/component/<component name>/<1:2 code hash>/<3:4 code hash>/<long code hash>_<short distgit hash>/

+

Besides hashed repositories, we have some special directories, created as symlinks to hashed repos:

+
    +
  • current points to the repository with contains the last successfully built package from every project.
  • +
  • consistent points to the latest repository where none of the packages have current build failures.
  • +
  • current-passed-ci points to the last consistent repository that passed all the promotion CI tests.
  • +
+

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deploy/index.html b/deploy/index.html new file mode 100644 index 0000000..2267551 --- /dev/null +++ b/deploy/index.html @@ -0,0 +1,1214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Install - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

RDO OpenStack deployment

+

There have always been multiple ways of deploying OpenStack. In RDO we are using some of them. Before starting your RDO deployment, make sure you understand the different repo flavors and releases that RDO is providing by reading our deliverables documentation.

+

Packstack

+

For an initial test deployment, follow the Packstack instructions. While using Packstack is sufficient as a proof of concept, there are other ways that you can +use to deploy OpenStack with RDO.

+

Puppet OpenStack Integration

+

Puppet OpenStack modules provide puppet-based per-service modules intended to provide automation to OpenStack cloud deployments based on Puppet automation engine. More about can be found in official documentation. RDO provides rpms for puppet modules and continuously test and validate its packages and repos using puppet-openstack-integration CI repository.

+

OpenStack Ansible

+

This project has partial support for RDO as provider for binary installations in CentOS, hovewer it's not tested in our CI. Main documentation can be find here, there is also available a deployment guide.

+

RDO on OKD - experimental

+

Deployment of OpenStack based on OKD, The Community Distribution of Kubernetes, where OpenStack management is handled through a new podified control plane (a set of tools for deploying and managing an OpenStack control plane as Kubernetes-native pods). You can read documentation and instructions about RDO on OKD Proof of Concept, which is a part of CentOS CloudSIG. Also you can watch RDO's presentation which is explaining that concept in details.

+

Tools used in RDO

+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deploy/packstack/index.html b/deploy/packstack/index.html new file mode 100644 index 0000000..d0fc481 --- /dev/null +++ b/deploy/packstack/index.html @@ -0,0 +1,1206 @@ + + + + + + + + + + + + + + + + + + + + + + + + Packstack - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

TBD: update this article

+

Packstack: Create a proof of concept cloud

+

Packstack is an OpenStack deployment tool intended to install Proof of Concept small environments in a quick and easy way using the RDO distribution on a CentOS Stream hosts. +Production features such as High Availability, OpenStack upgrades or other day-2 operations are out of the scope of Packstack. For these cases, you can rely on other recommended tools +described in Deploy RDO section.

+

This document shows how to spin up a proof of concept cloud on one node using the Packstack installation utility. You will be able to add more nodes to your OpenStack cloud later, if you choose.

+

These instructions apply to the following Release and Operating Systems - Victoria, Wallaby, Xena and Yoga on CentOS Stream 8, and Yoga, Zed and Antelope on CentOS Stream 9.

+

WARNING

+

Read this document in full, then choose your install path:

+

Don't just start typing commands at Summary for the impatient and proceed downwards through the page.

+

Summary for the impatient

+

If you are using non-English locale make sure your /etc/environment is populated:

+
LANG=en_US.utf-8
+LC_ALL=en_US.utf-8
+
+

If your system meets all the prerequisites mentioned below, proceed with running the following commands.

+
    +
  • On CentOS Stream 8:
  • +
+

$ sudo dnf update -y + $ sudo dnf config-manager --enable powertools + $ sudo dnf install -y centos-release-openstack-yoga # Replace yoga by the desired release name + $ sudo dnf update -y + $ sudo dnf install -y openstack-packstack + $ sudo packstack --allinone

+
    +
  • On CentOS Stream 9:
  • +
+

$ sudo dnf update -y + $ sudo dnf config-manager --enable crb + $ sudo dnf install -y centos-release-openstack-bobcat + $ sudo setenforce 0 + $ sudo dnf update -y + $ sudo dnf install -y openstack-packstack + $ sudo packstack --allinone

+

Note for RHEL: Although it is expected that RDO works fine on RHEL, it is currently not tested in RHEL OS.

+
    +
  • On RHEL 8:
  • +
+

$ sudo dnf install -y https://www.rdoproject.org/repos/rdo-release.el8.rpm + $ sudo dnf update -y + $ subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-rpms + $ sudo dnf install -y openstack-packstack + $ sudo packstack --allinone

+

Step 0: Prerequisites

+

Software

+

CentOS Stream 8 is the minimum recommended version, or the equivalent version of one of the RHEL-based Linux distributions such as Red Hat Enterprise Linux, Scientific Linux, and so on. Packages are provided for x86_64, aarch64 and ppc64le architectures although most of the testing is done on x86_64.

+

Hardware

+

Machine with at least 16GB RAM, processors with hardware virtualization extensions, and at least one network adapter.

+

Hostname

+

Name the host with a fully qualified domain name rather than a short-form name to avoid DNS issues with Packstack.

+

Network

+

If you plan on having external network access to the server and instances, this is a good moment to properly configure your network settings. A static IP address to your network card, and disabling NetworkManager are good ideas.

+

On CentOS Stream 8/RHEL 8:

+

network-scripts is deprecated and not installed by default, so needs to be installed explicitly.

+
$ sudo dnf install network-scripts -y
+
+

Disable firewalld and NetworkManager

+
$ sudo systemctl disable firewalld
+$ sudo systemctl stop firewalld
+$ sudo systemctl disable NetworkManager
+$ sudo systemctl stop NetworkManager
+$ sudo systemctl enable network
+$ sudo systemctl start network
+
+

If you are planning on something fancier, read the document on advanced networking before proceeding.

+

Step 1: Software repositories

+

On CentOS Stream 8, first you need to enable the powertools repository. +Then, the Extras repository provides the RPM that enables the OpenStack repository. Extras is enabled by default on CentOS 8, so you can simply install the RPM to set up the OpenStack repository:

+
$ sudo dnf config-manager --enable powertools
+$ sudo dnf install -y centos-release-openstack-yoga
+
+

On CentOS Stream 9, first you need to enable the crb. +Then, the extras-common repository provides the RPM that enables the OpenStack repository. It is enabled by default on CentOS Stream 9, so you can simply install the RPM to set up the OpenStack repository:

+
$ sudo dnf config-manager --enable crb
+$ sudo dnf install -y centos-release-openstack-bobcat
+
+

On RHEL 8, install the RDO repository RPM to setup the Openstack repository, then you must enable the codeready-builder option in subscription-manager:

+
$ sudo dnf install -y https://www.rdoproject.org/repos/rdo-release.el8.rpm
+$ subscription-manager repo --enable codeready-builder-for-rhel-8-x86_64-rpms
+
+

Update your current packages:

+
$ sudo dnf update -y
+
+

Looking for an older version? See http://rdoproject.org/repos/ for the full listing.

+

Step 2: Install Packstack Installer

+
$ sudo dnf install -y openstack-packstack
+
+

Step 3: Disable selinux enforcing mode

+

There are known issues with selinux policies and rabbitmq in CentOS Stream 9. Disable selinux enforcing mode:

+
$ sudo setenforce 0
+
+

Step 4: Run Packstack to install OpenStack

+

Packstack takes the work out of manually setting up OpenStack. It provides a set of options to specify the desired services and configurations for each installation. You can list all the available parameters using:

+
$ packstack --help
+
+

For a simple, single node OpenStack deployment with default options, run the following command:

+
$ sudo packstack --allinone
+
+

The Packstack command line interface accepts an answers file as a mechanism to specify the parameters. The base answers file can be created with:

+
$ packstack --gen-answer-file
+
+

Then can be used by using --answer-file option:

+
$ sudo packstack --answer-file=<path to the answers file>
+
+

If you have run Packstack previously, there will be a file in your home directory named something like packstack-answers-20130722-153728.txt You will probably want to use that file again, using the --answer-file option, so that any passwords you have already set (for example, mysql) will be reused.

+

The installer will ask you to enter the root password for each host node you are installing on the network, to enable remote configuration of the host so it can remotely configure each node using Puppet.

+

Once the process is complete, you can log in to the OpenStack web interface Horizon by going to http://$YOURIP/dashboard. The user name is admin. The password can be found in the file keystonerc_admin in the /root directory of the control node.

+

Next steps

+

Now that your single node OpenStack instance is up and running, you can read on about configuring a floating IP range, configuring RDO to work with your existing network, or about expanding your installation by adding a compute node.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/deploy/tripleo/index.html b/deploy/tripleo/index.html new file mode 100644 index 0000000..dad35bc --- /dev/null +++ b/deploy/tripleo/index.html @@ -0,0 +1,1142 @@ + + + + + + + + + + + + + + + + + + + + + + + + TripleO - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

TripleO

+

TripleO is a set of tools for the deployment and management of OpenStack which utilizes the RDO repositories. The TripleO project was retired after the Zed +release of OpenStack.

+

The name TripleO refers to three related things:

+
    +
  • A design pattern, where an underlying OpenStack instance is used to deploy and then to manage another, usually more complex, OpenStack instance.
  • +
  • A set of configuration files and scripts which contain OS image building rules and service configuration rules
  • +
  • The upstream program within the OpenStack project which develops the various scripts and utilities which are combined to deliver the complete software solution.
  • +
+

The design pattern utilizes a single-purpose deployment OpenStack which deploys and manages a more sophisticated, general-purpose OpenStack instance which is what +gives TripleO its name. TripleO is short for OpenStack On OpenStack.

+

Upstream TripleO documentation:

+ +

Note: Limit your environment-specific content in the menu on the left-hand side of the documentation page.

+

RDO/TripleO documentation:

+ +

TripleO YouTube channel:

+ +

Get in touch

+
    +
  • IRC: #tripleo and #rdo channels on OFTC.
  • +
  • Mailing list: openstack-discuss, using [TripleO] tag in the subject of the email.
  • +
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/factory/dlrn/index.html b/factory/dlrn/index.html new file mode 100644 index 0000000..f2a502c --- /dev/null +++ b/factory/dlrn/index.html @@ -0,0 +1,1306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + DLRN - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

DLRN: What it is, what we use it for

+

DLRN (can be read as "Delorean") is an application that helps us do continuous packaging of RDO. It is used to build packages using the latest commit from each of the OpenStack project repositories.

+

DLRN can be run as a standalone application to create a single package, or periodically (using a cron job) to rebuild all packages listed for a specific release.

+

High-level DLRN flow

+

The basic DLRN flow is:

+
    +
  • For each package listed in the RDO metadata file:
      +
    • Fetch the latest upstream commit from the OpenStack Git repositories
    • +
    • Fetch the latest commit from the distgit repositories
    • +
    • Build an RPM package using the source and distgit commits
    • +
    • Create a YUM repository with that package, and the latest build package for the other packages
    • +
    • If a package build fails, open a review in the RDO Gerrit to track and fix the issue.
    • +
    +
  • +
+

The result of each DLRN run is an RDO Trunk repository, containing the latest commit from each supported OpenStack project, ready to be consumed.

+

Tips and tricks

+

Multiple branch support

+

DLRN can build packages using different upstream branches, not only master. For example, we have DLRN workers building packages for the Newton and Mitaka releases. That allows us to test each commit landing to stable/newton and stable/mitaka before it is part of a release. We can select which releases we want to build a package for using tags in the RDO metadata file, for example:

+
- project: watcher
+  conf: rpmfactory-core
+  tags:
+    ocata-uc:
+    ocata:
+    newton:
+
+

This project (openstack-watcher) is built for Ocata (master) and Newton.

+

Setting up a DLRN instance

+

You can follow the instructions from the README file to set up a test instance. The Puppet module we use to build the RDO instances is also available if you want to take a look at how to configure multiple instances on a single machine.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/factory/index.html b/factory/index.html new file mode 100644 index 0000000..47fdab8 --- /dev/null +++ b/factory/index.html @@ -0,0 +1,1144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Factory - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Factory

+

This section presents documents about how the factory behind building packages and repositories looks like. Here you will find sections about infrastructure, promotions and all tooling specific to this process.

+ + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/factory/pipeline/index.html b/factory/pipeline/index.html new file mode 100644 index 0000000..a41ddd0 --- /dev/null +++ b/factory/pipeline/index.html @@ -0,0 +1,1272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Delivery pipeline - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

The delivery pipeline

+

This is the 10,000 foot view of the RDO delivery pipeline. For more +detail, see the various more in-depth documents:

+

Trunk chasing

+

We use DLRN to track upstream changes and build continuously OpenStack as a RPM distribution. +Then our Zuul spfCI hosted on SoftwareFactory runs multiple jobs +on DLRN snapshots. We use the WeIRDO framework to run the same jobs as upstream CI on our packages. +This allows us to detect early integration issues and get either our packaging or upstream projects fixed.

+

Branching

+

We start branching RDO stable release around milestone 3, and have stable builds getting bootstrapped. This includes:

+
    +
  • registering packages in CBS, which is scripted using the rdoinfo database.
  • +
  • syncing requirements in packages.
  • +
  • branching distgit repositories.
  • +
  • building upstream releases in CBS. This part used to be semi-automated using rdopkg tool, and currently being consolidated into a cron job creating reviews.
  • +
  • tag builds in -testing repositories, some automation is in preparation.
  • +
+

Trunk chasing continues, but we pay attention in keeping promotions happening more frequently to avoid a gap between tested upstream commits and releases.

+

GA publication

+

Since OpenStack does releases slightly ahead of time, we have most of GA releases built in CBS, but some of them comes late. +We also trim final GA repositories, use repoclosure utility to check if there's no missing dependencies. +Before mass-tagging builds in -release we launch stable promotion CI jobs and if they're green, we publish them.

+

At this stage, CentOS Core team, creates final GA repositories and sign packages.

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/factory/promotion-pipeline/index.html b/factory/promotion-pipeline/index.html new file mode 100644 index 0000000..907ac61 --- /dev/null +++ b/factory/promotion-pipeline/index.html @@ -0,0 +1,1391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Workflow - Promotion pipeline - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Workflow: Promotion pipeline

+

+

Promotion pipelines are composed by a set of related CI jobs that are executed +for each supported OpenStack release to test the content of a specific RDO repository. +For each OpenStack release Puppet promotion pipelines are proceeded, to validate RDO packages with OpenStack Puppet + Modules and to promote the RDO packages used in upstream OpenStack Puppet modules check and gate jobs.

+

This pipeline run in parallel and is composed of different jobs.

+

The promotion workflow can be described with following schema:

+
    +
  1. +

    Define the repository to be tested. RDO Trunk repositories are identified +by a hash based on the upstream commit of the last built package. The content of +these repos doesn't change over time. When a promotion pipeline is launched, it +grabs the latest consistent hash repo and sets it to be tested in the following phases.

    +
  2. +
  3. +

    Deploy and test RDO. We run a set of jobs which deploy and test OpenStack +using different installers and scenarios to ensure they behave as expected. Currently, +there are following promotion testing method:

    +
      +
    • OpenStack Puppet scenarios. Project puppet-openstack-integration (a.k.a. p-o-i) + maintains a set of Puppet manifests to deploy different OpenStack services + combinations and configurations (scenarios) in a single server using OpenStack + Puppet Modules, and run tempest smoke tests for the deployed services. The + tested services on each scenario can be found in the + README + for p-o-i. These scenarios, together with Packstack deployment ones, are executed in puppet + promotion pipelines to test new packages build in RDO Repos. + Part of scenarios are currently tested in RDO CI as Packstack deployment.
    • +
    +
  4. +
  5. +

    Repository and images promotion. When all jobs in the previous phase succeed, +the tested repository is considered good and it is promoted so that users can use these +packages:

    + +
  6. +
+

Tools used in RDO CI

+
    +
  • Jobs definitions are managed using Zuul, +via a gerrit review workflow in review.rdoproject.org
  • +
  • WeIRDO is the tool we +use to run p-o-i and Packstack testing scenarios defined upstream inside RDO CI. +It is composed of a set of ansible roles and playbooks that prepare the environment +and deploy and test the installers using the testing scripts provided by +the projects.
  • +
  • ARA is used to store and visualize +the results of ansible playbook runs, making it easier to analize and troubleshoot +them.
  • +
+

Infrastructure

+

RDO runs the promotion pipelines in the CI infrastructure managed by Software Factory.

+

Handling issues in RDO CI

+

An important aspect of running RDO CI is properly managing the errors found in the +jobs included in the promotion pipelines. The root cause of these issues sometimes +is in the OpenStack upstream projects:

+
    +
  • Some problems are not caught in devstack-based jobs running in upstream gates.
  • +
  • In some cases, new versions of OpenStack services require changes in the deployment +tools
  • +
+

One of the contributions of RDO to upstream projects is to increase test coverage of +the projects and help to identify the problems as soon as possible. When we find them, +we report it upstream as Launchpad bugs and propose fixes when possible.

+

Status of promotion pipelines

+

If you are interested in the status of the promotion pipelines in RDO CI you can +check:

+
    +
  • +

    Zuul pipelines status view +can be used to see the result and status of each kind of puppet promotion pipeline +and OpenStack release.

    +
  • +
  • +

    RDO Dashboard shows the overall +status of RDO promotion pipelines.

    +
  • +
+

+ +

+

More info

+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/factory/workflow-overview/index.html b/factory/workflow-overview/index.html new file mode 100644 index 0000000..571690d --- /dev/null +++ b/factory/workflow-overview/index.html @@ -0,0 +1,1155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Infrastructure - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Infrastructure

+ +

The following pieces of infrastructure are used during the cycle:

+
    +
  • review.rdoproject.org is the central system for our workflow, powered by SoftwareFactory. It contains a Gerrit instance to manage all changes to the repositories where the spec files used to build our packages are contained, as well as the components managing our CI infrastructure.
  • +
  • Our distgit repositories contain one repository for each project built by RDO, where the spec files are located. Every change submitted via review.rdoproject.org is synchronized to the repos at GitHub.
  • +
  • The RDO Trunk repositories contain the latest packages.
  • +
  • The Zuul CI infrastructure is used to run the periodic jobs to promote the latest repositories.
  • +
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..4be7613 --- /dev/null +++ b/index.html @@ -0,0 +1,1407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Home - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+ + +
+

RDO

+

OpenStack, packaged for and tested on CentOS. +

+ + + Find us! + + Contribute + + Get start +
+
+
+
+ + + +
+ +
+

+ + + + Find us! +

+

Check out our community and see how can you find us! +

+
+ +
+

+ + + + Contribute +

+

Looking for a way to add your package or update dependency? See our contibution documentation. +

+
+ +
+

+ + + Get start +

+

Documentation to help you start +

+
+
+ +
+
+
+
+ + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

What is RDO?

+

RDO is a community of people using and deploying OpenStack on CentOS Stream and Red Hat Enterprise Linux. We have documentation to help get started, mailing lists where you can connect with other users, and community-supported packages of the most up-to-date OpenStack releases available for download.

+

If you are looking for enterprise-level support, or information on partner certification, Red Hat also offers Red Hat OpenStack Platform.

+

OpenStack relies on the underlying operating system and hypervisor — and what better operating system to build on than the industry's leading enterprise operating system? The RDO community is your one-stop community site for all things related to using OpenStack on Red Hat based platforms. +What's happening?

+

Find us!

+ +

Take a shortcut

+ + +
+
+ + + +
+ + + +
+ +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/misc/networking/index.html b/misc/networking/index.html new file mode 100644 index 0000000..228cec3 --- /dev/null +++ b/misc/networking/index.html @@ -0,0 +1,1308 @@ + + + + + + + + + + + + + + + + + + + + + + + + Networking - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Network troubleshooting

+

Check out this webcast - an overview of networking principles and how they apply to Neutron and OpenvSwitch - by Dave Neary.

+ + +

Toolchain

+

A number of tools come in handy when troubleshooting Neutron/Quantum networking issues.

+ +

tcpdump

+

tcpdump will be your best friend so it's best to learn and understand how to use it. When debugging routing issues with quantum, tcpdump can be used to investigate the ingress and egress of traffic. For example:

+
       tcpdump -n -i br-int
+
+

The above command will capature all traffic on the internal bridge interface.

+
       tcpdump -n -i br-int  -w tcpdump.pcap
+
+

The above command will capture all traffic on the internal bridge interface and dump it to a file named tcpdump.pcap.

+
       tcpdump -r tcpdump.pcap
+
+

The above command will read in a previously created tcpdump file

+
       tcpdump -n -i any
+
+

The above command will capture all traffic on any interface. ...

+

iproute2

+

iproute2 provides a tool called ip which allows you to debug what is going on.

+

Here are some diagnostics commands for networking (assuming you are using Neutron). Of-course, you'll replace the router namespace, dhcp namespace IDs , IP addresses accordingly:

+
# List namespaces
+$ ip netns
+qdhcp-4a04382f-03bf-49a9-9d4a-35ab9ffc22ad
+qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f
+
+# Show all interfaces inside the namespace
+$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \
+  ip a
+
+# Check routing table inside the router namespace
+$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \
+  ip r
+
+# IP config inside the router namesapce
+$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \
+  ifconfig
+
+# IP configu inside the dhcp namesace
+$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \
+  ifconfig
+
+# Ping the private IP (of the cirros guest)
+$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \
+  ping -c2 30.0.0.7
+$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \
+  ping -c2 192.168.122.14
+
+# ssh into cirros guest
+$ ip netns exec qdhcp-4a04382f-03bf-49a9-9d4a-35ab9ffc22ad ssh   cirros@30.0.0.7
+
+

Common issues

+
    +
  • +

    I can create an instance, but cannot SSH or ping it

    +
      +
    • +

      Verify that traffic to port 22 and ICMP traffic of any type (-1:-1) is allowed in the default security group + In the dashboard, in the Project tab, under "Access and Security", check the rules which are active on the security group you are using with your instances (typically "default"). You should see a rule allowing traffic to port 22 over tcp from all hosts, and a port enabling icmp traffic of all types (-1). If you don't, create the necessary rules, and try again.

      +
    • +
    • +

      Verify that you can ping and SSH the host where the instance is running + From the host where you are attempting to connect to your instance, verify that network traffic is being correctly routed to the compute node in question.

      +
    • +
    • +

      Ensure that the router is correctly created, that the internal subnet and external subnet are attached to it, and that it can route traffic from your IP to the instance IP + If your VM is in the 192.168.1.x subnet, and the host from which you are trying to connect is in the 192.168.0.x subnet, then you will need to have a route from one to the other. Ensure that the subnet 192.168.1.x and 192.168.0.x are both added to a router which you create in Neutron

      +
    • +
    • +

      Check that you can ping an instance from inside its network namespace. + If you are using network namespaces, then each VLAN will have its own namespace, and entities inside that namespace will be invisible from outside. You can check whether you can ping an instance from inside the namespace by first finding the namespace identifier, and then using the iproute toolset to execute a "ping" inside that namespace:

      +
    • +
    +
  • +
+ + +
ip netns list
+# Identify virtual router to which your subnet is connected
+ip netns exec qrouter-de0b9dbe-6b65-45ee-9ff2-c752c7937a9e ping 10.10.0.7
+# IP address and qrouter ID correspond to the network namespace and private IP address for instance
+
+-   Check the OVS routing table to ensure that it is correctly routing traffic from internal to external.
+    You should see a route for each subnet attached to your virtual router, and you should see routing which will allow traffic from the VM to get to the subnet of the host from which you are trying to connect (or to a public gateway)
+
+        ip netns exec qrouter-de0b9dbe-6b65-45ee-9ff2-c752c7937a9e route -n
+
+-   Verify that br-ex is associated with the physical NIC, and that the virtual router can route traffic to the IP address of the host. For a single NIC set-up, you will need to bring up br-ex at boot time, and connect eth0 to it.
+    To set up br-ex initially (on a host with static IP 192.168.0.2), the following will do the initial configuration:
+
+ + +
ip addr flush eth0
+ovs-vsctl add-port br-ex eth0
+ip addr add 192.168.0.2 dev br-ex
+ip link set br-ex up
+
+

To make changes persist after boot, you will need to create /etc/sysconfig/network-scripts/ifcfg-br-ex as follows (replace DNS, IP addresses for your local network):

+
DEVICE=br-ex
+TYPE=Ethernet
+BOOTPROTO=static
+ONBOOT=yes
+IPADDR=192.168.0.2
+NETMASK=255.255.255.0
+GATEWAY=192.168.0.1
+DNS1=89.2.0.1
+DNS2=89.2.0.1
+DOMAIN=neary.home
+NAME="System br-ex"
+
+

After this, you will no longer need to bring up eth0, and all going well you will be able to access both instances and the management interface on the same host.

+
    +
  • I cannot associate a floating IP with an instance
      +
    • If the error is that the external network is not visible from the subnet: Check that br-ex has its MAC address set correctly. Check for the error "Device or resource busy" in /var/log/messages - if it's present, you will need to bring down br-ex, set its MAC address to match that of the physical NIC, and bring it back up.
    • +
    +
  • +
  • I can create an instance, however, it does not get a DHCP address
      +
    • See openstack documentation for information on sniffing the various steps of the allocation of an IP address by DHCP - verify that your DHCP agent is running, is receiving the DHCPDISCOVER request, and is replying to it - and verify that your host is receiving the DHCP reply.
    • +
    • Make sure that IPv6 is enabled. Disabling IPv6 will give an error such as "Address family not supported".
    • +
    • If you are using OpenvSwitch with VLAN, make sure that the network created includes VLAN information. You may need to restart the quantum-openvswitch-agent service and/or create a network using specific VLAN information.
    • +
    +
  • +
+ + +
    +
  • If you are using more than one node for OpenStack (i.e., not an all-in-one installation), then you must use VLANs.
  • +
  • If you are using a virtual machine as a node in OpenStack, you must use the virtio network driver when using VLANs. The default rt8139 driver seems to drop VLAN information.
  • +
  • You must have an external network set as the gateway to the router if you want to get network traffic out of the private instance network.
  • +
+

Other resources

+ +

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/misc/qpid-errors/index.html b/misc/qpid-errors/index.html new file mode 100644 index 0000000..17fc053 --- /dev/null +++ b/misc/qpid-errors/index.html @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + Qpid errors - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Qpid errors

+

Config file errors

+

If you see something like the following message in your system log when the qpidd service attempts to start:

+
Jul 22 15:39:08 localhost qpidd[8631]: 2013-07-22 15:39:08 [Broker] critical Unexpected error: Error in configuration file /etc/qpidd.conf: Bad argument: |cluster-mechanism=DIGEST-MD5 ANONYMOUS|
+
+

Replace 'cluster-mechanism' with 'ha-mechanism' in /etc/qpidd.conf then restart the qpidd service, or reboot.

+

sasldb errors

+

The qpid user database may become corrupted. This may be evidenced by error messages such as:

+
     qpidd: unable to open Berkeley db /var/lib/qpidd/qpidd.sasldb: No such file or directory
+
+

You can recreate the sasldb file using the following command:

+
     saslpasswd2 -f /var/lib/qpidd/qpidd.sasldb -u QPID guest
+
+

Provide the password at the command line (usually 'guest'), and the file will be created. You should further ensure that /etc/cinder/cinder.conf references the correct username and password corresponding with this file. Then restart qpidd:

+
     service qpidd restart
+
+

You can verify the presence of users accounts in that file with:

+
     sasldblistusers2 -f /var/lib/qpidd/qpidd.sasldb
+
+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/misc/selinux-issues/index.html b/misc/selinux-issues/index.html new file mode 100644 index 0000000..fdfae50 --- /dev/null +++ b/misc/selinux-issues/index.html @@ -0,0 +1,1195 @@ + + + + + + + + + + + + + + + + + + + + + + + + SELinux issues - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

SELinux issues

+

Troubleshooting SELinux issues

+

General tips

+

SELinux can sometimes be a source of issues with OpenStack. On a system with SELinux enabled (as it is by default on Fedora and RHEL), you can check for denial messages with the command:

+
sudo cat /var/log/audit/audit.log | grep -i avc
+
+

or

+
sudo sealert -a /var/log/audit/audit.log
+
+

You can check the SELinux enforcement status of your machine with the command "sestatus" and can temporarily place SELinux in enforcing (in which it blocks access violations) or permissive (logs access violations, but does not block) with the commands "setenforce 1" and "setenforce 0", respectively.

+

To make SELinux enforcement changes that persist between reboots, edit the file /etc/selinux/config.

+

To see what the current security context for a resource ls, run

+
ls -Z
+
+

For more information on SELinux troubleshooting, see http://fedoraproject.org/wiki/SELinux/Troubleshooting.

+

Filing Bugzillas Jira ticket

+

Sometimes, there are missing policies required in order released RDO versions to work correctly with SELinux in enforcing mode. In order for the RDO developers to troubleshoot the problem, please perform the following:

+
    +
  • Set SELinux to permissive mode
  • +
  • +

    Zero out your /var/log/audit/audit.log: + sudo cp /dev/null /var/log/audit/audit.log

    +
  • +
  • +

    Perform a full test of the use case that is causing the problem

    +
  • +
  • File a Jira ticket and attach your /var/log/audit/audit.log
  • +
+

For more information about how SELinux policies are developed for RDO, see SELinux

+

PackStack fails if SELinux is disabled

+

It has been reported that PackStack will fail if SELinux is disabled.

+

The error observed is:

+
ERROR : Error during puppet run : err: /Stage[main]//Exec[setenforce 0]/returns:
+change from notrun to 0 failed: setenforce 0 returned 1 instead of one of [0]
+at /var/tmp/packstack/51a57c45478b4091b2eb6a1bbd4c2303/manifests/my_public_ip_ring_swift.pp:56
+Please check log file /var/tmp/packstack/20130421-002212-fYYLUA/openstack-setup.log for more information
+
+

The solution is to enable SELinux in permissive mode (if there is a reason not to have it in enforcing mode). In

+
/etc/selinux/config
+
+

set

+
SELINUX=permissive
+
+

If you have previously disabled SELinux, you will need to re-label the filesystem, since when SELinux is disabled, this does not happen for new files, and failing to relabel will likely cause many false positive issues. The easiest way to do that is to do the following as root:

+
touch /.autorelabel
+reboot
+
+

This issue is being tracked in Red Hat Bugzilla bug #954188

+

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/misc/selinux/index.html b/misc/selinux/index.html new file mode 100644 index 0000000..4f2a746 --- /dev/null +++ b/misc/selinux/index.html @@ -0,0 +1,1109 @@ + + + + + + + + + + + + + + + + + + + + + + + + SELinux - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

SELinux in an RDO Deployment

+

RDO releases should operate with SELinux in enforcing mode without issue. If it does not work for you, please see the SELinux_issues page for more information on how to troubleshoot and what information to gather for filing bugzillas.

+

From time to time, especially with the EL6 releases of RDO, certain measures are taken to ensure that RDO works and are distributed as part of the openstack-selinux package. This package contains fixes to ensure RDO continues working on top of the latest Red Hat Enterprise Linux 6 and CentOS 6 releases. It always advised to run the very latest selinux-policy package appropriate for your distribution, even if you upgrade nothing else. For example, if you are running CentOS 6.4, it is recommended to run the latest selinux-policy package from CentOS 6.5 if at all possible.

+

Occasionally, RDO developers will even release updated selinux-policy packages to ensure that your RDO systems stay operational with the latest RDO releases.

+

SELinux during RDO Development

+

RDO releases interim releases during upstream OpenStack development based on upstream milestones. For example, "icehouse-1". Shortly thereafter, the RDO team schedules Test Days in order to gather information on what needs to be fixed.

+

OpenStack is often in heavy development during these interim releases. Consequently, SELinux is likely to stand in the way of performing useful testing during these test days. For this reason, it is recommended to run in permissive mode during test days and gather AVCs:

+
sudo setenforce 0
+
+

The RDO team typically waits to coordinate with upstream SELinux policy developers until after the upstream "-3" milestone, which is the Feature Freeze for the next OpenStack release. This is because the high pace of innovation that takes place during OpenStack development cycles makes writing SELinux policy modules difficult to keep up with; it is similar to trying to keep localization work up to date.

+

What about a modular SELinux policy?

+

I get a lot of questions about this. The short answer is that SELinux policies are not conducive to being separated in to multiple git repositories/packages at this time.

+

(still work in progress)

+ + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/misc/troubleshoot/index.html b/misc/troubleshoot/index.html new file mode 100644 index 0000000..fe728eb --- /dev/null +++ b/misc/troubleshoot/index.html @@ -0,0 +1,1104 @@ + + + + + + + + + + + + + + + + + + + + + + + + Troubleshooting - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Troubleshooting

+

Every piece of software as complex as OpenStack has some pitfalls in its usage. We will use this page to collect tips and tricks related to installation and configuration issues, and issues which people run into during the lifetime of their OpenStack deployment.

+ + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/misc/uninstalling-rdo/index.html b/misc/uninstalling-rdo/index.html new file mode 100644 index 0000000..edebb75 --- /dev/null +++ b/misc/uninstalling-rdo/index.html @@ -0,0 +1,1099 @@ + + + + + + + + + + + + + + + + + + + + + + + + Uninstalling RDO - An OpenStack distribution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + +

Uninstalling RDO

+

There is no automated uninstall process for RDO (or OpenStack in general) because OpenStack consists of multiple services, (possibly) running across multiple systems. At this time there is no way to identify all of the various parts, locate them, and safely uninstall them.

+

Since OpenStack installations are almost certain to be deployed on dedicated systems (or VMs), the most reasonable way to "uninstall" RDO is to reinstall the base OS and start fresh.

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

RDO is a community of people using and deploying OpenStack on CentOS Stream and Red Hat Enterprise Linux. We have documentation to help get started, mailing lists where you can connect with other users, and community-supported packages of the most up-to-date OpenStack releases available for download.

If you are looking for enterprise-level support, or information on partner certification, Red Hat also offers Red Hat OpenStack Platform.

OpenStack relies on the underlying operating system and hypervisor \u2014 and what better operating system to build on than the industry's leading enterprise operating system? The RDO community is your one-stop community site for all things related to using OpenStack on Red Hat based platforms. What's happening?

"},{"location":"#find-us","title":"Find us!","text":"
  • Documentation to help you get started
  • Mailing lists
  • Report a bug in RDO Jira
"},{"location":"#take-a-shortcut","title":"Take a shortcut","text":"
  • How to deploy RDO?
  • How to add a package?
  • How to update a dependency?
"},{"location":"community/","title":"Community","text":"

Help us make the RDO community site a great place for users and cloud operators in the Red Hat ecosystem. There are many ways to contribute to RDO, some of which are detailed below.

Our community strives to operate according to the terms of the OpenStack Code of Conduct.

If you're just getting started, and are looking for a little help, consult our mentors list.

"},{"location":"community/#people-person","title":"People person","text":"
  • Join the RDO mailing lists
  • Chat on #rdo on OFTC
  • Participate in weekly meetings
"},{"location":"community/#latest-rdo-activity","title":"Latest RDO activity","text":""},{"location":"community/#centos-connect-brussels-2024","title":"Centos Connect, Brussels, 2024","text":""},{"location":"community/#centos-connect-brussels-2023","title":"Centos Connect, Brussels, 2023","text":"

See more at dedicated page.

"},{"location":"community/#user","title":"User","text":"
  • Share questions and solutions on openstack mailing lists
  • Add the most useful solutions
"},{"location":"community/#discuss","title":"Discuss","text":""},{"location":"community/#irc-channels","title":"IRC channels","text":"

Come chat in real-time with RDO users on IRC on the OFTC server:

  • #rdo: Any general conversation about RDO, including developer issues and user questions. (Transcripts.)

  • #openstack: Remember that RDO is just a small part of a larger community. Questions about OpenStack in general, not specifically about RDO, should go to the upstream channel. (Transcripts.)

Come chat in real-time with the CentOS Cloud SIG on IRC on the Libera Chat server:

  • #centos-cloud: If you have questions about the CentOS Cloud Special Interest Group (SIG) and the parts of the RDO infrastructure that run in the CentOS Community Build System (cbs), this is where you're most likely to get answers.
  • #centos-devel: If you have questions about the CentOS Project
"},{"location":"community/#irc-meetings","title":"IRC meetings","text":"

We have weekly IRC meetings you can participate in:

  • RDO meetings @ every Wednesday at 14:00 UTC on #rdo on OFTC
  • CentOS Cloud SIG meetings on the second Thursday of the month at 15:00 UTC on #centos-meeting on Libera Chat
"},{"location":"community/#content-writer","title":"Content writer","text":"
  • Work on RDO website issues
"},{"location":"community/#additional-sources","title":"Additional sources","text":"
  • Check our Frequently Asked Questions (FAQ) page for answers to common questions
  • Try our troubleshooting page for solutions to common problems
  • Watch RDO videos. These include recorded talks and community events.
  • Help improve our knowledge base by turning the best answers to questions on the mailing lists.
  • Fork the website on Github and help us improve our documentation.
"},{"location":"community/community-meeting/","title":"Community meeting","text":"

We hold our weekly community meeting every Wednesday at 14:00 UTC. The first week of the month is a virtual meeting held at https://meet.google.com/uzo-tfkt-top. All other weeks, the meeting is held on the #rdo IRC channel (OFTC - oftc.net).

The agenda for that meeting is in this etherpad.

The minutes for these meetings are below:

  • Jul 04, 2024
  • Jun 26, 2024
  • May 29, 2024
  • May 22, 2024
  • Apr 24, 2024
  • Apr 17, 2024
  • Apr 10, 2024
  • Apr 03, 2024
  • Mar 27, 2024
  • Mar 20, 2024
  • Mar 13, 2024
  • Mar 06, 2024
  • Feb 14, 2024
  • Feb 07, 2024
  • Jan 24, 2023
  • Jan 10, 2023
  • Nov 29, 2023
  • Nov 22, 2023
  • Oct 25, 2023
  • Oct 18, 2023
  • Oct 11, 2023
  • Oct 04, 2023
  • Sep 27, 2023
  • Sep 20, 2023
  • Sep 13, 2023
  • Sep 06, 2023
  • Aug 16, 2023
  • Aug 09, 2023
  • Aug 02, 2023
  • Jul 26, 2023
  • Jul 19, 2023
  • Jul 12, 2023
  • Jul 05, 2023
  • Jun 28, 2023
  • Jun 21, 2023
  • Jun 14, 2023
  • Jun 07, 2023
  • May 31, 2023
  • May 24, 2023
  • May 17, 2023
  • May 10, 2023
  • May 03, 2023
  • Apr 26, 2023
  • Apr 19, 2023
  • Apr 12, 2023
  • Apr 05, 2023
  • Mar 29, 2023
  • Mar 22, 2023
  • Mar 15, 2023
  • Mar 08, 2023
  • Mar 01, 2023
  • Feb 22, 2023
  • Feb 15, 2023
  • Feb 08, 2023
  • Jan 25, 2023
  • Jan 18, 2023
  • Jan 11, 2023
  • Dec 21, 2022
  • Dec 14, 2022
  • Nov 30, 2022
  • Nov 23, 2022
  • Nov 16, 2022
  • Oct 26, 2022
  • Oct 19, 2022
  • Oct 05, 2022
  • Sep 28, 2022
  • Sep 21, 2022
  • Sep 14, 2022
  • Sep 07, 2022
  • Aug 31, 2022
  • Aug 24, 2022
  • Aug 17, 2022
  • Aug 10, 2022
  • Aug 03, 2022
  • July 27, 2022
  • July 20, 2022
  • July 13, 2022
  • July 06, 2022
  • June 29, 2022
  • June 22, 2022
  • June 15, 2022
  • June 01, 2022
  • May 25, 2022
  • May 18, 2022
  • May 11, 2022
  • Apr 27, 2022
  • Apr 20, 2022
  • Apr 13, 2022
  • Mar 30, 2022
  • Mar 23, 2022
  • Mar 16, 2022
  • Mar 09, 2022
  • Feb 23, 2022
  • Feb 16, 2022
  • Feb 09, 2022
  • Jan 12, 2022
  • Jan 05, 2022
  • Dec 15, 2021
  • Dec 08. 2021
  • Nov 24. 2021
  • Nov 10. 2021
  • Nov 03. 2021
  • Oct 27. 2021
  • Oct 20. 2021
  • Oct 13. 2021
  • Oct 06. 2021
  • Sep 29. 2021
  • Sep 22. 2021
  • Sep 15. 2021
  • Sep 08. 2021
  • Sep 01. 2021
  • Aug 25. 2021
  • Aug 18. 2021
  • Aug 11. 2021
  • Aug 04. 2021
  • Jul 28. 2021
  • Jul 21. 2021
  • Jul 07. 2021
  • Jun 30. 2021
  • Jun 23. 2021
  • Jun 16. 2021
  • Jun 09. 2021
  • Jun 02. 2021
  • May 19. 2021
  • May 12. 2021
  • Apr 28. 2021
  • Apr 14. 2021
  • Apr 07. 2021
  • Mar 31. 2021
  • Mar 24. 2021
  • Mar 17. 2021
  • Mar 10. 2021
  • Mar 03. 2021
  • Feb 24. 2021
  • Feb 17. 2021
  • Feb 10. 2021
  • Feb 03. 2021
  • Jan 27. 2021
  • Jan 20. 2021
  • Jan 13. 2021
  • Jan 06. 2021
  • Dec 16. 2020
  • Dec 09. 2020
  • Dec 02, 2020
  • Nov 25, 2020
  • Nov 18, 2020
  • Nov 11, 2020
  • Oct 21, 2020
  • Oct 14, 2020
  • Oct 07, 2020
  • Sep 30, 2020
  • Sep 23, 2020
  • Sep 16, 2020
  • Sep 09, 2020
  • Sep 02, 2020
  • Aug 26, 2020
  • Aug 19, 2020
  • Aug 12, 2020
  • Aug 05, 2020
  • Jul 29, 2020
  • Jul 22, 2020
  • Jul 15, 2020
  • Jul 08, 2020
  • Jul 01, 2020
  • Jun 24, 2020
  • Jun 17, 2020
  • Jun 10, 2020
  • May 27, 2020
  • May 20, 2020
  • May 13, 2020
  • Apr 29, 2020
  • Apr 22, 2020
  • Apr 15, 2020
  • Apr 08, 2020
  • Apr 01, 2020
  • Mar 25, 2020
  • Mar 18, 2020
  • Mar 11, 2020
  • Mar 04, 2020
  • Feb 26, 2020
  • Feb 19, 2020
  • Feb 12, 2020
  • Feb 05, 2020
  • Jan 29, 2020
  • Jan 22, 2020
  • Jan 15, 2020
  • Jan 08, 2020
  • Dec 18, 2019
  • Ded 11, 2019
  • Nov 27, 2019
  • Nov 20, 2019
  • Nov 13, 2019
  • Nov 06, 2019
  • Oct 30, 2019
  • Oct 23, 2019
  • Oct 16, 2019
  • Oct 09, 2019
  • Oct 02, 2019
  • Sep 11, 2019
  • Jun 12, 2019
  • May 05, 2019
  • Mar 27, 2019
  • Mar 06, 2019
  • Jan 23, 2019
  • Jan 16, 2019
  • Dec 19, 2018
  • Dec 12, 2018
  • Nov 28, 2018
  • Nov 21, 2018
  • Nov 14, 2018
  • Nov 07, 2018
  • Oct 17, 2018
  • Oct 10, 2018
  • Sep 19, 2018
  • Sep 05, 2018
  • Aug 29, 2018
  • Aug 08, 2018
  • Aug 01, 2018
  • Jul 18, 2018
  • Jul 11, 2018
  • Jun 27, 2018
  • Jun 20, 2018
  • June 13, 2018
  • June 06, 2018
  • May 23, 2018
  • May 16, 2018
  • May 09, 2018
  • May 02, 2018
  • Apr 11, 2018
  • Apr 04, 2018
  • Mar 14, 2018
  • Mar 7, 2018
  • Feb 21, 2018
  • Feb 14, 2018
  • Feb 07, 2018
  • Jan 31, 2018
  • Jan 17, 2018
  • Jan 10, 2018
  • Nov 22, 2017
  • Nov 15, 2017
  • Nov 08, 2017
  • Nov 01, 2017
  • Oct 18, 2017
  • Oct 11, 2017
  • Oct 04, 2017
  • Sep 20, 2017
  • Sep 6, 2017
  • Aug 23, 2017
  • Aug 16, 2017
  • Aug 09, 2017
  • Jul 12, 2017
  • Jul 5, 2017
  • Jun 14, 2017
  • Jun 7, 2017
  • May 24, 2017
  • May 3, 2017
  • March 29, 2017
  • March 15, 2017
  • March 1, 2017
  • February 15, 2017
  • February 8, 2017
  • January 18, 2017
  • December 21, 2016
  • December 14, 2016
  • December 7, 2016
  • November 30, 2016
  • November 23, 2016
  • October 5, 2016
  • August 17, 2016
  • July 6, 2016
  • June 15, 2016
  • June 1, 2016
  • May 18, 2016
  • May 11, 2016
  • April 20, 2016
  • March 16, 2016
  • March 9, 2016
  • January 20, 2016
  • January 13, 2016
  • January 6, 2016
"},{"location":"community/faq/","title":"Frequently Asked Questions","text":""},{"location":"community/faq/#what-is-rdo","title":"What is RDO?","text":"

RDO is two things. It's a freely-available, community-supported distribution of OpenStack that runs on Red Hat Enterprise Linux (RHEL) and its derivatives, such as CentOS Stream.

In addition to providing a set of software packages, RDO is also a community of users of cloud computing platform on Red Hat-based operating systems to get help and compare notes on running OpenStack.

RDO aims to be the natural option for anyone that wants to run the most recently released version of OpenStack on supported systems. Whether you are interested in running OpenStack on RHEL in a production environment, or doing a proof of concept deployment on CentOS Stream, RDO is for you.

"},{"location":"community/faq/#what-does-rdo-stand-for","title":"What does RDO stand for?","text":"

RDO is the RPM Distribution of OpenStack. It's a group of Rediculously Dedicated OpenStackers who are here to help you Rapidly Deploy OpenStack, in a way that is Really Darned Obvious. RDO is Rebuilt Daily, Regularly Delivered, OpenStack.

"},{"location":"community/faq/#what-is-openstack","title":"What is OpenStack?","text":"

OpenStack is an open source project for building a private or public infrastructure-as-a-service (IaaS) cloud running on standard hardware. You can learn more about it by visiting www.openstack org.

"},{"location":"community/faq/#why-is-rdo-needed","title":"Why is RDO needed?","text":"

Just as a traditional operating system relies on the hardware beneath it, so too does the OpenStack cloud operating system rely on the foundation of a hypervisor and OS platform. RDO makes it easy to install and deploy the most up-to-date OpenStack components on the industry's most trusted Linux platform, Red Hat Enterprise Linux. and on RHEL derivatives like CentOS Stream, and Scientific Linux.

"},{"location":"community/faq/#why-should-i-use-an-openstack-distribution-from-red-hat","title":"Why should I use an OpenStack distribution from Red Hat?","text":"

The OpenStack project benefits from a broad group of providers and distributors, but none match Red Hat's combination of production experience, technical expertise, and commitment to the open source way of producing software. Some of the largest production clouds in the world run on and are supported by Red Hat, and Red Hat engineers contribute to every layer of the OpenStack platform. From the Linux kernel and the KVM hypervisor to the top level OpenStack project components, Red Hat is at or near the top of the list in terms of number of developers and of contributions.

"},{"location":"community/faq/#for-which-distributions-does-rdo-provide-packages","title":"For which distributions does RDO provide packages?","text":"

RDO targets Red Hat Enterprise Linux, CentOS Stream and their derivatives. Specifically, RDO packages are available for RHEL 7.0 or later (and CentOS 7.0, Scientific Linux 7.0 and other similar derivatives). More information is available at Release-cadence.

"},{"location":"community/faq/#how-is-rdo-different-from-upstream","title":"How is RDO different from upstream?","text":"

The OpenStack project develops code, and does not handle packaging for specific platforms. As a distribution of OpenStack, RDO packages the upstream OpenStack components to run well together on CentOS Stream, Red Hat Enterprise Linux and their derivatives, and provides you with installation tools to make it easier for you to deploy OpenStack.

Stable client branches are maintained per release as part of RDO because client backward compatibility isn't guaranteed upstream.

"},{"location":"community/faq/#how-can-i-participate","title":"How can I participate?","text":"

Feel free to contribute any packaging and integration patches via our developer mailing lists, or propose improvements to OpenStack on the upstream Launchpad page. For more information, see getting involved.

"},{"location":"community/faq/#is-rdo-a-fork-of-openstack","title":"Is RDO a fork of OpenStack?","text":"

RDO is not a fork of OpenStack, but a community focused on packaging and integrating code from the upstream OpenStack project on CentOS Stream and Red Hat Enterprise Linux. Red Hat continues to participate in the development of the core OpenStack projects upstream, and all relevant patches and bug reports are routed directly to the OpenStack community code base.

"},{"location":"community/faq/#how-do-i-deploy-rdo","title":"How do I deploy RDO?","text":"

You have multiple options, including:

  1. Check out dedicated aritcle about RDO deployments

  2. For proof of concept (PoC) environments, Packstack, an installation utility which uses Puppet modules to deploy OpenStack, is the primary tool. Instructions on installing RDO with Packstack are available on the Packstack quickstart page.

  3. For manual deployments using RDO packages, read the upstream OpenStack Installation Tutorial.

"},{"location":"community/faq/#where-can-i-find-help-with-rdo","title":"Where can I find help with RDO?","text":"

You can find documentation and get help through IRC, or mailing lists and from others in the RDO community. And don't hesitate to answer someone else's question if you know the answer. You can find all of the ways you can get involved in the RDO community at Get involved.

"},{"location":"community/faq/#can-i-buy-commercial-support-for-rdo","title":"Can I buy commercial support for RDO?","text":"

No commercial support for RDO will be available from Red Hat. If you need support for your OpenStack deployments, Red Hat offers Red Hat OpenStack Platform including a Partner Certification Program and Red Hat's award-winning support offering.

"},{"location":"community/faq/#what-is-the-errata-or-updates-policy-for-rdo","title":"What is the errata or updates policy for RDO?","text":"

RDO updates when the OpenStack project provides updates. RDO provides no lifecycle guarantees beyond what the upstream project provides. If you require additional guarantees, see Red Hat OpenStack Platform.

"},{"location":"community/faq/#can-i-upgrade-between-versions-of-rdo","title":"Can I upgrade between versions of RDO?","text":"

RDO users are advised to upgrade between consecutive OpenStack versions. The RDO project strives to release updated OpenStack versions as soon as possible following upstream releases, on the order of hours to a few days.

The upgrade process differs depending on what tool was used for deployment, however RDO project currently doesn't validate manual deployments.

"},{"location":"community/faq/#how-often-are-bug-fix-updates-of-rdo-made-available","title":"How often are bug fix updates of RDO made available?","text":"

We make RDO bug fix updates available asynchronously by following the stable bug fix releases of upstream OpenStack projects.

"},{"location":"community/faq/#where-is-rdo-built","title":"Where is RDO built?","text":"

RDO is built using CentOS infrastructure, similar to how CentOS packages are built. The build system is accessible at CBS.

"},{"location":"community/faq/#what-is-the-relationship-between-rdo-and-red-hats-commercial-openstack-product","title":"What is the relationship between RDO and Red Hat's commercial OpenStack product?","text":"

RDO is a community-supported OpenStack distribution that tracks the latest version of OpenStack upstream, beginning with OpenStack Grizzly. Red Hat OpenStack Platform is an enterprise-ready commercially-supported product from Red Hat.

"},{"location":"community/irc-etiquette/","title":"IRC etiquette","text":"

See also the list of IRC channels, and the general mentors list for more suggestions of who you might ask.

"},{"location":"community/irc-etiquette/#irc-communication-guidelines-and-etiquette","title":"IRC communication guidelines and etiquette","text":""},{"location":"community/irc-etiquette/#guidelines","title":"Guidelines","text":"

These are just some guidelines so you get a perspective of IRC culture, communication:

  • Try to ask smart questions, let us try to think for ourselves first and not let some poor, good-intentioned soul to do all the thinking for us. [Pro-tip: Eric S. Raymond's guide referred in the Resources section]
  • Try (as humanly as possible) to be: clear, concrete, specific and complete with your statements/questions. People cannot read your mind.
  • Be patient: do not expect people will devote time for extreme hand-holding. If a URL is pointed, please try things yourself, do your home-work, use Google effectively.
  • Try to maintain a balance of taking vs giving from the community. Do not demand excessive attention.
  • IRC is a DIY environment, not a paid-support forum. If someone responds to you, that is a bonus.
  • Be reminded: respect people's time, always answering IRC questions isn't developers first priority. Someone could be knee deep in gdb/pdb investigating that time-critical bug.
  • When in a community environment, just post the question to the channel, you do not have to ping a specific person just because he/she answered your question before. Nor do you have to ask questions like \"Anyone alive on this channel?\" \"Are you using ABC?\" Stay channel topic related!
  • It is an international channel: you may get better responses in certain time-zones, be patient - don't count on instant reactions.

All of the above look dead obvious, but doesn't instantly come to mind when asking questions in a public IRC. And, sure - we also understand we are all human, already overwhelmed and sometimes, we Just Need that answer and not want to follow any heavy instructions. If you're lucky, you might even have the bonus of getting it answered instantly.

"},{"location":"community/irc-etiquette/#pinging-for-attention-please-avoid-a-naked-ping","title":"Pinging for attention (please avoid a 'naked ping')","text":"

If you're not aware of what a 'naked ping' is, please take 3 minutes to read this excellent post.

"},{"location":"community/irc-etiquette/#do","title":"Do:","text":"

To save everyone's time, please try to ping with a specific request/question/comment.

Preferred:

<Bob> Alice: Ping,  re:  a certain topic (or a specific question)\n

Even better: if possible, a fully self-contained question requesting a clear action, so the person you pinged may come back 3 hours later and respond at her/his own pace:

<Bob> Alice: Ping, re: bug#1456234. Don't you think the reporter\n             should retest with that specific version of openstack-nova\n             mentioned in comment#4? It fixes the bug.\n\n    [3 HOURS LATER. . .]\n\n<Alice> Bob: Hi, you were right with that bug. I had an incorrect assumption.\n             I just closed the bug, adding a relevant rationale.\n

(Agreed -- not all questions can be that self-contained, but you get the drift.)

"},{"location":"community/irc-etiquette/#dont","title":"Don't:","text":"

In short: please avoid -- a-ping-followed-by-permission-to-ask-a-question-followed-by-long-silence. Or any similar variants.

i.e. do not do a naked ping with no request for any information or any question:

<Bob> Alice: Ping\n\n    [LONG SILENCE. . .]\n

nor this:

<Bob> Alice: Ping\n<Alice> Bob: Pong?\n<Bob> Alice: Can I talk to you now? I have a technical question to discuss\n\n    [LONG SILENCE. . .]\n\n<Alice> Bob: Sure.    (Inside Alice's head -- 'Sigh, will you already ask the question please?!')\n\n    [Again, in some cases, this interrupt is  followed by a long SILENCE. . . ]\n\n<Bob> Alice: A vague question with not so clear details.\n

You see what a time drain the above has become which has not led to any meaningful exchange? At this point, I'm sure you can clearly imagine what a test of mental sanity it'll be for Alice to have 10 to 12 pings like that each day. Let's not do that.

"},{"location":"community/irc-etiquette/#resources","title":"Resources","text":"
  • A fantastic resource from Eric S. Raymond on how to ask smart questions
  • Other communities (Fedora project) IRC communication guidelines
"},{"location":"community/mailing-lists/","title":"Mailing lists","text":"

There are three main mailing lists for RDO discussion:

"},{"location":"community/mailing-lists/#users-userslistsrdoprojectorg","title":"Users - users@lists.rdoproject.org","text":"

The main discussion list if you are looking for help on the RDO project.

  • Subscribe
  • Archives
"},{"location":"community/mailing-lists/#developers-devlistsrdoprojectorg","title":"Developers - dev@lists.rdoproject.org","text":"

The main discussion list for RDO project contributors.

  • Subscribe
  • Archives
"},{"location":"community/mailing-lists/#newsletter-newsletterlistsrdoprojectorg-inactive","title":"Newsletter - newsletter@lists.rdoproject.org - inactive","text":"

A monthly update of what's going on at RDO. This list is read-only, and very low volume.

  • ~~Subscribe~~ [ARCHIVED]
  • Archives
"},{"location":"community/mailing-lists/#other-lists","title":"Other lists","text":"

A complete list of mailing lists may be found at RDO Mailing-lists.

You may also want to be on one or more of the OpenStack mailing lists.

"},{"location":"community/rdo-videos/","title":"RDO videos","text":""},{"location":"community/rdo-videos/#centos-connect-brussels-2024","title":"Centos Connect, Brussels, 2024","text":""},{"location":"community/rdo-videos/#centos-connect-brussels-2023","title":"Centos Connect, Brussels, 2023","text":""},{"location":"community/rdo-videos/#openstack-ptg-atlanta-2017","title":"OpenStack PTG, Atlanta, 2017","text":"
  • What did you do in OpenStack Ocata?
"},{"location":"community/rdo-videos/#centos-dojo-brussels-2017","title":"CentOS Dojo, Brussels, 2017","text":"
  • Watch videos from the event in Videos from the CentOS Dojo, Brussels, 2017.
"},{"location":"community/rdo-videos/#rdo-bof-openstack-summit-austin","title":"RDO BoF @ OpenStack Summit Austin","text":""},{"location":"community/rdo-videos/#fosdem-2016","title":"FOSDEM 2016","text":"
  • RDO Community Day
"},{"location":"community/rdo-videos/#openstack-summit-atlanta","title":"OpenStack Summit Atlanta","text":"
  • OpenStack Summit Atlanta presentations
"},{"location":"community/rdo-videos/#openstack-networking-part-ii","title":"OpenStack Networking Part II","text":""},{"location":"community/rdo-videos/#openstack-networking-for-dummies","title":"OpenStack Networking for Dummies","text":""},{"location":"community/rdo-videos/#introducing-rdo","title":"Introducing RDO","text":""},{"location":"community/rdo-videos/#installing-openstack-with-packstack-and-rdo","title":"Installing OpenStack with PackStack and RDO","text":""},{"location":"community/rdo-videos/#automating-openstack-with-red-hat-puppet","title":"Automating OpenStack with Red Hat & Puppet","text":""},{"location":"community/rdo-videos/#heat-openstack-and-red-hat","title":"Heat, OpenStack and Red Hat","text":"
  • Interview with Steve Hardy at Open World Forum 2013.
"},{"location":"contribute/","title":"Contribute to RDO","text":"

If you are interested in contribute to RDO project, here you can find all documentation related to this process.

Our community strives to operate according to the terms of the OpenStack Code of Conduct.

If you're just getting started, and are looking for a little help, consult our mentors list.

"},{"location":"contribute/#packager","title":"Packager","text":"
  • Review RDO patches
  • Become an RDO package maintainer
  • Get to know RDO Packaging documentation
  • Get started now!
"},{"location":"contribute/#tester","title":"Tester","text":"
  • Review open bugs
  • File bugs
"},{"location":"contribute/add-packages/","title":"Adding new packages to RDO","text":""},{"location":"contribute/add-packages/#how-to-add-a-new-openstack-package-to-rdo-trunk","title":"How to add a new OpenStack package to RDO Trunk","text":"

When a new package is required in RDO, it must be added to RDO Trunk packaging. To include new packages, following steps are required:

  1. Create a \"Package Review\" story in RDO Jira board. You can clone the new package template story. Make sure you replace the title with the actual package name, and provide the reason and upstream code repository in the description. The story should be assigned to the Epic \"RDO release name\" and \"Fix Version/s\" field is also assigned to the desired RDO release. Once the issue has been created, and an initial license check has been conducted, you can continue with steps 2 and 3.

  2. Send a review adding the new project in rdo.yml to the rdoinfo project in review.rdoproject.org. In this change you must provide the project information and Package Review Jira story ticket in the commit message (see this example). Add the project definition in rdo.yml file and under-review tag in tags/under-review.yml file, as for example:

    # in rdo.yml\n- project: octavia-lib\n  conf: rpmfactory-lib\n  maintainers:\n  - nmagnezi@redhat.com\n  - cgoncalves@redhat.com\n  - bcafarel@redhat.com\n\n# in tags/under-review.yml\n- project: octavia-lib\n  tags:\n    under-review:\n

    Note: Maintainers must be registered in review.rdoproject.org and use the registered email in the rdoinfo review. This is required to set your permissions on your project.

    Once the patch is merged, following tasks are done by RDO automation process:-

    • Patch is proposed to create project and assign permissions to maintainers to manage the project. (as in this example)
    • Once the create project patch is merged, required projects will be created in https://review.rdoproject.org with repo synched to github.com.
    • Patch is proposed to add new projects to rdo zuul configuration in review.rdoproject.org.
    • Patch is proposed to add check jobs to new projects in rdoproject.org. (as in this example). CI jobs in this patch will fail until the Patch to add new projects to rdo zuul configuration is merged.
  3. Create a new review to the new distgit project with the needed content (spec file, etc...) for the initial import as in this example. This will trigger a CI job to test the package build. The spec will be reviewed by the core RDO packagers, and cannot be approved by the requester.

  4. Once the initial spec is considered ready to merge by the reviewers, go back to the Package Review Story and update it with the final spec and SRPM. Then, the formal package review will be conducted by the reviewer using fedora-review. Only after the fedora-review output is added as a comment in the story, the initial spec review will be approved in Gerrit.

  5. Finally, send a new review to rdoinfo project to remove the under-review tag from tags/under-review.yml file and add tags for which package needs to be build, For current release Train, 2 files need to be updated(tags/train.yml, tags/train-uc.yml) (example). This change can be sent before merging review in step 3 if a Depends-On: <gerrit-change-id step 3> is added.

Once the change is merged in rdoinfo, a new package should be automatically built and published in the RDO Trunk repos.

In order to track all review requests related to a new package process, it's recommended to use the same topic (as add-octavia-lib in the above examples) for all these reviews.

RDO project is working to automate as much as possible this process. If you need help to add new packages, you can ask on #rdo or rdo-list mailing list.

"},{"location":"contribute/add-packages/#how-to-add-a-new-puppet-module-to-rdo-trunk","title":"How to add a new puppet module to RDO Trunk","text":"

Adding a new puppet module to RDO Trunk is done using the same process as adding a new package to RDO Trunk with a few small differences. Use the following steps referencing the above How to add a new package to RDO Trunk for details on submitting a new puppet module. The steps here correspond to the steps above offering details specific to puppet modules.

  1. Submit the Package Review, instead of including a spec file reference that the spec file will be generated.

  2. Send a review to rdoinfo according to the package requirements. The under-review tag is still required. Use this as example content:

    # in rdo.yml\n- project: puppet-congress\n  conf: rpmfactory-puppet\n\n# in tags/under-review.yml\n- project: puppet-congress\n  tags:\n    under-review:\n
  3. Generate the spec file to submit to the new distgit project using this script

  4. Process is the same as standard packages

"},{"location":"contribute/get_packages_ready/","title":"New OpenStack release","text":""},{"location":"contribute/get_packages_ready/#getting-packages-ready-for-new-openstack-releases","title":"Getting packages ready for new OpenStack releases","text":"

When a new OpenStack release is delivered upstream, there is a set of steps that must be performed in RDO to build and publish new packages both in RDO CloudSIG and RDO Trunk repos.

"},{"location":"contribute/get_packages_ready/#1-rdo-infrastructure-preparation","title":"1. RDO infrastructure preparation","text":"

Some weeks before a new OpenStack release is published, some changes in RDO tools and infrastructure are needed to get the delivery pipeline ready. These tasks are mostly done by RDO core members, for example:

  • Adding a new DLRN builder following stable/ branch.
  • Creating CI jobs for new branches.
  • Including new release in automation bots.
  • etc...
  • Once these tasks are done, it will be announced in rdo mailing lists so that package maintainers can start carrying out the next steps.

    "},{"location":"contribute/get_packages_ready/#2-update-package-distgits","title":"2. Update package distgits.","text":"

    Around RC1 time (check upstream schedule), package maintainers should send required reviews to rpm-master branch to adjust distgits contents to the changes occurred during the cycle. This typically includes updating minimal versions for existing dependencies, removing not longer used requirements, etc... Note that rdopkg reqcheck command can be used to check changes in dependencies.

    "},{"location":"contribute/get_packages_ready/#3-create-new-branch-release-rdo-in-distgits","title":"3. Create new branch <release>-rdo in distgits.","text":"

    Once the distgits content is ready for the new release, package maintainers must request a new branch <release>-rdo for their packages. This can be done by sending a review to the corresponding package resource in gerrit configuration following next steps:

    1. Clone config project:

      git clone https://review.rdoproject.org/r/config\n
    2. RDO gerrit config project contains a resource file for each managed package. Look for the one containing the package where the new branch is needed:

      cd config/resources\ngrep <project name>-distgit *\n

      i.e.:

      $ grep novaclient-distgit *\nopenstack-novaclient.yaml:    openstack-novaclient-distgit:\nopenstack-novaclient.yaml:    openstack/novaclient-distgit:\nopenstack-novaclient.yaml:      acl: openstack-novaclient-distgit\n
    3. Edit the yaml file. Look for <project name>-distgit under repos section. If it doesn't have a branches sub-section, add it. Inside branches add a new line with the branch name:

      <release>-rdo: <commit id for last commit in rpm-master in the project distgit>\n

      The commit id of the last commit in the project distgit must be specified as it will be used as starting point for the new branch. For example:

      repos:\n  openstack/novaclient:\n    acl: openstack-novaclient\n    description: Mirror of upstream novaclient (mirror + patches)\n  openstack/novaclient-distgit:\n    acl: openstack-novaclient-distgit\n    description: Packaging of upstream novaclient\n    branches:\n      pike-rdo: 71fafbb21c2dc8dd518a0c3d5f635b6b04100661\n      queens-rdo: c2e115b3283fd776cabaf68d0eb7940030fc1821\n      rocky-rdo: c0663f17adf0bc05999d8b2caabbe9270af93c27\n      stein-rdo: 9d0b15be17c3aaf39dccd5a0ab8fe01801d6484d\n
    4. Commit the change and send the review using commands:

      git commit -a -m \"Create new branch <release>-rdo\"\ngit review\n

      An example of a new branch request can be found here

    "},{"location":"contribute/get_packages_ready/#4-request-new-builds-for-cloudsig-repos","title":"4. Request new builds for CloudSIG repos.","text":"

    After new branches are created in distgits and upstream projects have pushed tags for new RC or final releases (depending on the release model adopted for each upstream project), new builds are created using Centos Build System by sending a review to the <release>-rdo branch as shown in this doc. Note that RDO uses a bot to propose reviews for new releases automatically in most cases, however it's recomended that package maintainers pay some attention on this process and send a review if reviews have not been created on time.

    "},{"location":"contribute/get_packages_ready/#5-pin-branchless-projects-in-rdoinfo","title":"5. Pin branchless projects in rdoinfo.","text":"

    According to stable policies, RDO Trunk repos shouldn't follow master branch after GA. By default, DLRN builders are configured to use stable/<release> branches for non-master releases. However, some projects packaged in RDO don't create stable branches upstream or use different ones. For example, some independent projects create a branch for each supported major package version instead of OpenStack release. For those cases, packages should be pinned to a specific git tag, commit or branch. This is done by sending a review to rdoinfo project using source-branch parameter for the release tag as in this example.

    "},{"location":"contribute/how-to-fix-a-ftbfs-using-dlrn/","title":"How to fix a FTBFS using DLRN","text":"

    DLRN is the tool used by the RDO project to build RPM packages for every commit from the OpenStack projects. See article for more details on how DLRN works. These commits from the upstream OpenStack projects can introduce changes that break the packaging. We call these FTBFS (Failure To Build From Source). When we have a FTBFS reported by DLRN, someone needs to take care of fixing it. You can see these using gerrit at https://review.rdoproject.org/#/q/topic:rdo-FTBFS. We\u2019ll work on an example reported on the horizon package in https://review.rdoproject.org/r/#/c/1131/1/. Here are the steps to propose a correction:

    First you need to install DLRN:\ngit clone [https://github.com/openstack-packages/DLRN.git](https://github.com/openstack-packages/DLRN.git)\ncd DLRN\ntox\n. .tox/py27/bin/activate\n

    Then let DLRN build the horizon project to be sure we reproduce the build issue locally: dlrn --config projects.ini --package-name horizon --dev --head-only

    Keep in mind that the default projects.ini file will try to create a package for the master branch using CentOS7 as a target. If the failure happens in a different branch, such as stable/mitaka, you will need to adjust the file as needed. The dist-git repository is stored under data/_distro so extract the gerrit review in this directory:

    cd data/horizon_distro\ngit review -s\ngit review -d 1131\n

    Edit the spec file to fix the problem. Remember to remove the last line in the spec file, it was created by the dummy review. Here in this case, we just needed to remove files not distributed anymore and then archive the change in git resetting the author to take the ownership of the review:

    git commit --amend -a --reset-author\ncd ../..\n

    To test your change use the same build command as before with the addition of \u2013local to use your modifications:

    dlrn --config projects.ini --package-name horizon --dev --head-only --local\n

    If everything is fine, just submit the change using the rdo-FTBFS topic:

    cd data/horizon_distro\ngit review -t rdo-FTBFS\n

    Then you\u2019ll need to have the review accepted by a core reviewer. In our example, here is the proposed changeset to fix the problem: https://review.rdoproject.org/r/#/c/1131/2/

    "},{"location":"contribute/intro-packaging/","title":"RDO OpenStack Packaging","text":""},{"location":"contribute/intro-packaging/#packaging-overview","title":"Packaging overview","text":"

    RDO produces two set of packages repositories:

    • RDO CloudSIG repositories provide packages of upstream point releases created through a controlled process using CentOS Community Build System. This is kind of \"stable RDO\".

    • RDO Trunk repositories provide packages of latest upstream code without any additional patches. New packages are created on each commit merged on upstream OpenStack projects.

    Following diagram shows the global packaging process in RDO.

    "},{"location":"contribute/intro-packaging/#distgit-where-the-spec-file-lives","title":"distgit - where the .spec file lives","text":"

    distgit is a git repository which contains .spec file used for building a RPM package. It also contains other files needed for building source RPM such as patches to apply, init scripts etc.

    RDO packages' distgit repos are hosted on review.rdoproject.org and follow $PROJECT-distgit naming. You can navigate the full list of distgit repos using this link.

    You can use rdopkg to clone a RDO package distgit and also setup related remotes:

    $> rdopkg clone openstack-nova\nCloning distgit into ./openstack-nova/\ngit clone http://review.rdoproject.org/r/p/openstack/nova-distgit.git openstack-nova\n...\n

    Inspect package history using git:

    $> cd openstack-nova\n$> git checkout mitaka-rdo\n$> git log --oneline\nded74f2 Add privsep-helper to nova sudoers file\n55981cf Add python-microversion-parse dependency\n39d576a Update .gitreview\n4e53ad0 Add missing python-cryptography BuildRequires\n

    See what rdopkg thinks about current distgit:

    $> rdopkg pkgenv\n\nPackage:   openstack-nova\nVersion:   13.0.0\nUpstream:  13.0.0\nTag style: X.Y.Z\n\nPatches style:          review\nDist-git branch:        mitaka-rdo\nLocal patches branch:   mitaka-patches\nRemote patches branch:  patches/mitaka-patches\nRemote upstream branch: upstream/master\nPatches chain:          http://review.rdoproject.org/r/631\n

    Submit distgit changes for review:

    $> rdopkg review-spec\n

    "},{"location":"contribute/intro-packaging/#branches-in-distgits","title":"Branches in distgits","text":"

    Because of the different build tools used for RDO CloudSIG and Trunk repos and the differences in dependencies and content in packages for each OpenStack release, RDO maintains several branches in distgits:

    • rpm-<release>: is used to package RDO trunk (version can be master, mitaka or liberty )
    • <release>-rdo: is used for RDO CloudSIG.

    There are a number of expected differences between the spec files in rpm-<release> and <release>-rdo branches:

    • For RDO trunk, packaging has had Version: and Release: fields both set to XXX as dlrn takes both of these from the tags set on the git repositories. For <release>-rdo branches they must be manually set to the right version and release.

    • %changelog section is empty in rpm-<release>.

    • Because we are packaging vanilla upstream code, patches aren't backported into the RDO Trunk repositories.

    • All of the specs in rpm-<release> branches contain a reference to %{upstream_version} in the %setup macro, this is because the subdirectory contained in the source tarball contains both the version and release, this is being passed into rpmbuild. In the Fedora packaging, spec can include compatibility macro e.g. Nova to avoid conflicts when backporting change from master packaging.

    • The files sources and .gitignore have been truncated in the master packaging

    • In %files avoid using %{version} and use instead wildcard *

    "},{"location":"contribute/intro-packaging/#rpm-master-and-rpm-master-head-branches","title":"rpm-master and rpm-master-head branches","text":"

    As previously stated, the rpm-master branch is used to package RDO Trunk using the master source branch. However, There are two RDO Trunk builder building packages from that branch:

    • The main builder, which pins libraries and clients to the versions included in upper-constraints.

    • The master-head, that chases master in all packages, including libraries, clients, etc.

    Initially, both builders use the rpm-master distgit branch. However, we may find an issue for a client or library in master-head that does not show up on the main builder yet. In those cases, we will create a temporary distgit branch called rpm-master-head, where the fix will be merged.

    Having this temporary rpm-master-head branch will allow us to fix the build for the package, and once the change in the master repo reaches a tagged release used by the main builder, we can simply cherry-pick the change and remove the temporary branch.

    "},{"location":"contribute/intro-packaging/#patches-branch","title":"Patches branch","text":"

    Because we rebase often in RDO CloudSIG repos, manual management of patch files in distgit would be unbearable. That's why each distgit branch has an associated patches branch which contains upstream git tree with extra downstream patches on top.

    A distgit can be automatically updated by rdopkg to include patches from associated patches branch and thus RPM patches are managed with git.

    Individual RDO patches are maintained in form of gerrit reviews on review.rdoproject.org.

    "},{"location":"contribute/intro-packaging/#rdopkg","title":"rdopkg","text":"

    rdopkg is a command line tool that automates many operations on RDO packages including:

    • cloning package distgit and setting up remotes
    • introducing patches
    • rebases to new versions
    • sending changes for review
    • querying rdoinfo metadata
    • modifying .spec file: bumping versions, managing patches, writing changelog, producing meaningful commit messages, ...

    rdopkg is a Swiss army knife of RDO packaging and it automates a number of repetitive and error prone processes involving several underlying tools, each with its own quirks.

    Install rdopkg from Fedora/EPEL repos:

    $> dnf install rdopkg\n

    rdopkg source lives at softwarefactory-project.io but it's also mirrored to github.

    Bugs are tracked as github issues.

    Poke jruzicka on #rdo for help/hate/suggestions about rdopkg.

    See also man rdopkg.

    "},{"location":"contribute/intro-packaging/#rdoinfo-metadata","title":"rdoinfo metadata","text":"

    rdoinfo is a git repository containing RDO packaging metadata such as releases, packages, maintainers and more.

    rdoinfo lives at review.rdoproject.org and is also mirrored to github.

    Most of the metadata is stored in rdo.yml and deps.yml, tags and buildsys-tags are stored in multiple YAML files as described below:

    • rdo.yml
    • deps.yml
    • tags/\\<tag>.yml
    • buildsys-tags/cloud7-openstack-\\<release>-\\<phase>.yml

    The files under tags and buildsys-tags directories are named based on names of tags and buildsys-tags, this is defined as follows:-

    • release: is a the OpenStack release name, as queens, rocky or stein.
    • tag: tag for which project is build, like queens, rocky, stein, train, train-uc, etc.
    • phase:
    • candidate phase is assigned to packages to be rebuilt in CBS but not pushed to any RDO repository.
    • el7-build (only available for Rocky and newer releases) is assigned to packages that only required to build other packages but are not a runtime requirement for any other package.
    • testing phase means that the package is used in deployments using RDO Trunk repo and published in a testing repo, but not official CloudSIG repository.
    • release phase means that is published in the official CloudSIG repository. This phase is only available after a RDO version has been officially released not for the one currently under development.

    To query rdoinfo, use rdopkg info:

    $> rdopkg info\n$> rdopkg info openstack-nova\n$> rdopkg info maintainers:jruzicka@redhat.com\n

    To integrate rdoinfo in your software, use rdopkg.actionmods.rdoinfo module.

    "},{"location":"contribute/intro-packaging/#dlrn","title":"DLRN","text":"

    DLRN is a tool used to build RPM packages on each commit merged in a set of configurable git repositories. DLRN uses rdoinfo to retrieve the metadata and repositories associated with each project in RDO (code and distgit) and mock to carry out the actual build in an isolated environment.

    DLRN is used to build the packages in RDO Trunk repositories that are available from http://trunk.rdoproject.org.

    NVR for packages generated by DLRN follows some rules:

    • Version is set to MAJOR.MINOR.PATCH of the next upstream version.
    • Release is 0.<timestamp>.<short commit hash>

    For example openstack-neutron-8.1.1-0.20160531171125.ddfe09c.el7.centos.noarch.rpm.

    "},{"location":"contribute/intro-packaging/#rdo-trunk-packaging-guide","title":"RDO Trunk Packaging Guide","text":"

    In RDO Trunk packages are built automatically by DLRN from .spec templates residing in rpm-master and rpm-$RELEASE distgits.

    In order to build an RPM with the master packaging you'll need to install DLRN, following the instructions described in this README.

    "},{"location":"contribute/intro-packaging/#run-dlrn","title":"Run DLRN","text":"

    Once DLRN is installed, run dlrn for the package you are trying to build.

    $> dlrn --config-file projects.ini --local --package-name openstack-cinder\n

    This will clone the distgit for the project you're interested in into data/openstack-cinder_distro, you can now change this packaging and rerun the dlrn command in test your changes.

    If you have locally changed the packaging make sure to include --dev in the command line. This switches dlrn into \"dev mode\" which causes it to preserve local changes to your packaging between runs so you can iterate on spec changes. It will also cause the most current public master repository to be installed in your build image(as some of its contents will be needed for dependencies) so that the packager doesn't have to build the entire set of packages.

    The output from dlrn is a repository containing the packages you just built along with the most recent successfully built version of each package. To find the most recent repository follow the symbolic link ./data/repos/current

    "},{"location":"contribute/intro-packaging/#submitting-distgit-changes-to-gerrit","title":"Submitting distgit changes to gerrit","text":"

    When modifying spec files for RDO Trunk keep in mind the considerations shown in Branches in distgits and follow the recommendations in the RDO Packaging Guidelines. Once you are happy that you have your changes in distgit ready to be reviewed, create a git commit with an appropriate comment, add a git remote pointing to gerrit and then submit your patch

    $> git review -s\n$> git commit -p\n$> git review rpm-master\n
    "},{"location":"contribute/intro-packaging/#browsing-gerrit-for-reviews","title":"Browsing gerrit for reviews","text":"

    To look at all open patches for the upstream packaging simply use the this link and look for your desired project, for example openstack/cinder-distgit.

    "},{"location":"contribute/intro-packaging/#rdo-cloudsig-packaging-guide","title":"RDO CloudSIG Packaging Guide","text":"

    Packaging files for CloudSIG repos live in $RELEASE-rdo branches of distgit. Patches can be introduced as needed through associated patches branch.

    "},{"location":"contribute/intro-packaging/#initial-repository-setup","title":"Initial repository setup","text":"

    rdopkg clone takes care of getting the package distgit and also setting up all relevant git remotes defined in rdoinfo. Use -u/--review-user option to specify your github username if it differs from $USER.

    $> rdopkg clone openstack-nova -u github-username\nCloning distgit into ./openstack-nova/\ngit clone http://review.rdoproject.org/r/p/openstack/nova-distgit.git openstack-nova\nAdding patches remote...\ngit remote add patches http://review.rdoproject.org/r/p/openstack/nova.git\nAdding upstream remote...\ngit remote add upstream git://git.openstack.org/openstack/nova\n...\n

    Check output of rdopkg pkgenv to see what rdopkg thinks about your package:

    $> cd openstack-nova\n$> git checkout mitaka-rdo\n$> rdopkg pkgenv\n
    "},{"location":"contribute/intro-packaging/#simple-spec-fix","title":"Simple .spec fix","text":"

    The simplest kind of change that doesn't introduce/remove patches or different source tarball.

    • Make required changes.
    • Bump Release.
    • Provide useful %changelog entry describing your change.
    • Commit the distgit changes with meaningful commit message.
    • Send the change for review.

    Although this change is simple, rdopkg fix can still make some string manipulation for you. In following example, I add a new dependency to nova package:

    $> cd openstack-nova\n$> git checkout mitaka-rdo\n$> rdopkg fix\n\nAction required: Edit .spec file as needed and describe changes in changelog.\n\nOnce done, run `rdopkg -c` to continue.\n\n$> vim openstack-nova.spec\n# Add Requires line and describe the change in %changelog\n$> rdopkg -c\n

    After this, rdopkg generates new commit from the %changelog entry you provided and displays the diff:

        Epoch:            1\n    Version:          13.0.0\n   -Release:          1%{?dist}\n   +Release:          2%{?dist}\n    Summary:          OpenStack Compute (nova)\n\n    ...\n\n    Requires:         bridge-utils\n    Requires:         sg3_utils\n    Requires:         sysfsutils\n   +Requires:         banana\n\n    %description compute\n    OpenStack Compute (codename Nova) is open source software designed to\n\n    ...\n\n    %changelog\n   +* Mon May 09 2016 Jakub Ruzicka <jruzicka@redhat.com> 1:13.0.0-2\n   +- Require banana package for the lulz\n   +\n    * Thu Apr  7 2016 Ha\u00efkel Gu\u00e9mar <hguemar@fedoraproject.org> - 1:13.0.0-1\n    - Upstream 13.0.0\n

    Finally, send the changes for review:

    $> rdopkg review-spec\n
    "},{"location":"contribute/intro-packaging/#introducingremoving-patches","title":"Introducing/removing patches","text":"

    See patches branch for introduction.

    Following schema shows the workflow to maintain patches applied in the packaging process.

         +------------------------+\n     |        upstream        |\n     |  github.com/openstack  |\n     +------------------------+\n                 |\n git cherry-pick | rdopkg review-patch\n                 V\n     +-------------------------+\n     |      patches branch     |\n     |  review.rdoproject.org  |\n     +-------------------------+\n                 |\n    rdopkg patch | rdopkg review-spec\n                 V\n     +-------------------------+\n     |        distgit          |\n     |  review.rdoproject.org  |\n     +-------------------------+\n

    First, use rdopkg get-patches to get a patches branch associated with current distgit, cherry pick your patch(es) on top, and send them for review with rdopkg review-patch:

    $> git checkout mitaka-rdo\n$> rdopkg get-patches\n$> git cherry-pick YOUR_PATCH\n$> rdopkg review-patch\n

    Once the patch gets approved (not merged), you can tell rdopkg to update the distgit and send the .spec change for review:

    $> git checkout mitaka-rdo\n$> rdopkg patch\n$> rdopkg review-spec\n

    For more specific example, please see Introducing patches to RDO CloudSIG packages RDO blog post.

    "},{"location":"contribute/intro-packaging/#rebasing-on-new-version","title":"Rebasing on new version","text":"

    tl;dr rdopkg new-version should take care of that:

    $> git checkout mitaka-rdo\n$> rdopkg new-version\n

    or rdopkg new-version 1.2.3 to select specific version.

    Inspect resulting distgit commit and if you need to adjust anything, use rdopkg amend to amend and regenerate commit message from changelog.

    Finally, once happy with your change submit it for review with

    $> rdopkg review-spec\n
    "},{"location":"contribute/mentors.html/","title":"RDO Mentors","text":"

    It can sometimes be a little intimidating when you first start contributing to OpenStack. Most of the RDO related tickets are in the Jira and have a designated asignee, you may also wish to find a mentor based on the area that you're interested in working on.

    Or, when you arrive on IRC, and ask a question and are greeted with silence, it can be very useful to know who to ping to get their attention.

    The following people have indicated that they're willing to mentor you through your first contributions, or answer your questions on particular topics on IRC. Please don't hesitate to ask. (And, if you're willing to be on the list, please add your name and/or IRC nick below.)

    Finally, if you want to contribute to the upstream OpenStack community, there's a similar list called the OpenStack Upstream Institute.

    "},{"location":"contribute/mentors.html/#who-to-ask","title":"Who to ask","text":""},{"location":"contribute/mentors.html/#general","title":"General","text":"
    • Alfredo Moralejo \u2013 amoralej
    • Alan Pevec \u2013 apevec
    • Amy Marrich \u2013 spotz
    • Joel Capitao \u2013 jcapitao
    • Jon Schlueter \u2013 jschlueter/yazug
    • Karolina Kula \u2013 kkula
    "},{"location":"contribute/mentors.html/#installation","title":"Installation","text":"
    • Alfredo Moralejo \u2013 amoralej
    • Joel Capitao \u2013 jcapitao
    • Amy Marrich \u2013 spotz
    "},{"location":"contribute/mentors.html/#packaging","title":"Packaging","text":"
    • Alfredo Moralejo \u2013 amoralej
    • Joel Capitao \u2013 jcapitao
    • Karolina Kula \u2013 kkula
    "},{"location":"contribute/mentors.html/#infrastructure","title":"Infrastructure","text":"
    • Alfredo Moralejo \u2013 amoralej
    • Joel Capitao \u2013 jcapitao
    "},{"location":"contribute/mentors.html/#documentation","title":"Documentation","text":"
    • Amy Marrich \u2013 spotz
    "},{"location":"contribute/mentors.html/#where-to-ask","title":"Where to ask","text":"

    Conversations about RDO happen a number of different places on IRC. For a full list of IRC channels related to RDO, see the IRC section in Contribute to RDO.

    "},{"location":"contribute/new_release_guide/","title":"Step by step RDO release guide","text":"

    Creating a new release in RDO is a complex process with multiple dependencies. This overview provides users and contributors information on what leads up to a release and what detailed steps are to be performed before a new release. Not all steps are frozen in the sequence, but our experience shows that this is the most efficient way of working and some steps may be done in parallel.

    These steps follow the processes found in OpenStack releases - typically for the cycle-with-intermediary type of releasing - which is repeatable every 6 months. First there are provided non-client libraries, followed by client libraries, then services and lastly there are provided release-trailing deliverables.

    "},{"location":"contribute/new_release_guide/#1-create-cbs-tags-for-next-release","title":"1. Create CBS tags for next release","text":"

    At the very beginning, a new CBS tag for the next release should be created. This is needed before performing a switch to the new master. This operation is performed by creating a bug on pagure.io/centos-infra. An example can be found here.

    "},{"location":"contribute/new_release_guide/#2-create-a-dlrn-builder-for-the-new-openstack-release-in-rdo-trunk-servers","title":"2. Create a DLRN builder for the new OpenStack release in RDO Trunk servers.","text":""},{"location":"contribute/new_release_guide/#prepare-new-dlrn-trunk-builder","title":"Prepare new DLRN trunk builder.","text":"

    DLRN builder is an instance used to build RDO Trunk repos (follow articles about RDO Trunk repos and RDO CloudSIG repos). Before we start working on new packages, we have to set the builder. The first step is a change in rdo-infra/ansible-role-dlrn, where we define new repositories for the builder, as an example. The second step is to define the new builder in sf-infra. A patch to sf-infra will to depend on the previous one from ansible-role-dlrn.

    Before starting the building process, some steps have to be performed on the builder: 1. Create the database, users and tables 2. Set up authentication from trunk-centos8.rdoproject.org host to trunk.rdoproject.org 3. Synchronize deps

    "},{"location":"contribute/new_release_guide/#bootstrapping","title":"Bootstrapping","text":"

    Once the DLRN builder is ready, the bootstrap process can be started. This process is about building all DLRN packages in the proper sequence. Building is automated, but due to dependencies it may need to be restarted several times, and sometimes requires fixes in spec files.

    "},{"location":"contribute/new_release_guide/#enable-usual-operations-for-the-new-dlrn-trunk-builder","title":"Enable usual operations for the new DLRN Trunk builder","text":"

    The new builder, to be fully operated, needs to have enabled operations which were not possible before bootstrapping. Examples can be found in sf-infra and ansible-role-dlrn.

    This operation enables building new packages in the builders with any new commit in the projects (operated by cron), enables triggering automated gerrit reviews in case of FTBFS and sets the new builder visible on trunk.rdoproject.org website.

    "},{"location":"contribute/new_release_guide/#enable-distgit-cbs-builds-for-next-release-branch","title":"Enable distgit CBS builds for next release branch","text":"

    When reviews appear in the new release branch, appropriate jobs and builds have to be triggered.

    "},{"location":"contribute/new_release_guide/#3-requirement-check-reqcheck","title":"3. Requirement check - reqcheck","text":"

    Most of the projects we are packaging are constantly being developed on, so their requirements can change - added, removed, in the new version or constrained. This check is being done manually, using the rdopkg reqcheck tool. First libraries and client packages are rechecked, then the core packages (like openstack-nova).

    Even though the process seems to be not complicated, the appearing issues are often connected with missing dependencies. An example requirement check can be found here.

    "},{"location":"contribute/new_release_guide/#4-build-libs-clients-and-core-projects-in-cloudsig-repos-on-cbs","title":"4. Build libs, clients and core projects in CloudSIG repos on CBS.","text":"

    Once the requirement check is completes, the next step can be performed - building. To proceed with this, the new releases has to be created upstream. This step requires following steps:

    1. Cut rpm-master branch of distgit repo to create the \\<release>-rdo branch. This can be done with branching script from releng tooling, as an example, or manually by modifying config repo.
    2. Submit review with new version - a helpful script.
    "},{"location":"contribute/new_release_guide/#5-pin-branch-and-build-non-openstack-puppet-modules-in-cloudsig-repos","title":"5. Pin, branch and build non-OpenStack puppet modules in CloudSIG repos","text":"

    Non-OpenStack modules have to be pinned to the last promoted hash at branching time, since they don't follow the OpenStack lifecycle and RDO stable releases do not follow the master branches for them. The package has to be built based on the commit snapshot. This operation is done with the cooperation of the Puppet OpenStack team - these modules can be pinned after p-o-i team confirmation.

    1. Pin non OpenStack puppet modules, as example, using releng script.
    2. Cut branches, as in this review.
    3. Build, with releng script.
    "},{"location":"contribute/new_release_guide/#6-move-master-rdo-trunk-to-next-release-tags","title":"6. Move master RDO Trunk to next release tags","text":"

    Rdoinfo buildsys-tags and tags can be moved to the next-release after openstack/requirements is branched. As in review and review. This action has to be coordinated with the reviews mentioned in the \"Prepare new DLRN trunk builder\" section above.

    "},{"location":"contribute/new_release_guide/#7-branch-openstack-puppet-modules-and-build-them-in-cloudsig-repos","title":"7. Branch OpenStack puppet modules and build them in CloudSIG repos","text":"

    There is a bot which will automatically send the update reviews, when the tagged releases are created upstream. To trigger this step, we have to branch the distgit projects before the upstream p-o-i project creates the releases for the OpenStack puppet modules.

    "},{"location":"contribute/new_release_guide/#8-pin-branch-and-build-tempest-and-tempest-plugins-in-cloudsig-repos","title":"8. Pin, branch and build tempest and tempest plugins in CloudSIG repos","text":"

    Following steps are required to perform this operation:

    1. Branch and build the tempest package with bootstrap mode enabled, as here
    2. Disable the bootstrap mode without bumping release, to have other Openstack-tempest packages in RDO Trunk - example
    3. Cut branches, as in this review
    4. Pin tempest plugins in rdoinfo
    5. Review automatically created reviews
    6. Update version of tempest plugin project
    "},{"location":"contribute/new_release_guide/#9-create-the-puppet-promotion-pipeline","title":"9. Create the puppet promotion pipeline","text":"

    The Puppet promotion pipelines have to be defined as in patchset. Tests can be performed using testinfo. Newly defined jobs have to be assigned to the project - example.

    "},{"location":"contribute/new_release_guide/#10-create-the-next-release-branch-for-dependencies","title":"10. Create the next release branch for dependencies","text":"

    As development of dependencies is still ongoing, the new branch has to be prepared for featuring builds - as in this review.

    New branches have to be created in the upstream requirements repo to complete this task.

    "},{"location":"contribute/new_release_guide/#11-add-support-of-the-new-release-in-ansible-role-weirdo-puppet-openstack","title":"11. Add support of the new release in ansible-role-weirdo-puppet-openstack","text":"

    This is an example review of this operation.

    "},{"location":"contribute/new_release_guide/#12-create-the-rdo-release-rpm","title":"12. Create the rdo-release RPM","text":"

    Following step needs to be performed: 1. Create next release branch in distgit repo, as in example 2. Edit specification file 3. Trigger CBS build 4. Publish the RPM on repos.fedorapeople.org

    More details about used commands can be found in task description.

    "},{"location":"contribute/new_release_guide/#13-create-weirdo-jobs-to-promote-to-release-tag","title":"13. Create weirdo jobs to promote to -release tag","text":"

    The following jobs have to be defined in rdo-jobs repo. Such jobs will be triggered whenever promoting the package to -release tag.

    "},{"location":"contribute/new_release_guide/#14-add-the-new-release-to-dashboards","title":"14. Add the new release to dashboards","text":"

    Currently there are three dashboards to update with new release:

    1. rdo-dev dashboard
    2. Promotion dashboard
    3. FTBFS dashboard
    "},{"location":"contribute/new_release_guide/#15-create-the-new-centos-release-openstack-","title":"15. Create the new centos-release-openstack-

    To prepare for final release, the new release rpm has to be created for CentOS CloudSIG in extras9s-extras-common-el9s, and later tagged in extras9s-extras-common-testing, -release, and finally build.

    ","text":""},{"location":"contribute/new_release_guide/#16-promote-ga-builds-to-testing-and-release","title":"16. Promote GA builds to -testing and -release

    The final step to publish the next RDO release is performed by review as following one and another, which can be done only after completing previous step.

    ","text":""},{"location":"contribute/new_release_guide/#17-enable-remaining-monitoring-on-grafana","title":"17. Enable remaining monitoring on Grafana

    Also monitoring, other than dashboards, should be activated for the new release: Prometheus and Grafana.

    ","text":""},{"location":"contribute/new_release_guide/#18-unpin-non-openstack-puppet-modules-and-tempest-plugins-in-master-release","title":"18. Unpin non OpenStack puppet modules and tempest plugins in master release

    After the release, these projects can go back to active master. To do so, they have to be unpinned in rdoinfo.

    ","text":""},{"location":"contribute/onboarding/","title":"Let's Contribute to the RDO Project!","text":"

    Welcome on board! As a new contributor there are some things you'll want to do to get ready:

    "},{"location":"contribute/onboarding/#lets-get-prerequisites-ready","title":"Let's get prerequisites ready.","text":"
    • Join the RDO Mailing List
    • Join the IRC channel #rdo on OFTC
    • Create a GitHub account
    • Sign up to review.rdoproject.org
    • Add an SSH key to review.rdoproject.org
    • Create a RDO Jira Board account
    • Configure git and git review
    • Install the rdopkg tool
    "},{"location":"contribute/onboarding/#whats-next","title":"What's Next!","text":"
    • Make your first contribution
    • How to fix git Merge conflicts
    • Review RDO patches
    • Become an RDO package maintainer.
    "},{"location":"contribute/onboarding/#join-the-rdo-mailing-list","title":"Join the RDO Mailing List","text":"
    • Go to RDO mailing list and enter your email address and password and click on subscribe. Once done, open your mailbox, you will get a confirmation email, click on the verification link and you are subscribed to the RDO List.
    • You can introduce yourself by sending a mail to the mailing list. Tell us what your interests are and how you plan to participate.
    "},{"location":"contribute/onboarding/#join-the-irc-channel-rdo-on-oftc","title":"Join the IRC channel #rdo on OFTC","text":"
    • All the development and communication related to the RDO Project happens on the #rdo IRC channel on OFTC. Click this link to join the channel and feel free to say Hello! We are always there to help.
    • Feel free to check out the IRC etiquette guide.
    "},{"location":"contribute/onboarding/#create-a-github-account","title":"Create a GitHub account","text":"

    Go to the GitHub Sign Up page and enter your username, email address, and password, and you are done. If you already have a GitHub account, you can skip this step.

    "},{"location":"contribute/onboarding/#sign-up-to-reviewrdoprojectorg","title":"Sign up to review.rdoproject.org","text":"

    Sign-in to review.rdoproject.org using your GitHub account.

    "},{"location":"contribute/onboarding/#add-an-ssh-key-to-reviewrdoprojectorg","title":"Add an SSH key to review.rdoproject.org","text":"
    • Generate an SSH key, if you don't have one you already use. Follow these instructions on Generating a new SSH key if necessary.
    • Then, go to ssh-key and click on the \"Add Key\" button and copy the contents of id_rsa.pub (your SSH public key) and paste it there, and then click on the 'Add' button and you are done.
    "},{"location":"contribute/onboarding/#create-a-rdo-jira-board-account","title":"Create a RDO Jira board account","text":"

    All the bugs related to RDO packages are tracked on Red Hat Jira under the RDO project. OpenStack project bugs are tracked on Launchpad.

    • You can create a RDO Board account by clicking on the \"Log In\" button on the RDO Board page then following the \"Register for a Red Hat account\" link.

    "},{"location":"contribute/onboarding/#configure-git-and-git-review","title":"Configure git and git review","text":"
    • Run these steps to let git know your email address:
    $ git config --global user.name \"Firstname Lastname\"\n$ git config --global user.email \"your_email@youremail.com\"\n
    • To check your git configuration:
    $ git config --list\n
    • Install the git-review tool

    RHEL-based systems (e.g. CentOS Steam 8+ with EPEL repo enabled)

    $ sudo dnf install git-review\n

    Fedora-based systems (after F24)

    $ sudo dnf install git-review\n

    "},{"location":"contribute/onboarding/#install-the-rdopkg-tool","title":"Install the rdopkg tool","text":"

    Follow this link to install rdopkg, and you are set for making contributions to the RDO Project.

    "},{"location":"contribute/onboarding/#make-your-first-contribution","title":"Make your first contribution","text":"
    • The RDO Project has lots of easy fixes. Check out the RDO easyfix page, pick an issue, and feel free to move ahead.
    • Feel free to familiarize yourself with RDO Packaging documentation.
    • Clone the project.

    For example, cloning keystone-distgit, we need to pass the source code URL.

    $ git clone https://review.rdoproject.org/r/openstack/keystone-distgit\n

    You can also use rdopkg to clone an RDO package.

    $ rdopkg clone package-name\n
    • Go inside the project directory, create, and checkout a new branch. Note: Always create a new branch to work on any issue.
    $ cd <project_name>\n$ git checkout -b <issue name>\n
    • Make changes in the code and add the changed files to git.
    $ git add <changed files>\n
    • Commit the changes
    $ git commit -m \"Add the commit message\"\n

    You can check this link on how to write proper commit messages.

    • If something went wrong in the commit message, or you need to adjust it, run the following command:
    $ git commit --amend\n
    • Now push the changes for review using git-review.
    $ git review\n

    Running git review will create an RDO Gerrit review link, and someone from RDO project will review the changes. Once everything looks fine, and is approved, your changes will get merged, and you'll have made your first contribution. Thanks!

    "},{"location":"contribute/onboarding/#how-to-fix-git-merge-conflicts","title":"How to fix git Merge conflicts?","text":"

    You have submitted a patch and got merge conflict on your patch. You can check this link on how to resolving merge conflicts.

    "},{"location":"contribute/onboarding/#review-rdo-patches","title":"Review RDO patches","text":"
    • Reviewing other peoples patches is a good way to learn things.
    • You can start getting familiar with RDO by reviewing patches in the RDO Gerrit instance or by sending your own patches for existing packages.

    "},{"location":"contribute/onboarding/#become-an-rdo-package-maintainer","title":"Become an RDO package maintainer","text":"

    If you want to become a maintainer for one or more packages, you can request to be added to the core group for them by sending a review to rdoinfo as in this example.

    Being a maintainer for a package provides the ability to approve reviews for it (grants +2 and +W in Gerrit terms).

    "},{"location":"contribute/package-building-overview/","title":"Package building process \u2013 overview","text":"

    In the RDO Project, we maintain two kinds of repos: RDO Trunk repositories and RDO CloudSIG repositories. RDO Trunk repositories have no-deps Openstack packages, which contain client, core, libs, puppet and tempest packages, while CloudSIG packages are a set of packages built by CentOS Community Build System. For Centos9 Stream master Trunk (DLRN) packages are stored in trunks and CloudSIG packages ends up in CentOS mirror.

    During the cycle of a given OpenStack release, we have the following recurring activities:

    • New packages are created when needed.
    • Each package is rebuilt anytime a new commit is available in the repository upstream on the RDO Trunk builder.
    • If the package build fails, a review is automatically opened in our Gerrit review system, so the package maintainers can work on a fix.
    • Periodically, the latest repository where all packages had been successfully built goes through a number of CI jobs. If all jobs are successful, the repository is promoted, meaning it is considered as good enough for other upstream CIs to rely on it for their jobs.
    "},{"location":"contribute/package-building-overview/#what-is-dlrn","title":"What is DLRN?","text":"

    In simplest words, DLRN is a tool which builds packages. In automated way DLRN is building package every time when new commit is merged in observed upstream repos, creating individual, separated environment basing on code, distgit and rdoinfo repo. DLRN can be also used to manually debug failing packages.

    "},{"location":"contribute/package-building-overview/#ftbfs","title":"FTBFS","text":"

    If build succeeds, package appears in trunk. If fails, automatic FTBFS (Fail To Build From Source) review is created in gerrit, providing building logs and information which commit caused FTBFS, like in example. All FTBFS\u2019 have to be reviewed and fixed. Current FTBFS can be easily spotted on RDO dashboard. Other way to check statuses of last builds is checking Latest Build Reports, for example for Centos 9 master.

    "},{"location":"contribute/package-building-overview/#trunk-packages-branching-and-debugging","title":"Trunk packages \u2013 branching and debugging","text":"

    Each trunk distgit has multiple branches. Under development one is rpm-master and the stable ones are named \\<release>-rdo. The rpm-master branch has Version: and Release: fields filled with XXX, which are automatically replaced with proper values during the DLRN building process. In \\-rdo branch, those values are filled while cutting the branch: master -> stable/\\<release> during the release process. Having such situation, a different procedure of bug/FTBFS reproduction is needed."},{"location":"contribute/package-building-overview/#debugging-with-dlrn","title":"Debugging with DLRN","text":"

    Most reliable way to create a debugging or testing environment is Centos 9 container or vm usage. Steps to reproduce FTBFS:

    1. Clone DLRN repo:
            git clone https://github.com/softwarefactory-project/DLRN.git\n
    1. Follow setup procedure from README.

    2. Clone rdoinfo repository:

            git clone \"https://review.rdoproject.org/r/rdoinfo\"\n
    1. Edit projects.ini files with desired data. If you don\u2019t know how to reproduce a remote DLRN build, check logs from building in FTBFS review. Below you can see example of projects.ini preparation for Centos 9 master.
            sed -i 's%target=.*%target=centos9-stream%' projects.ini\n        sed -i 's%source=.*%source=master%' projects.ini\n        sed -i 's%baseurl=.*%baseurl=https://trunk.rdoproject.org/centos9/%' projects.ini\n        sed -i 's%tags=.*%tags=%' projects.ini\n
    1. Run DLRN command (example package name):
            dlrn --head-only --dev --local --verbose-build --package-name openstack-tacker --info-repo ../rdoinfo\n

    You can find more information and explanation of DLRN usage in the documentation.

    1. Edit the package distgit or package code directly if needed. Both of them are now created inside DLRN directory, like data/openstack-tacker_distro for distgit and data/openstack-tacker for code.

    2. Run dlrn command once again. You should now be able to see reproduced error.

    "},{"location":"contribute/package-building-overview/#dependencies","title":"Dependencies","text":"

    CloudSIG packages have different workflow of creating, maintaining and storing. They are finally placed in this repo. Describing CloudSIG packages, it is crucial to explain two packages building systems taking part in whole process. DLRN is for trunk packages, while for CloudSIG ones there are Koji and CBS. Whole package process building starts in Fedora. The packages exist in Fedora Package Sources repository, maintained by packagers an builded by Koji. If the package is needed in RDO project, it has to be rebuild for RDO. Process of building Fedora package for RDO using repo gating_script is well described in this document. Creating such review will effect with rebuilding package in CentOS Build System. On this level, there may occur some errors or misconfigurations, caused by different environment.

    "},{"location":"contribute/package-building-overview/#debugging-package-building-failures","title":"Debugging package building failures","text":""},{"location":"contribute/package-building-overview/#logs","title":"Logs","text":"

    After pushing your change to code review system, CI will trigger a bunch of tests on it and give results as vote or/and logs. If +1 is given by Zuul, everything went well. If -1 appears, it means that tests didn\u2019t pass, so debugging is needed.

    "},{"location":"contribute/package-building-overview/#find-cbs-task-number-in-your-zuul-job-output","title":"Find CBS task number in your Zuul job output","text":"

    First step is to check job logs. They are available after clicking on job name in Gerrit. Depending on which point of building failure happens, the true cause of it may be found in this job output or has to be found directly in CBS building job. In this example build failure reason can be found in Zuul job output, but in this one, the real reason has to be looked for in CBS logs, because Zuul jobs one doesn\u2019t provide anything useful. This is happening when the error doesn\u2019t refers to spec file, but the building process itself. The easiest way to find proper link to CBS build is to find \u201ctaskID\u201d word in job_output.txt, the result should looks like: Task console is: https://cbs.centos.org/koji/taskinfo?taskID=2800330. Note, that each job and each patchset has its own individual build number.

    "},{"location":"contribute/package-building-overview/#how-to-read-cbs-build-logs","title":"How to read CBS build logs?","text":"

    After going to the provided URL, general information about build will appear. The logs can be find by clicking on red hyperlink \u201cbuildArch\u201c. Provided output is placed in following files: * build.log * hw_info.log * mock_output.log * root.log * state.log

    If the error refers to dependencies, it will be placed in root.log. Also some errors may occur in other files, especially in build.log.

    "},{"location":"contribute/package-building-overview/#common-package-building-issues","title":"Common package building issues","text":"
    • Missing dependency

    In a root.log file: DEBUG util.py:444: No matching package to install: 'python3dist(xxx)' DEBUG util.py:444: Not all dependencies satisfied

    Solution: The dependency is not tagged yet in our repo or not available. Contact RDO maintainers to discuss adding a new dependency.

    • SPEC file syntax error

    • Infra issue (timeout)

    Solution: If there are timeouts in refreshing repo metadata or other steps, it\u2019s good idea to recheck tests, by typing comment \u201crecheck\u201d in Gerrit review.

    • failing %check phase Some unit tests failed during package building, like in example.

    Solution: Create testing environment and try to reproduce the error. Then, try to figure out and fix failing reason. It is possible to exclude failing test(s), but we only use that solution if it\u2019s strongly justified (like issue created in bugzilla or other bug tracker).

    • missing macro

    in build.log file: RPM build errors: /var/tmp/rpm-tmp.s6H1EG: line 32: fg: no job control error: Bad exit status from /var/tmp/rpm-tmp.s6H1EG (%generate_buildrequires) Bad exit status from /var/tmp/rpm-tmp.s6H1EG (%generate_buildrequires) Child return code was: 1

    Solution: add BuildRequires: pyproject-rpm-macros to build requirements.

    "},{"location":"contribute/packager/","title":"RDO Package Maintainer Guide","text":""},{"location":"contribute/packager/#documents-for-packagers","title":"Documents for packagers","text":"
    • RDO Packager onboarding guide
    • Package building process \u2013 overview
    • Introduction to packaging at RDO
    • RDO Packaging guidelines
    • Requirements management
    "},{"location":"contribute/packager/#package-maintainer-common-tasks","title":"Package Maintainer common tasks","text":"
    • Adding new packages to RDO
    • Retiring a package in RDO
    • Adding a new requirement
    • Updating a requirement
    • Fixing a FTBFS (failed to build from source)
    • Adding a patch
    "},{"location":"contribute/packager/#packager-tools","title":"Packager tools","text":"
    • rdopkg: swiss army knife for RDO packagers
    • rdoinfo: RDO packages metadata
    "},{"location":"contribute/rdo-packaging-guidelines/","title":"RDO OpenStack Packaging Guidelines","text":""},{"location":"contribute/rdo-packaging-guidelines/#introduction","title":"Introduction","text":"

    This document collects guidelines and practical tips

    "},{"location":"contribute/rdo-packaging-guidelines/#packaging-guidelines","title":"Packaging Guidelines","text":"

    RDO packages mostly follow Fedora Packaging Guidelines. There are two exceptions:

    • Override rules listed in this document.
    • Exceptions granted by RDO Packaging Group (e.g. bundling)

    A set of examples for spec and other useful files can be found in openstack-example-spec github repository. These files can be used as templates for new packages although some adjustments may be needed for each particular case.

    "},{"location":"contribute/rdo-packaging-guidelines/#package-naming-guidelines","title":"Package Naming Guidelines","text":"

    RDO packages mostly follow Fedora Package Naming Guidelines. On top of it to maintain consistency in package names across different sets of RDO packages we follow:-

    • For service package: name it like 'openstack-', ex. openstack-nova, openstack-cinder, etc.
    • For python library: name it like 'python-', ex. python-oslo-cache, python-novaclient, etc.
    • For puppet package: name it like 'puppet-', ex. puppet-nova, puppet-cinder, etc.
    • For tempest plugin: name it like 'python--tests-tempest', ex. python-heat-tests-tempest, python-mistral-tests-tempest, etc.
    • For ui package: name it like 'openstack--ui', ex. openstack-heat-ui, openstack-octavia-ui, etc.
    • For ansible role: name it like 'ansible-role-', ex. ansible-role-container-registry, ansible-role-chrony, etc.
    • For ansible collection: name it like 'ansible-collection-, ex. ansible-collection-containers-podman, etc.

      NOTE: In case of python packages, srpms names should be prefixed with 'python-' and sub packages with 'python2-' or 'python3-'.

      "},{"location":"contribute/rdo-packaging-guidelines/#rdo-guidelines","title":"RDO Guidelines","text":""},{"location":"contribute/rdo-packaging-guidelines/#systemd-packaging","title":"Systemd packaging","text":"
      • All services must be configured to allow automated restart
      Restart=[on-failure|always]\n
      • If a service depends on other for proper start, you can use the After= and optionally Requires= parameters in unit configuration file. An example of dependencies for neutron-openvswitch-agent service:
      After=syslog.target network.target network.service openvswitch.service\nRequires=openvswitch.service\n
      • The systemd package provides a set of rpm macros to handle systemd operations on %post, %preun and %postun (more details here).
      "},{"location":"contribute/rdo-packaging-guidelines/#python-packaging-guidelines","title":"python packaging guidelines","text":"
      • Remove requirements files used by pip to download dependencies from the network. That may hide missing dependencies or integration issues (e.g. a dependency package only available in an incompatible version)
        rm -rf {,tests-}requirements.txt\n
      • Use versioned python macros everywhere.
      "},{"location":"contribute/rdo-packaging-guidelines/#packages-requirements","title":"Packages requirements","text":"
      • Check your package dependencies with rdopkg reqcheck.

      • Versions for build requirements are not needed as the latest available version will be always installed at build time by the packaging tools.

      • Actual requirements for default or common configurations of services must be added as explicit requires.

      • Optional requirements for specific configurations must not be added as explicit requires.

      • When versioning of explicit requires is needed be aware that epoch is used in some RDO packages. In those cases remember to add the epoch in the required version as in:

      Requires:         python-oslo-config >= 2:2.6.0\n
      "},{"location":"contribute/rdo-packaging-guidelines/#configuration-files","title":"Configuration files","text":"
      • Use oslo-config-generator to generate configuration files.
      oslo-config-generator --config-file=config-generator/keystone.conf\n
      • Configuration files must be in /etc and not /usr/etc.
      "},{"location":"contribute/rdo-packaging-guidelines/#tests-packaging","title":"Tests packaging","text":"

      OpenStack projects provide different tests including unit tests and functional tests, typically using the tempest framework.

      • Core packages shouldn't include tests as are not required in runtime.

      • Unit tests should be included in a <package name>-tests-unit package that should depend on the test requirements.

      • Tempest tests should be included in a <package name>-tests-tempest package which should depend on the dependencies to run the provided tests. Note that some projects include tempest tests in the main project git repository (so tempest package would be a subpackage in the same spec file) while others use a separate git repository (so a specific distgit and spec will be needed).

      • <package name>-tests: includes all tests, and should be a virtual package requiring <package name>-tests-tempest and <package name>-tests-unit.

      "},{"location":"contribute/rdo-packaging-guidelines/#other-considerations","title":"Other considerations","text":"
      • To enforce consistency accross OpenStack services packages, use the following snippet to set upstream project name.
      %global service keystone\n

      RDO project provides different examples specs in openstack-example-spec for the different package types (OpenStack service, library, client, dashboard plugin, etc...). This examples can be used as templates for new packages being added to RDO repositories.

      "},{"location":"contribute/rdo-packaging-guidelines/#patches","title":"Patches","text":"

      RDO is and intends to remain a vanilla distribution of OpenStack. Our default policy is to refuse downstream patches, but RDO Packaging Group may grant exceptions on per-case basis

      • Feature patches: must be submitted upstream

      • Security patches: requires RDO Security team clearance.

      • FTBFS patches: requires peer review, and must be submitted upstream when possible.

      "},{"location":"contribute/release/","title":"Releasing","text":""},{"location":"contribute/release/#step-by-step-rdo-release-guide","title":"Step by step RDO release guide","text":"

      Here you can find detailed information about what are the steps we are doing one by one (with explanation) to create new RDO release. This documentation is basen on our Jira board.

      "},{"location":"contribute/release/#getting-ready-for-new-openstack-release","title":"Getting ready for new OpenStack release","text":"

      This document describes how RDO builds and publishes new packages both in RDO CloudSIG and RDO Trunk repos around new release.

      "},{"location":"contribute/requirements/","title":"Requirements management in RDO","text":""},{"location":"contribute/requirements/#introduction","title":"Introduction","text":"

      OpenStack services usually need some pieces of software which are not developed as part of the project. They are are general purpose libraries (typically python modules) or services used in some way to run or build OpenStack packages as databases, messaging brokers, etc...

      OpenStack requirements project defines the policies and processes to manage requirements in upstream projects from a global perspective.

      "},{"location":"contribute/requirements/#managing-openstack-requirements-in-rdo","title":"Managing OpenStack requirements in RDO","text":"

      RDO provides all requirements for packaged services in RPM format from their own repos, so that no software should be installed from external repositories. This packages can be provided by:

      • CentOS base repositories, which is the preferred source of packages whenever possible:

        • For CentOS Stream 9: BaseOS, AppStream, CRB and HighAvailability.
      • Other CentOS SIG repositories (Virtualization, Storage, NFV, etc...). When a required package is being maintained by other CentOS SIG, it will be reused for RDO repos.

      • RDO CloudSIG repositories. When a package is not available from previous repos, it will be provided in RDO repositores. Note that it's required that these packages exist previously in Fedora so that they can be rebuilt with minimal changes (if any).

      If you have questions or special requests, don't hesitate in contacting RDO using our mailing lists or #rdo channel on OFTC.

      "},{"location":"contribute/requirements/#adding-a-new-requirement-to-rdo","title":"Adding a new requirement to RDO","text":"

      When a new requirement is needed for an OpenStack project included in RDO, package maintainers must follow this workflow:

      Note that, typically new requirements are added only for the release of OpenStack under development, not for stable releases, although they may be accepted in previous releases if it's properly justified. Also, as we're currently maintaining releases on CentOS Linux 7, CentOS Stream 8 & 9, there are particularities in adding new requirements for each of them.

      1. If the project follows global-requirements processes, make sure that the requirement has been added to global-requirements.txt and upper-constraints.txt files as described in the upstream documentation

      2. Check if the new requirement is present in CentOS base channels. The easiest way to do this is using 'repoquery' command from a system running RPM based OS(CentOS/RHEL/Fedora):

        # For CentOS Stream 9:\nrepoquery --repofrompath=tmp,http://mirror.stream.centos.org/9-stream/BaseOS/x86_64/os \\\n--repofrompath=tmp2,http://mirror.stream.centos.org/9-stream/AppStream/x86_64/os \\\n--repofrompath=tmp3,http://mirror.stream.centos.org/9-stream/CRB/x86_64/os \\\n--repofrompath=tmp4,http://mirror.stream.centos.org/9-stream/HighAvailability/x86_64/os \\\n--disablerepo=* --enablerepo=tmp* \"*<dependency>\"\n\n# For CentOS Stream 8:\nrepoquery --repofrompath=tmp,http://mirror.centos.org/centos/8-stream/BaseOS/x86_64/os \\\n--repofrompath=tmp2,http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os \\\n--repofrompath=tmp3,http://mirror.centos.org/centos/8-stream/PowerTools/x86_64/os \\\n--repofrompath=tmp4,http://mirror.centos.org/centos/8-stream/HighAvailability/x86_64/os \\\n--disablerepo=* --enablerepo=tmp* \"*<dependency>\"\n

        If it's present, the desired package is already available to RDO users.

      3. If the package is not in CentOS base repos, you can check if it has been already built by the CloudSIG using rdopkg:

        rdopkg findpkg <package name>\n

        as, for example:

        $ rdopkg findpkg python-eventlet\nname: python-eventlet\nproject: python-eventlet\nconf: fedora-dependency\nupstream: https://src.fedoraproject.org/rpms/python-eventlet\npatches: None\ndistgit: http://review.rdoproject.org/r/deps/python-eventlet.git\nbuildsys-tags:\n  cloud7-openstack-ocata-release: python-eventlet-0.18.4-2.el7\n  cloud7-openstack-ocata-testing: python-eventlet-0.18.4-2.el7\n  cloud7-openstack-pike-release: python-eventlet-0.20.1-2.el7\n  cloud7-openstack-pike-testing: python-eventlet-0.20.1-2.el7\n  cloud7-openstack-queens-release: python-eventlet-0.20.1-6.el7\n  cloud7-openstack-queens-testing: python-eventlet-0.20.1-6.el7\n  cloud7-openstack-rocky-release: python-eventlet-0.20.1-6.el7\n  cloud7-openstack-rocky-testing: python-eventlet-0.20.1-6.el7\n  cloud7-openstack-stein-release: python-eventlet-0.24.1-3.el7\n  cloud7-openstack-stein-testing: python-eventlet-0.24.1-3.el7\n  cloud7-openstack-train-release: python-eventlet-0.25.1-1.el7\n  cloud7-openstack-train-testing: python-eventlet-0.25.1-1.el7\n  cloud8-openstack-train-release: python-eventlet-0.25.2-3.1.el8\n  cloud8-openstack-train-testing: python-eventlet-0.25.2-3.1.el8\n  cloud8-openstack-ussuri-release: python-eventlet-0.25.2-3.el8\n  cloud8-openstack-ussuri-testing: python-eventlet-0.25.2-3.el8\n  cloud8-openstack-victoria-candidate: python-eventlet-0.25.2-3.el8\n  cloud8-openstack-victoria-release: python-eventlet-0.25.2-3.1.el8\n  cloud8-openstack-victoria-testing: python-eventlet-0.25.2-3.1.el8\n  cloud8s-openstack-train-testing: python-eventlet-0.25.2-3.1.el8\n  cloud8s-openstack-ussuri-release: python-eventlet-0.25.2-3.1.el8\n  cloud8s-openstack-ussuri-testing: python-eventlet-0.25.2-3.1.el8\n  cloud8s-openstack-victoria-release: python-eventlet-0.25.2-3.1.el8\n  cloud8s-openstack-victoria-testing: python-eventlet-0.25.2-3.1.el8\n  cloud8s-openstack-wallaby-release: python-eventlet-0.30.0-1.1.el8\n  cloud8s-openstack-wallaby-testing: python-eventlet-0.30.0-1.1.el8\n  cloud8s-openstack-xena-candidate: python-eventlet-0.31.1-1.el8\n  cloud8s-openstack-xena-release: python-eventlet-0.31.1-1.el8\n  cloud8s-openstack-xena-testing: python-eventlet-0.31.1-1.el8\n  cloud8s-openstack-yoga-testing: python-eventlet-0.31.1-1.el8\n  cloud9s-openstack-wallaby-testing: python-eventlet-0.30.2-1.el9s\n  cloud9s-openstack-xena-testing: python-eventlet-0.31.1-1.el9s\n  cloud9s-openstack-yoga-testing: python-eventlet-0.31.1-1.el9s\ncentos-distgit: https://git.centos.org/rpms/python-eventlet\nmaster-distgit: http://review.rdoproject.org/r/deps/python-eventlet.git\nreview-origin: null\nreview-patches: null\ntags:\n  dependency: null\nmaintainers:\n- amoralej@redhat.com\n- jcapitao@redhat.com\n- ykarel@redhat.com\n

        Note that the version of the package included in repositories is given by the CBS tags applied to each package (shown under buildsys-tags section for each package). Tags have a format cloud9s-openstack-<release>-<phase> where:

        • release: is the OpenStack release name, as Wallaby, Xena or Yoga.
        • phase:
        • candidate phase is assigned to packages to be rebuilt in CBS but not pushed to any RDO repository.
        • el<centos_version>-build is assigned to packages that only required to build other packages but are not a runtime requirement for any other package. (e.g centos_version can be '9s' or '8')
        • testing phase means that the package is used in deployments using RDO Trunk repo and published in a testing repo, but not official CloudSIG repository.
        • release phase means that is published in the official CloudSIG repository. This phase is only available after a RDO version has been officially released not for the one currently under development.

        For example, the package included in cloud8s-openstack-xena-release will be published in the CloudSIG repo for xena. The CBS tags flow will be: - Runtime requirements: candidate -> testing -> release - Build requirements: candidate -> el8-build or el9s-build

        Note that, for the release currently under development (Yoga right now), testing and el9s-build phase will be available. The package included in cloud9s-openstack-yoga-testing will be the one used to deploy from RDO Trunk Master repositories and it will be automatically pushed to cloud9s-openstack-yoga-release at RDO Yoga is officially released and published.

        If the package is found for the required CBS tag, it's already in RDO repositories and no more actions are needed to add it to the repos.

      4. In case that the dependency is not in CentOS base or CloudSIG repo, you can check if it has been built by other SIGs in CBS web interface. You can use wildcards in the packages search expression. If you find the desired dependency, you can open a ticket in RDO Jira board requesting the inclusion of the package in RDO repos. RDO Core members will handle the request.

      5. If the new package is not in CBS, you must check if it's packaged in Fedora using the Koji Web Interface. If the package exists, you need to open a review to rdoinfo project in RDO gerrit instance.

        For CentOS Stream 8 and 9, you need to add the new dependency to deps.yml file as in this example:

        # in deps.yml\n- project: python-ssh-python\n  name: python-ssh-python\n  conf: fedora-dependency\n

        For CentOS Stream 8 only, you also need to add buildsys-tag in buildsys-tags/cloud8s-openstack-yoga-candidate.yml

        # in buildsys-tags/cloud8s-openstack-yoga-candidate.yml\n- project: python-ssh-python\n  buildsys-tags:\n    cloud8s-openstack-yoga-candidate: python-ssh-python-0.9.0-1.el8\n

        Where: - project and name must be the name of the main package (the same as in fedora). - conf must be fedora-dependency. - In buildsys-tags section a new line for the candidate tag in the OpenStack release in development (cloud8s-openstack-yoga-candidate) with the required NVR (name-version-release), which must be the same one found in Fedora replacing fcXX part in release by el8. For example, for python-ssh-python the build is python-ssh-python-0.9.0-1.fc36, so in buildsys-tags/cloud8s-openstack-yoga-candidate.yml, cloud8s-openstack-yoga-candidate must point to python-ssh-python-0.9.0-1.fc36.

        Once merged this review will be enough to rebuild the Fedora package in the CentOS Build System for CentOS Stream 8.

        For CentOS Stream 9, a few more steps are required to be able to rebuild the patch in CentOS Build System. After the review in rdoinfo repo is merged, some changes in config need to be done in the config which will be automatically triggered. You can check when the distgit for the new dependency is created by monitoring if it appears in https://review.rdoproject.org/r/admin/repos/deps/.

        Once the repo is available, you can propose a review to build the package. We have a tool which does the work: setup_distgit.sh

        $ git clone https://review.rdoproject.org/cgit/gating_scripts\n$ cd gating_scripts\n$ bash -x setup_distgit.sh google-benchmark google-benchmark-1.6.0-1.fc36 yoga 9s\n$ cd workdir/<project_name>\n$ git diff\n

        Basically, the script clones the new repo, downloads the Fedora build and dispatches SPEC and sources files to the right place.

        If you\u2019re ok with the change, submit it. Note: this last step is for CentOS Stream 9 only.

        This review will rebuild the Fedora package in the CentOS Build System for CentOS Stream 9 and make it available to be pushed to the next CBS phase.

      6. When the packages doesn't exist even in Fedora you need to add the package following the New package process. Note that a Fedora packager needs to participate in this process. While RDO core members may maintain the new package for common requirements used by different projects, dependencies for specific project must be maintained in Fedora by the project team. Once the package is included in Fedora repos you can create a gerrit review as explained in step 5.

      7. Once the package is rebuilt in CBS (review in step 5 is merged) you can push it to the next phase, this means testing (for runtime dependencies) or el9s-build (for build-time dependencies). This is done by sending a new review to rdoinfo project adding a new line under buildsys-tags to both buildsys-tags/cloud9s-openstack-yoga-testing.yml and buildsys-tags/cloud8s-openstack-yoga-testing.yml file for the new tag as in this example:

        # in buildsys-tags/cloud8s-openstack-yoga-testing.yml\nbuildsys-tags:\n  cloud8s-openstack-yoga-testing: python-stestr-3.2.0-3.el8\n\n# in buildsys-tags/cloud9s-openstack-yoga-testing.yml\nbuildsys-tags:\n  cloud9s-openstack-yoga-testing: python-stestr-3.2.0-3.el9s\n

        Once this review is merged, the tag will be applied to this build and the package will be added to the testing repo for Yoga (note that some delay, up to 30 minutes is expected).

      8. After the package is available in the repos, you can add it to the list of Requires or BuildRequires in your package spec file. Note that optional dependencies not used in default or common configurations should not be added as Requires but installed only when needed.

      9. "},{"location":"contribute/requirements/#updating-a-requirement-in-rdo-cloudsig-repositories","title":"Updating a requirement in RDO CloudSIG repositories","text":"

        There are some rules to follow when a requirement update is needed by a OpenStack project. Following diagram summarizes the considerations to update the dependencies in RDO.

        If the dependency is included in upstream OpenStack global requirements project, the required version should be equal (exceptions will be shown below) to the version in upper-constraints file for the appropiate OpenStack release (requirements project has stable/\\ branches). For the master branch, RDO provides a report to quickly check the state of dependencies compared to upper-constraints."},{"location":"contribute/requirements/#packages-provided-in-centos-stream-os-repos","title":"Packages provided in CentOS Stream OS repos","text":"

        • For packages provided in CentOS Stream OS repos, the preferred option is to consume those packages from OS whenever possible, even if versions are below the ones in upper-constraints.txt file. If OpenStack requires newer versions of those packages to work properly (for example, an OpenStack project requires a minimal version of the dep which is newer that the one in CentOS) there are two options:
        • Request a package update in CentOS by opening a bug in RHEL product. This bug will be evaluated following the RHEL process.
        • Add it to RDO repository following the process described in Adding a new requirement to RDO. Note that this may impact other packages using it in the Operating System so this option should be minimized.
        "},{"location":"contribute/requirements/#packages-not-provided-in-centos-stream-os-repos","title":"Packages not provided in CentOS Stream OS repos","text":"
        • The required dependencies not included in the CentOS OS are provided in the RDO repos. Before updating a dependency in RDO, the package must be updated to the required version in Fedora. If it has not been updated first you can:
        • Contact Fedora package maintainer or search for open bug against component, example component:python-migrate, if bug does not exist, open a bug for Fedora product requesting the update.
        • Or you can directly propose to update fedora package by creating your own pull request, following Fedora packaging guide and Fedora CI - Pull Requests. Once the pull request merged, the package must be built by its maintainer. Building Fedora\u2019s packages can be monitored on Koji.

        • Once the package is build in Fedora, you can update the requirement in RDO. For CentOS Stream 9, you need to rebuild the package first by sending a review to the RDO Gerrit instance in the distgit project deps/<package name> in the branch c9s-<openstack version>-rdo. RDO provides the script setup_distgit.sh to ease the preparation of the dependency update review by importint content from Fedora. i.e. if you need to update python module foo to version 1.0.0 in OpenStack Zed and the package is ready in fedora as python-foo-1.0.0-1.fc37 you should execute:

          $ git clone https://review.rdoproject.org/cgit/gating_scripts\n$ cd gating_scripts\n$ bash -x setup_distgit.sh python-foo python-foo-1.0.0-1.fc37 zed 9s\n$ cd workdir/python-foo\n$ git diff\n

          Basically, the script clones the new repo, downloads the Fedora build and dispatches SPEC and sources files to the right place.

          If you\u2019re ok with the change, commit it and send the review. Note that, in some cases, changes are required to build fedora packages for CentOS. It is usually a good idea to test new package with mock or rpm-build.

        • Once the patch in deps/<dependency> is merged, the package is built and tagged in CBS but will not be available in the RDO repositories. The next step is to include the package in RDO Testing repo for the appropiate OpenStack release. This is done by sending a patch to the rdoinfo project, adding it to the file buildsys-tags/cloud9s-openstack-<openstack release>-testing like this example.

        • Once the package exist in testing tag it will be available in the RDO Trunk repositories to be used in jobs or update in rpm spec. For stable releases (non master) an automatic task will also propose review to rdoinfo to upddate the package the corresponding release tag in the same OpenStack release in rdoinfo repo. Once that patch is merged, the update will also appear in the CloudSIG official CentOS mirror.

        "},{"location":"contribute/requirements/#contact-us","title":"Contact us","text":"

        If you have questions or special requests about requirements, don't hesitate to contact RDO community members using our mailing lists or #rdo channel on OFTC.

        "},{"location":"contribute/retire-packages/","title":"Retiring a package from RDO","text":""},{"location":"contribute/retire-packages/#what-does-retiring-a-package-means","title":"What does retiring a package means","text":"
        • The package will not be build and published to RDO Trunk repo
        • The package will not be build in CBS and published to next CloudSIG repo

        NOTE: The package can be retired only from the current development release.

        "},{"location":"contribute/retire-packages/#how-to-remove-an-openstack-package-from-rdo-trunk","title":"How to remove an OpenStack package from RDO Trunk","text":"

        Package for a project can exist across different releases. So retiring it in RDO needs to go via stages.

        To remove a package, following steps are required:-

        Stage 1:- Project Source is retired/deleted upstream, but it's package still need to be maintained because it's required by other projects

        • Send a review to rdoinfo like Example review to pin(add source-branch: <good commit>) the project against the tag or commit, so package get's build from pinned commit rather than latest commit(deleted source code).

          ```

        • Send a review to config project like Example review to run DLRN-pinned jobs(legacy-DLRN-rpmbuild-pinned, legacy-DLRN-rpmbuild-fedora-pinned) so package get's build from pinned commit rather than from latest, This is required so that spec changes can be done like https://review.rdoproject.org/r/#/c/20383/.

        Stage 2:- Package is no longer needed by other projects:-

        • Send a review to rdoinfo project in review.rdoproject.org. In this change you need to delete the tag for the project for which package is not needed to built.

        Once the change is merged in rdoinfo, package will no longer exist in RDO trunk repo, but it will still be built for previous releases(for which tag is defined in rdoinfo):- RDO Trunk repos.

        "},{"location":"contribute/retire-packages/#need-to-add-source-branch-like-below","title":"Need to add source-branch like below","text":"
        • project: oslo-sphinx tags: train-uc: source-branch: f92583cfc34292ec1441368f984c9692346946c4 ```
        "},{"location":"deliverables/","title":"What we deliver?","text":"

        This section contains information what and how RDO is releasing. Also you can find here description and differences of deliverables documented and find out, how the process of releasing looks like.

        "},{"location":"deliverables/general_concept_comparison/","title":"Overview and comparison of RDO's deliverables","text":"

        The RDO project has turning around two main concepts of deliverables: packages and repositories. Differences between them and their purpose may be confusing, so this documents is created to summarize the knowledge and emphasise divergences to help fully understand them.

        "},{"location":"deliverables/general_concept_comparison/#packages","title":"Packages","text":"

        Packages in RDO are the most atomic unit in RDO and there are basically two kinds of them:

        • OpenStack RDO packages (i.e. openstack-nova, openstack-neutron, python-osprofiler)
        • dependencies (i.e. python-hatchling, python-eventlet)

        Both types of package have distgits (repositories containing spec files) in common, as necessary part of package building process.

        The table below shows main characteristic of each kind of package.

        OpenStack RDO packages dependencies 1. Code comes from upstream OpenStack project Code comes from any upstream project 2. Created in RDO Comes from Fedora 3. Build by DLRN (Trunks) or CentOS CBS (CloudSIG) Build by CentOS Community Build Service

        The first row of the table compares the origin of each kind of package.

        The second row describes how packages land in RDO projects. In other words, each dependency's distgit has to be present in Fedora first, while distgits for OpenStack packages are created by package maintainers, as in this example review.

        The third row compares how packages are built.

        These two kinds of packages are what composes the RDO repositories, in addition RDO project also takes part in maintaining and developing Fedora OpenStackSIG packages. The purpose of this special interest group is to maintain and ship latest packages such as: OpenStack clients, libraries and dependencies in Fedora.

        "},{"location":"deliverables/general_concept_comparison/#repositories","title":"Repositories","text":"

        In RDO we deliver two types of repositories:

        • RDO Trunks
        • RDO CloudSIGs

        Each of them is managed and delivered in different way. Both of them are composed from OpenStack packages and dependencies, but they are shipped differently.

        RDO Trunks RDO CloudSIGs 1. build by DLRN build by CentOS Community Build Service 2. new package with every new commit new package with every new tag released upstream 3. Delivered very close in time after new commit Delivered in days 4. Fetch source code through involved repo Fetch tarball for point release 5. Continuous delivery of master branch Repo released after OpenStack GA 6. Unsigned packages Signed packages 7. Delivered in trunk.rdoproject.org server Delivered in official Centos mirrors in CloudSIG"},{"location":"deliverables/general_concept_comparison/#building","title":"Building","text":"

        The first row shows that each repository is build by different system. All trunk repos are created and managed by DLRN, while CloudSIGs is managed by CBS.

        "},{"location":"deliverables/general_concept_comparison/#handling-new-packages","title":"Handling new packages","text":"

        The second and third row compare ways of handling new packages. In trunks, any time a new commit is merged in upstream project, the package building process is triggered and new repositories containing this package are published, so the time of publishing new deliverable is very short. For RDO CloudSIGs the process in slightly longer, because publishing new repo is happening when new tag is released in upstream, as in example review.

        "},{"location":"deliverables/general_concept_comparison/#origin-of-sources","title":"Origin of sources","text":"

        Package process building is fetching project source code directly from repository, while RDO CloudSIGs are basing on tarballs.

        "},{"location":"deliverables/general_concept_comparison/#frequency-of-releasing","title":"Frequency of releasing","text":"

        Trunk repositories are constantly following master branch for all projects, so new packages and repositories are delivered in continuous way. RDO CloudSIGs are released only after OpenStack GA.

        "},{"location":"deliverables/general_concept_comparison/#security","title":"Security","text":"

        Trunks contains only unsigned packages on the contrary to RDO CloudSIGs.

        "},{"location":"deliverables/general_concept_comparison/#distribution","title":"Distribution","text":"

        Trunks are distributed by trunk servers. RDO CloudSIGs are delivered in official Centos mirrors.

        "},{"location":"deliverables/how-to-install-rdo-repo/","title":"How to install RDO repositories","text":"

        TBD

        "},{"location":"deliverables/release-cadence/","title":"Release cadence","text":""},{"location":"deliverables/release-cadence/#rdo-packaging-release-cadence","title":"RDO packaging release cadence","text":"

        This page describes the release cadence of RDO packages in relation to different community distributions, giving an approximate idea of community support status of any given OpenStack release.

        "},{"location":"deliverables/release-cadence/#centos-versions","title":"CentOS Versions","text":"

        Due to the slower release cadence of RHEL and therefore CentOS, only the most recent release plus the previous one are supported, in keeping up with upstream policy. Older versions of the operating system such as CentOS 7 do not receive later releases.

        When there is a new major CentOS release, the following OpenStack version is packaged for both for the new and the previous version of CentOS. The purpose of this policy is to ease the trasition between them.

        "},{"location":"deliverables/release-cadence/#maintained-rdo-versions-in-cloudsig-repos","title":"Maintained RDO versions in CloudSIG repos","text":"

        RDO CloudSIG repositories are based on tag releases provided by OpenStack project. According to the definition of maintenance phases of OpenStack, RDO will not update CloudSIG repos after a release is transitioned to Extended Maintenance status.

        Current maintained CloudSIG releases are:

        CentOS Stream 9 Caracal supported CentOS Stream 9 Bobcat supported CentOS Stream 9 Antelope supported CentOS Stream 9 Zed unmaintained"},{"location":"deliverables/release-cadence/#maintained-rdo-versions-in-rdo-trunk-repos","title":"Maintained RDO versions in RDO Trunk repos","text":"

        In order to provide patches merged in OpenStack releases in Extended Maintenance state, RDO mantains RDO Trunk repositories following stable branches or pinned releases until they are EOL.

        Currently, RDO maintains following RDO Trunk repositories:

        CentOS Stream 9 Bobcat supported CentOS Stream 9 Antelope supported CentOS Stream 9 Zed unmaintained CentOS Stream 9 Yoga unmaintained CentOS Stream 9 Xena unmaintained CentOS Stream 9 Wallaby unmaintained"},{"location":"deliverables/release-cadence/#rhel-compatibility","title":"RHEL compatibility","text":"

        Although it is expected that RDO works fine in Red Hat Enterprise Linux (RHEL) OS, it is currently not tested on it. Note that CentOS Stream is a continuosly delivered distribution that tracks just ahead of RHEL and differences between both distributions at a certain point are expected.

        • What is CentOS Stream?
        "},{"location":"deliverables/release-cadence/#fedora","title":"Fedora","text":"

        The RDO team, in coordination with the Fedora OpenStack SIG maintains the OpenStack Clients in Fedora repositories.

        • Fedopra OpenStack SIG
        "},{"location":"deliverables/release-cadence/#references","title":"References","text":"
        • OpenStack Releases
        "},{"location":"deliverables/repos/","title":"Overview of available RDO repos","text":"

        There are a number of different repos that the RDO project works out of. This is an overview of each of them.

        NOTE: Overview and comparison of RDO's deliverables can be found in this article.

        "},{"location":"deliverables/repos/#rdo-cloudsig-repositories","title":"RDO CloudSIG repositories","text":"

        Provide a set of stable OpenStack packages through CentOS CloudSIG repos based on CBS, CentOS Community Build System:

        • The RDO CloudSIG repos are only published after GA of a upstream release (only stable branches are used, not master).
        • New packages are created only when a new point release is published (release tag created) on upstream stable repositories.
        • In addition to the vanilla upstream code, some patches may be applied during packaging:
        • Fixes for security issues or critical bugs not backported upstream. Note that an upstream-first policy is applied so these patches will be applied only after merged in upstream master.
        • Patches required for the packaging process.

        For each OpenStack release RDO provides two repos:

        "},{"location":"deliverables/repos/#cloudsig-ga-repo","title":"CloudSIG GA repo","text":"

        The GA repository is the one you should be using for your production environment. It contains tested, digitally signed packages.

        To enable this repository on a CentOS system, run the following command:

        For CentOS Stream 9:\n$ sudo dnf install centos-release-openstack-<release>\n

        Where <release> is the name of the OpenStack release you want to install. The RDO community supports the same OpenStack releases supported by upstream.

        On a non-CentOS system (e.g. RHEL), you can run the following command to setup the RDO GA repositories:

        For CentOS Stream 9:\n$ sudo dnf install https://www.rdoproject.org/repos/rdo-release.el9.rpm\n

        This will configure the repositories for the most recent version of RDO. RPMs for previous releases are accessible from this location.

        "},{"location":"deliverables/repos/#cloudsig-testing-repo","title":"CloudSIG Testing repo","text":"

        The testing repository contains packages that have not gone through our complete test suite. These packages can be useful to test newer versions of the code, or when you need to quickly deliver a hotfix to your production environment. Please keep in mind that packages from the testing repository are not digitally signed.

        If you enabled the RDO repositories using the centos-release-openstack-* RPM, run the following command to enable the testing repository:

        $ sudo yum-config-manager --enable centos-openstack-<release>-test\n

        If you used the rdo-release RPM, run the following command:

        $ sudo yum-config-manager --enable openstack-<release>-testing\n
        "},{"location":"deliverables/repos/#comparison-of-cloudsig-ga-repo-and-testing-repo","title":"Comparison of CloudSIG GA repo and testing repo","text":""},{"location":"deliverables/repos/#rdo-trunk-repositories","title":"RDO Trunk repositories","text":"

        RDO Trunk repositories are built using the most recent commit from each of the OpenStack projects. They are used in different ways:

        • By several OpenStack CI jobs, to test packages built from the current under-development branch.
        • Internally by the RDO community, to ensure that our packaging pipeline is always up to date.
        • They can also be used to deliver hotfixes for stable releases, as soon as the relevant patch has been merged in the upstream repos.

        The RDO Trunk packages are not digitally signed, and have gone through some minimal CI. You can enable the CI-passed RDO Trunk repo using the following command:

        $ sudo yum-config-manager --enable rdo-trunk-newton-tested\n

        If you need a package using the latest commit, even before it passes CI (be aware this is bleeding edge!), go to the RDO Trunk web.

        "},{"location":"deliverables/trunk-repos/","title":"RDO Trunk repos","text":"

        RDO Trunk repositories are built using the most recent commit(or from the pin to a commit/tag/branch if source-branch is set for a release in rdoinfo) from each of the OpenStack projects defined for a release. We host the RDO Trunk repositories at https://trunk.rdoproject.org/. On that server, you will find several repositories:

        • CentOS Stream 9 master, using versions from upper-constraints
        • CentOS Stream 9 stable releases for the currently supported versions

        These repos contain packages build for each OpenStack project defined for a particular release in rdoinfo. This mapping of repo and release is as follows:-

        • CentOS Stream 9 master, using versions from upper-constraints with current release rdoinfo tag i.e zed-uc
        • CentOS Stream 9 stable releases for the currently supported versions with stable release rdoinfo tag other than current release zed-uc
        "},{"location":"deliverables/trunk-repos/#the-upper-constraints-based-repositories","title":"The upper-constraints based repositories","text":"

        The gate jobs for each OpenStack project use a common set of dependencies, defined by the requirements repository. One of the files on that repository is upper-constraints.txt, which contains the supported version for each library on each OpenStack release.

        Why is this file important? It defines an upper cap for every gate job, meaning those are the versions all OpenStack projects are being tested against. For example, if the specified version for python-novaclient in the file is X.Y.Z, we can safely assume that this version will work fine for all projects, but we cannot say the same for any commit beyond that point.

        This is also important when packaging, because we want our generated repositories to be usable by upstream CIs, so we need to provide a set of packages that matches the versions available in the upper-constraints.txt file. For this reason RDO builds all libraries and clients from the latest versions in upper-constraints.txt, and every other project is built from the master or stable branch.

        "},{"location":"deliverables/trunk-repos/#hashed-repos-and-special-repos","title":"Hashed repos and special repos","text":"

        When each new upstream commit is built, a repository is created with the new package and the latest versions from every other package built by RDO Trunk. This new repository is located in a hashed URL. This URL is built using:

        • The hash of the commit for the project that triggered the build. I'll take as example, commit 5848c0dd from openstack-neutron, long hash is 5848c0dd1c951e916c0b769f711d8aafa6aa72b1.
        • The short hash of the distgit repo for the project. In the same example, it is commit 21f87ec3 from the neutron-distgit repo which was the latest commit when the neutron patch was merged.
        • The component for the package. For each project, a component is defined in rdoinfo openstack packages file. For neutron the component is network (you can find it easily with rdopkg info tool).

        With that info we can figure out the repo URL:

        https://trunk.rdoproject.org/centos9-master/component/network/58/48/5848c0dd1c951e916c0b769f711d8aafa6aa72b1_21f87ec3/

        Note the pattern:

        https://trunk.rdoproject.org/centos<centos version>-<release>/component/<component name>/<1:2 code hash>/<3:4 code hash>/<long code hash>_<short distgit hash>/

        Besides hashed repositories, we have some special directories, created as symlinks to hashed repos:

        • current points to the repository with contains the last successfully built package from every project.
        • consistent points to the latest repository where none of the packages have current build failures.
        • current-passed-ci points to the last consistent repository that passed all the promotion CI tests.

        "},{"location":"deploy/","title":"RDO OpenStack deployment","text":"

        There have always been multiple ways of deploying OpenStack. In RDO we are using some of them. Before starting your RDO deployment, make sure you understand the different repo flavors and releases that RDO is providing by reading our deliverables documentation.

        "},{"location":"deploy/#packstack","title":"Packstack","text":"

        For an initial test deployment, follow the Packstack instructions. While using Packstack is sufficient as a proof of concept, there are other ways that you can use to deploy OpenStack with RDO.

        "},{"location":"deploy/#puppet-openstack-integration","title":"Puppet OpenStack Integration","text":"

        Puppet OpenStack modules provide puppet-based per-service modules intended to provide automation to OpenStack cloud deployments based on Puppet automation engine. More about can be found in official documentation. RDO provides rpms for puppet modules and continuously test and validate its packages and repos using puppet-openstack-integration CI repository.

        "},{"location":"deploy/#openstack-ansible","title":"OpenStack Ansible","text":"

        This project has partial support for RDO as provider for binary installations in CentOS, hovewer it's not tested in our CI. Main documentation can be find here, there is also available a deployment guide.

        "},{"location":"deploy/#rdo-on-okd-experimental","title":"RDO on OKD - experimental","text":"

        Deployment of OpenStack based on OKD, The Community Distribution of Kubernetes, where OpenStack management is handled through a new podified control plane (a set of tools for deploying and managing an OpenStack control plane as Kubernetes-native pods). You can read documentation and instructions about RDO on OKD Proof of Concept, which is a part of CentOS CloudSIG. Also you can watch RDO's presentation which is explaining that concept in details.

        "},{"location":"deploy/#tools-used-in-rdo","title":"Tools used in RDO","text":"
        • DLRN: What it is, what we use it for
        • SoftwareFactory
        "},{"location":"deploy/packstack/","title":"TBD: update this article","text":""},{"location":"deploy/packstack/#packstack-create-a-proof-of-concept-cloud","title":"Packstack: Create a proof of concept cloud","text":"

        Packstack is an OpenStack deployment tool intended to install Proof of Concept small environments in a quick and easy way using the RDO distribution on a CentOS Stream hosts. Production features such as High Availability, OpenStack upgrades or other day-2 operations are out of the scope of Packstack. For these cases, you can rely on other recommended tools described in Deploy RDO section.

        This document shows how to spin up a proof of concept cloud on one node using the Packstack installation utility. You will be able to add more nodes to your OpenStack cloud later, if you choose.

        These instructions apply to the following Release and Operating Systems - Victoria, Wallaby, Xena and Yoga on CentOS Stream 8, and Yoga, Zed and Antelope on CentOS Stream 9.

        "},{"location":"deploy/packstack/#warning","title":"WARNING","text":"

        Read this document in full, then choose your install path:

        Don't just start typing commands at Summary for the impatient and proceed downwards through the page.

        "},{"location":"deploy/packstack/#summary-for-the-impatient","title":"Summary for the impatient","text":"

        If you are using non-English locale make sure your /etc/environment is populated:

        LANG=en_US.utf-8\nLC_ALL=en_US.utf-8\n

        If your system meets all the prerequisites mentioned below, proceed with running the following commands.

        • On CentOS Stream 8:

        $ sudo dnf update -y $ sudo dnf config-manager --enable powertools $ sudo dnf install -y centos-release-openstack-yoga # Replace yoga by the desired release name $ sudo dnf update -y $ sudo dnf install -y openstack-packstack $ sudo packstack --allinone

        • On CentOS Stream 9:

        $ sudo dnf update -y $ sudo dnf config-manager --enable crb $ sudo dnf install -y centos-release-openstack-bobcat $ sudo setenforce 0 $ sudo dnf update -y $ sudo dnf install -y openstack-packstack $ sudo packstack --allinone

        Note for RHEL: Although it is expected that RDO works fine on RHEL, it is currently not tested in RHEL OS.

        • On RHEL 8:

        $ sudo dnf install -y https://www.rdoproject.org/repos/rdo-release.el8.rpm $ sudo dnf update -y $ subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-rpms $ sudo dnf install -y openstack-packstack $ sudo packstack --allinone

        "},{"location":"deploy/packstack/#step-0-prerequisites","title":"Step 0: Prerequisites","text":""},{"location":"deploy/packstack/#software","title":"Software","text":"

        CentOS Stream 8 is the minimum recommended version, or the equivalent version of one of the RHEL-based Linux distributions such as Red Hat Enterprise Linux, Scientific Linux, and so on. Packages are provided for x86_64, aarch64 and ppc64le architectures although most of the testing is done on x86_64.

        "},{"location":"deploy/packstack/#hardware","title":"Hardware","text":"

        Machine with at least 16GB RAM, processors with hardware virtualization extensions, and at least one network adapter.

        "},{"location":"deploy/packstack/#hostname","title":"Hostname","text":"

        Name the host with a fully qualified domain name rather than a short-form name to avoid DNS issues with Packstack.

        "},{"location":"deploy/packstack/#network","title":"Network","text":"

        If you plan on having external network access to the server and instances, this is a good moment to properly configure your network settings. A static IP address to your network card, and disabling NetworkManager are good ideas.

        On CentOS Stream 8/RHEL 8:

        network-scripts is deprecated and not installed by default, so needs to be installed explicitly.

        $ sudo dnf install network-scripts -y\n

        Disable firewalld and NetworkManager

        $ sudo systemctl disable firewalld\n$ sudo systemctl stop firewalld\n$ sudo systemctl disable NetworkManager\n$ sudo systemctl stop NetworkManager\n$ sudo systemctl enable network\n$ sudo systemctl start network\n

        If you are planning on something fancier, read the document on advanced networking before proceeding.

        "},{"location":"deploy/packstack/#step-1-software-repositories","title":"Step 1: Software repositories","text":"

        On CentOS Stream 8, first you need to enable the powertools repository. Then, the Extras repository provides the RPM that enables the OpenStack repository. Extras is enabled by default on CentOS 8, so you can simply install the RPM to set up the OpenStack repository:

        $ sudo dnf config-manager --enable powertools\n$ sudo dnf install -y centos-release-openstack-yoga\n

        On CentOS Stream 9, first you need to enable the crb. Then, the extras-common repository provides the RPM that enables the OpenStack repository. It is enabled by default on CentOS Stream 9, so you can simply install the RPM to set up the OpenStack repository:

        $ sudo dnf config-manager --enable crb\n$ sudo dnf install -y centos-release-openstack-bobcat\n

        On RHEL 8, install the RDO repository RPM to setup the Openstack repository, then you must enable the codeready-builder option in subscription-manager:

        $ sudo dnf install -y https://www.rdoproject.org/repos/rdo-release.el8.rpm\n$ subscription-manager repo --enable codeready-builder-for-rhel-8-x86_64-rpms\n

        Update your current packages:

        $ sudo dnf update -y\n

        Looking for an older version? See http://rdoproject.org/repos/ for the full listing.

        "},{"location":"deploy/packstack/#step-2-install-packstack-installer","title":"Step 2: Install Packstack Installer","text":"
        $ sudo dnf install -y openstack-packstack\n
        "},{"location":"deploy/packstack/#step-3-disable-selinux-enforcing-mode","title":"Step 3: Disable selinux enforcing mode","text":"

        There are known issues with selinux policies and rabbitmq in CentOS Stream 9. Disable selinux enforcing mode:

        $ sudo setenforce 0\n
        "},{"location":"deploy/packstack/#step-4-run-packstack-to-install-openstack","title":"Step 4: Run Packstack to install OpenStack","text":"

        Packstack takes the work out of manually setting up OpenStack. It provides a set of options to specify the desired services and configurations for each installation. You can list all the available parameters using:

        $ packstack --help\n

        For a simple, single node OpenStack deployment with default options, run the following command:

        $ sudo packstack --allinone\n

        The Packstack command line interface accepts an answers file as a mechanism to specify the parameters. The base answers file can be created with:

        $ packstack --gen-answer-file\n

        Then can be used by using --answer-file option:

        $ sudo packstack --answer-file=<path to the answers file>\n

        If you have run Packstack previously, there will be a file in your home directory named something like packstack-answers-20130722-153728.txt You will probably want to use that file again, using the --answer-file option, so that any passwords you have already set (for example, mysql) will be reused.

        The installer will ask you to enter the root password for each host node you are installing on the network, to enable remote configuration of the host so it can remotely configure each node using Puppet.

        Once the process is complete, you can log in to the OpenStack web interface Horizon by going to http://$YOURIP/dashboard. The user name is admin. The password can be found in the file keystonerc_admin in the /root directory of the control node.

        "},{"location":"deploy/packstack/#next-steps","title":"Next steps","text":"

        Now that your single node OpenStack instance is up and running, you can read on about configuring a floating IP range, configuring RDO to work with your existing network, or about expanding your installation by adding a compute node.

        "},{"location":"deploy/tripleo/","title":"TripleO","text":"

        TripleO is a set of tools for the deployment and management of OpenStack which utilizes the RDO repositories. The TripleO project was retired after the Zed release of OpenStack.

        The name TripleO refers to three related things:

        • A design pattern, where an underlying OpenStack instance is used to deploy and then to manage another, usually more complex, OpenStack instance.
        • A set of configuration files and scripts which contain OS image building rules and service configuration rules
        • The upstream program within the OpenStack project which develops the various scripts and utilities which are combined to deliver the complete software solution.

        The design pattern utilizes a single-purpose deployment OpenStack which deploys and manages a more sophisticated, general-purpose OpenStack instance which is what gives TripleO its name. TripleO is short for OpenStack On OpenStack.

        Upstream TripleO documentation:

        • http://docs.openstack.org/developer/tripleo-docs/

        Note: Limit your environment-specific content in the menu on the left-hand side of the documentation page.

        RDO/TripleO documentation:

        • TripleO in RDO Xena release

        TripleO YouTube channel:

        • TripleO YouTube Channel
        "},{"location":"deploy/tripleo/#get-in-touch","title":"Get in touch","text":"
        • IRC: #tripleo and #rdo channels on OFTC.
        • Mailing list: openstack-discuss, using [TripleO] tag in the subject of the email.
        "},{"location":"factory/","title":"Factory","text":"

        This section presents documents about how the factory behind building packages and repositories looks like. Here you will find sections about infrastructure, promotions and all tooling specific to this process.

        "},{"location":"factory/dlrn/","title":"DLRN: What it is, what we use it for","text":"

        DLRN (can be read as \"Delorean\") is an application that helps us do continuous packaging of RDO. It is used to build packages using the latest commit from each of the OpenStack project repositories.

        DLRN can be run as a standalone application to create a single package, or periodically (using a cron job) to rebuild all packages listed for a specific release.

        "},{"location":"factory/dlrn/#high-level-dlrn-flow","title":"High-level DLRN flow","text":"

        The basic DLRN flow is:

        • For each package listed in the RDO metadata file:
          • Fetch the latest upstream commit from the OpenStack Git repositories
          • Fetch the latest commit from the distgit repositories
          • Build an RPM package using the source and distgit commits
          • Create a YUM repository with that package, and the latest build package for the other packages
          • If a package build fails, open a review in the RDO Gerrit to track and fix the issue.

        The result of each DLRN run is an RDO Trunk repository, containing the latest commit from each supported OpenStack project, ready to be consumed.

        "},{"location":"factory/dlrn/#tips-and-tricks","title":"Tips and tricks","text":""},{"location":"factory/dlrn/#multiple-branch-support","title":"Multiple branch support","text":"

        DLRN can build packages using different upstream branches, not only master. For example, we have DLRN workers building packages for the Newton and Mitaka releases. That allows us to test each commit landing to stable/newton and stable/mitaka before it is part of a release. We can select which releases we want to build a package for using tags in the RDO metadata file, for example:

        - project: watcher\n  conf: rpmfactory-core\n  tags:\n    ocata-uc:\n    ocata:\n    newton:\n

        This project (openstack-watcher) is built for Ocata (master) and Newton.

        "},{"location":"factory/dlrn/#setting-up-a-dlrn-instance","title":"Setting up a DLRN instance","text":"

        You can follow the instructions from the README file to set up a test instance. The Puppet module we use to build the RDO instances is also available if you want to take a look at how to configure multiple instances on a single machine.

        "},{"location":"factory/pipeline/","title":"The delivery pipeline","text":"

        This is the 10,000 foot view of the RDO delivery pipeline. For more detail, see the various more in-depth documents:

        "},{"location":"factory/pipeline/#trunk-chasing","title":"Trunk chasing","text":"

        We use DLRN to track upstream changes and build continuously OpenStack as a RPM distribution. Then our Zuul spfCI hosted on SoftwareFactory runs multiple jobs on DLRN snapshots. We use the WeIRDO framework to run the same jobs as upstream CI on our packages. This allows us to detect early integration issues and get either our packaging or upstream projects fixed.

        "},{"location":"factory/pipeline/#branching","title":"Branching","text":"

        We start branching RDO stable release around milestone 3, and have stable builds getting bootstrapped. This includes:

        • registering packages in CBS, which is scripted using the rdoinfo database.
        • syncing requirements in packages.
        • branching distgit repositories.
        • building upstream releases in CBS. This part used to be semi-automated using rdopkg tool, and currently being consolidated into a cron job creating reviews.
        • tag builds in -testing repositories, some automation is in preparation.

          Trunk chasing continues, but we pay attention in keeping promotions happening more frequently to avoid a gap between tested upstream commits and releases.

          "},{"location":"factory/pipeline/#ga-publication","title":"GA publication","text":"

          Since OpenStack does releases slightly ahead of time, we have most of GA releases built in CBS, but some of them comes late. We also trim final GA repositories, use repoclosure utility to check if there's no missing dependencies. Before mass-tagging builds in -release we launch stable promotion CI jobs and if they're green, we publish them.

          At this stage, CentOS Core team, creates final GA repositories and sign packages.

          "},{"location":"factory/promotion-pipeline/","title":"Workflow: Promotion pipeline","text":"

          Promotion pipelines are composed by a set of related CI jobs that are executed for each supported OpenStack release to test the content of a specific RDO repository. For each OpenStack release Puppet promotion pipelines are proceeded, to validate RDO packages with OpenStack Puppet Modules and to promote the RDO packages used in upstream OpenStack Puppet modules check and gate jobs.

          This pipeline run in parallel and is composed of different jobs.

          The promotion workflow can be described with following schema:

          1. Define the repository to be tested. RDO Trunk repositories are identified by a hash based on the upstream commit of the last built package. The content of these repos doesn't change over time. When a promotion pipeline is launched, it grabs the latest consistent hash repo and sets it to be tested in the following phases.

          2. Deploy and test RDO. We run a set of jobs which deploy and test OpenStack using different installers and scenarios to ensure they behave as expected. Currently, there are following promotion testing method:

            • OpenStack Puppet scenarios. Project puppet-openstack-integration (a.k.a. p-o-i) maintains a set of Puppet manifests to deploy different OpenStack services combinations and configurations (scenarios) in a single server using OpenStack Puppet Modules, and run tempest smoke tests for the deployed services. The tested services on each scenario can be found in the README for p-o-i. These scenarios, together with Packstack deployment ones, are executed in puppet promotion pipelines to test new packages build in RDO Repos. Part of scenarios are currently tested in RDO CI as Packstack deployment.
          3. Repository and images promotion. When all jobs in the previous phase succeed, the tested repository is considered good and it is promoted so that users can use these packages:

            • The repo is published using RDO Trunk servers in https://trunk.rdoproject.org/centos9-\\<openstack_version>/current-passed-ci/delorean.repo
          "},{"location":"factory/promotion-pipeline/#tools-used-in-rdo-ci","title":"Tools used in RDO CI","text":"
          • Jobs definitions are managed using Zuul, via a gerrit review workflow in review.rdoproject.org
          • WeIRDO is the tool we use to run p-o-i and Packstack testing scenarios defined upstream inside RDO CI. It is composed of a set of ansible roles and playbooks that prepare the environment and deploy and test the installers using the testing scripts provided by the projects.
          • ARA is used to store and visualize the results of ansible playbook runs, making it easier to analize and troubleshoot them.
          "},{"location":"factory/promotion-pipeline/#infrastructure","title":"Infrastructure","text":"

          RDO runs the promotion pipelines in the CI infrastructure managed by Software Factory.

          "},{"location":"factory/promotion-pipeline/#handling-issues-in-rdo-ci","title":"Handling issues in RDO CI","text":"

          An important aspect of running RDO CI is properly managing the errors found in the jobs included in the promotion pipelines. The root cause of these issues sometimes is in the OpenStack upstream projects:

          • Some problems are not caught in devstack-based jobs running in upstream gates.
          • In some cases, new versions of OpenStack services require changes in the deployment tools

          One of the contributions of RDO to upstream projects is to increase test coverage of the projects and help to identify the problems as soon as possible. When we find them, we report it upstream as Launchpad bugs and propose fixes when possible.

          "},{"location":"factory/promotion-pipeline/#status-of-promotion-pipelines","title":"Status of promotion pipelines","text":"

          If you are interested in the status of the promotion pipelines in RDO CI you can check:

          • Zuul pipelines status view can be used to see the result and status of each kind of puppet promotion pipeline and OpenStack release.

          • RDO Dashboard shows the overall status of RDO promotion pipelines.

          • RDO FTBFS Dashboard shows status of currently failed package build attempts.

          "},{"location":"factory/promotion-pipeline/#more-info","title":"More info","text":"
          • Weirdo: A talk about CI in OpenStack and RDO by dmsimard.
          • ARA blog posts - from dmsimard blog
          • Ci in RDO: What do we test? - presentation in RDO and Ceph Meetup BCN.
          • RDO dashboards repo
          "},{"location":"factory/workflow-overview/","title":"Infrastructure","text":"

          The following pieces of infrastructure are used during the cycle:

          • review.rdoproject.org is the central system for our workflow, powered by SoftwareFactory. It contains a Gerrit instance to manage all changes to the repositories where the spec files used to build our packages are contained, as well as the components managing our CI infrastructure.
          • Our distgit repositories contain one repository for each project built by RDO, where the spec files are located. Every change submitted via review.rdoproject.org is synchronized to the repos at GitHub.
          • The RDO Trunk repositories contain the latest packages.
          • The Zuul CI infrastructure is used to run the periodic jobs to promote the latest repositories.
          "},{"location":"misc/networking/","title":"Network troubleshooting","text":"

          Check out this webcast - an overview of networking principles and how they apply to Neutron and OpenvSwitch - by Dave Neary.

          "},{"location":"misc/networking/#toolchain","title":"Toolchain","text":"

          A number of tools come in handy when troubleshooting Neutron/Quantum networking issues.

          • Open vSwitch (documentation)
            • ovs-vsctl - tool for querying and configuring ovs-vswitchd
            • ovs-ofctl - OpenFlow configuration tool
            • ovs-dpctl - query and configure Open vSwitch datapaths
          • iproute tools
            • iproute2 HOWTO
          • tcpdump (see next section)
            • tcpdump documentation
          "},{"location":"misc/networking/#tcpdump","title":"tcpdump","text":"

          tcpdump will be your best friend so it's best to learn and understand how to use it. When debugging routing issues with quantum, tcpdump can be used to investigate the ingress and egress of traffic. For example:

                 tcpdump -n -i br-int\n

          The above command will capature all traffic on the internal bridge interface.

                 tcpdump -n -i br-int  -w tcpdump.pcap\n

          The above command will capture all traffic on the internal bridge interface and dump it to a file named tcpdump.pcap.

                 tcpdump -r tcpdump.pcap\n

          The above command will read in a previously created tcpdump file

                 tcpdump -n -i any\n

          The above command will capture all traffic on any interface. ...

          "},{"location":"misc/networking/#iproute2","title":"iproute2","text":"

          iproute2 provides a tool called ip which allows you to debug what is going on.

          Here are some diagnostics commands for networking (assuming you are using Neutron). Of-course, you'll replace the router namespace, dhcp namespace IDs , IP addresses accordingly:

          # List namespaces\n$ ip netns\nqdhcp-4a04382f-03bf-49a9-9d4a-35ab9ffc22ad\nqrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f\n\n# Show all interfaces inside the namespace\n$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \\\n  ip a\n\n# Check routing table inside the router namespace\n$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \\\n  ip r\n\n# IP config inside the router namesapce\n$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \\\n  ifconfig\n\n# IP configu inside the dhcp namesace\n$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \\\n  ifconfig\n\n# Ping the private IP (of the cirros guest)\n$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \\\n  ping -c2 30.0.0.7\n$ ip netns exec qrouter-1fabd5f0-f80b-468d-b733-1b80d0c3e80f \\\n  ping -c2 192.168.122.14\n\n# ssh into cirros guest\n$ ip netns exec qdhcp-4a04382f-03bf-49a9-9d4a-35ab9ffc22ad ssh   cirros@30.0.0.7\n
          "},{"location":"misc/networking/#common-issues","title":"Common issues","text":"
          • I can create an instance, but cannot SSH or ping it

            • Verify that traffic to port 22 and ICMP traffic of any type (-1:-1) is allowed in the default security group In the dashboard, in the Project tab, under \"Access and Security\", check the rules which are active on the security group you are using with your instances (typically \"default\"). You should see a rule allowing traffic to port 22 over tcp from all hosts, and a port enabling icmp traffic of all types (-1). If you don't, create the necessary rules, and try again.

            • Verify that you can ping and SSH the host where the instance is running From the host where you are attempting to connect to your instance, verify that network traffic is being correctly routed to the compute node in question.

            • Ensure that the router is correctly created, that the internal subnet and external subnet are attached to it, and that it can route traffic from your IP to the instance IP If your VM is in the 192.168.1.x subnet, and the host from which you are trying to connect is in the 192.168.0.x subnet, then you will need to have a route from one to the other. Ensure that the subnet 192.168.1.x and 192.168.0.x are both added to a router which you create in Neutron

            • Check that you can ping an instance from inside its network namespace. If you are using network namespaces, then each VLAN will have its own namespace, and entities inside that namespace will be invisible from outside. You can check whether you can ping an instance from inside the namespace by first finding the namespace identifier, and then using the iproute toolset to execute a \"ping\" inside that namespace:

          ip netns list\n# Identify virtual router to which your subnet is connected\nip netns exec qrouter-de0b9dbe-6b65-45ee-9ff2-c752c7937a9e ping 10.10.0.7\n# IP address and qrouter ID correspond to the network namespace and private IP address for instance\n\n-   Check the OVS routing table to ensure that it is correctly routing traffic from internal to external.\n    You should see a route for each subnet attached to your virtual router, and you should see routing which will allow traffic from the VM to get to the subnet of the host from which you are trying to connect (or to a public gateway)\n\n        ip netns exec qrouter-de0b9dbe-6b65-45ee-9ff2-c752c7937a9e route -n\n\n-   Verify that br-ex is associated with the physical NIC, and that the virtual router can route traffic to the IP address of the host. For a single NIC set-up, you will need to bring up br-ex at boot time, and connect eth0 to it.\n    To set up br-ex initially (on a host with static IP 192.168.0.2), the following will do the initial configuration:\n
          ip addr flush eth0\novs-vsctl add-port br-ex eth0\nip addr add 192.168.0.2 dev br-ex\nip link set br-ex up\n

          To make changes persist after boot, you will need to create /etc/sysconfig/network-scripts/ifcfg-br-ex as follows (replace DNS, IP addresses for your local network):

          DEVICE=br-ex\nTYPE=Ethernet\nBOOTPROTO=static\nONBOOT=yes\nIPADDR=192.168.0.2\nNETMASK=255.255.255.0\nGATEWAY=192.168.0.1\nDNS1=89.2.0.1\nDNS2=89.2.0.1\nDOMAIN=neary.home\nNAME=\"System br-ex\"\n

          After this, you will no longer need to bring up eth0, and all going well you will be able to access both instances and the management interface on the same host.

          • I cannot associate a floating IP with an instance
            • If the error is that the external network is not visible from the subnet: Check that br-ex has its MAC address set correctly. Check for the error \"Device or resource busy\" in /var/log/messages - if it's present, you will need to bring down br-ex, set its MAC address to match that of the physical NIC, and bring it back up.
          • I can create an instance, however, it does not get a DHCP address
            • See openstack documentation for information on sniffing the various steps of the allocation of an IP address by DHCP - verify that your DHCP agent is running, is receiving the DHCPDISCOVER request, and is replying to it - and verify that your host is receiving the DHCP reply.
            • Make sure that IPv6 is enabled. Disabling IPv6 will give an error such as \"Address family not supported\".
            • If you are using OpenvSwitch with VLAN, make sure that the network created includes VLAN information. You may need to restart the quantum-openvswitch-agent service and/or create a network using specific VLAN information.
          • If you are using more than one node for OpenStack (i.e., not an all-in-one installation), then you must use VLANs.
          • If you are using a virtual machine as a node in OpenStack, you must use the virtio network driver when using VLANs. The default rt8139 driver seems to drop VLAN information.
          • You must have an external network set as the gateway to the router if you want to get network traffic out of the private instance network.
          "},{"location":"misc/networking/#other-resources","title":"Other resources","text":"
          • Network troubleshooting (OpenStack Operations Guide)

          "},{"location":"misc/qpid-errors/","title":"Qpid errors","text":""},{"location":"misc/qpid-errors/#config-file-errors","title":"Config file errors","text":"

          If you see something like the following message in your system log when the qpidd service attempts to start:

          Jul 22 15:39:08 localhost qpidd[8631]: 2013-07-22 15:39:08 [Broker] critical Unexpected error: Error in configuration file /etc/qpidd.conf: Bad argument: |cluster-mechanism=DIGEST-MD5 ANONYMOUS|\n

          Replace 'cluster-mechanism' with 'ha-mechanism' in /etc/qpidd.conf then restart the qpidd service, or reboot.

          "},{"location":"misc/qpid-errors/#sasldb-errors","title":"sasldb errors","text":"

          The qpid user database may become corrupted. This may be evidenced by error messages such as:

               qpidd: unable to open Berkeley db /var/lib/qpidd/qpidd.sasldb: No such file or directory\n

          You can recreate the sasldb file using the following command:

               saslpasswd2 -f /var/lib/qpidd/qpidd.sasldb -u QPID guest\n

          Provide the password at the command line (usually 'guest'), and the file will be created. You should further ensure that /etc/cinder/cinder.conf references the correct username and password corresponding with this file. Then restart qpidd:

               service qpidd restart\n

          You can verify the presence of users accounts in that file with:

               sasldblistusers2 -f /var/lib/qpidd/qpidd.sasldb\n
          "},{"location":"misc/selinux-issues/","title":"SELinux issues","text":""},{"location":"misc/selinux-issues/#troubleshooting-selinux-issues","title":"Troubleshooting SELinux issues","text":""},{"location":"misc/selinux-issues/#general-tips","title":"General tips","text":"

          SELinux can sometimes be a source of issues with OpenStack. On a system with SELinux enabled (as it is by default on Fedora and RHEL), you can check for denial messages with the command:

          sudo cat /var/log/audit/audit.log | grep -i avc\n

          or

          sudo sealert -a /var/log/audit/audit.log\n

          You can check the SELinux enforcement status of your machine with the command \"sestatus\" and can temporarily place SELinux in enforcing (in which it blocks access violations) or permissive (logs access violations, but does not block) with the commands \"setenforce 1\" and \"setenforce 0\", respectively.

          To make SELinux enforcement changes that persist between reboots, edit the file /etc/selinux/config.

          To see what the current security context for a resource ls, run

          ls -Z\n

          For more information on SELinux troubleshooting, see http://fedoraproject.org/wiki/SELinux/Troubleshooting.

          "},{"location":"misc/selinux-issues/#filing-bugzillas-jira-ticket","title":"Filing Bugzillas Jira ticket","text":"

          Sometimes, there are missing policies required in order released RDO versions to work correctly with SELinux in enforcing mode. In order for the RDO developers to troubleshoot the problem, please perform the following:

          • Set SELinux to permissive mode
          • Zero out your /var/log/audit/audit.log: sudo cp /dev/null /var/log/audit/audit.log

          • Perform a full test of the use case that is causing the problem

          • File a Jira ticket and attach your /var/log/audit/audit.log

          For more information about how SELinux policies are developed for RDO, see SELinux

          "},{"location":"misc/selinux-issues/#packstack-fails-if-selinux-is-disabled","title":"PackStack fails if SELinux is disabled","text":"

          It has been reported that PackStack will fail if SELinux is disabled.

          The error observed is:

          ERROR : Error during puppet run : err: /Stage[main]//Exec[setenforce 0]/returns:\nchange from notrun to 0 failed: setenforce 0 returned 1 instead of one of [0]\nat /var/tmp/packstack/51a57c45478b4091b2eb6a1bbd4c2303/manifests/my_public_ip_ring_swift.pp:56\nPlease check log file /var/tmp/packstack/20130421-002212-fYYLUA/openstack-setup.log for more information\n

          The solution is to enable SELinux in permissive mode (if there is a reason not to have it in enforcing mode). In

          /etc/selinux/config\n

          set

          SELINUX=permissive\n

          If you have previously disabled SELinux, you will need to re-label the filesystem, since when SELinux is disabled, this does not happen for new files, and failing to relabel will likely cause many false positive issues. The easiest way to do that is to do the following as root:

          touch /.autorelabel\nreboot\n

          This issue is being tracked in Red Hat Bugzilla bug #954188

          "},{"location":"misc/selinux/","title":"SELinux in an RDO Deployment","text":"

          RDO releases should operate with SELinux in enforcing mode without issue. If it does not work for you, please see the SELinux_issues page for more information on how to troubleshoot and what information to gather for filing bugzillas.

          From time to time, especially with the EL6 releases of RDO, certain measures are taken to ensure that RDO works and are distributed as part of the openstack-selinux package. This package contains fixes to ensure RDO continues working on top of the latest Red Hat Enterprise Linux 6 and CentOS 6 releases. It always advised to run the very latest selinux-policy package appropriate for your distribution, even if you upgrade nothing else. For example, if you are running CentOS 6.4, it is recommended to run the latest selinux-policy package from CentOS 6.5 if at all possible.

          Occasionally, RDO developers will even release updated selinux-policy packages to ensure that your RDO systems stay operational with the latest RDO releases.

          "},{"location":"misc/selinux/#selinux-during-rdo-development","title":"SELinux during RDO Development","text":"

          RDO releases interim releases during upstream OpenStack development based on upstream milestones. For example, \"icehouse-1\". Shortly thereafter, the RDO team schedules Test Days in order to gather information on what needs to be fixed.

          OpenStack is often in heavy development during these interim releases. Consequently, SELinux is likely to stand in the way of performing useful testing during these test days. For this reason, it is recommended to run in permissive mode during test days and gather AVCs:

          sudo setenforce 0\n

          The RDO team typically waits to coordinate with upstream SELinux policy developers until after the upstream \"-3\" milestone, which is the Feature Freeze for the next OpenStack release. This is because the high pace of innovation that takes place during OpenStack development cycles makes writing SELinux policy modules difficult to keep up with; it is similar to trying to keep localization work up to date.

          "},{"location":"misc/selinux/#what-about-a-modular-selinux-policy","title":"What about a modular SELinux policy?","text":"

          I get a lot of questions about this. The short answer is that SELinux policies are not conducive to being separated in to multiple git repositories/packages at this time.

          (still work in progress)

          "},{"location":"misc/troubleshoot/","title":"Troubleshooting","text":"

          Every piece of software as complex as OpenStack has some pitfalls in its usage. We will use this page to collect tips and tricks related to installation and configuration issues, and issues which people run into during the lifetime of their OpenStack deployment.

          • Troubleshooting networking
          • SELinux issues
          • Uninstalling RDO
          • qpidd/AMQP troubleshooting
          "},{"location":"misc/uninstalling-rdo/","title":"Uninstalling RDO","text":"

          There is no automated uninstall process for RDO (or OpenStack in general) because OpenStack consists of multiple services, (possibly) running across multiple systems. At this time there is no way to identify all of the various parts, locate them, and safely uninstall them.

          Since OpenStack installations are almost certain to be deployed on dedicated systems (or VMs), the most reasonable way to \"uninstall\" RDO is to reinstall the base OS and start fresh.

          "}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..0f8724e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..99bb3ac9a22954c868cc63d79c83440fd59e5aff GIT binary patch literal 127 zcmV-_0D%7=iwFpSeT-%T|8r?{Wo=<_E_iKh04<9_3V)_WXo8&M?ytk3HC}0~zlG)Vu

See more at dedicated page.