From 8dbcfa70f65559b3bda60549ac66087654a3337f Mon Sep 17 00:00:00 2001 From: arthurhauer Date: Sun, 10 Nov 2024 20:20:03 +0000 Subject: [PATCH] deploy: 3b89816492d1e422df03ce4e1cf4cf3b2720d006 --- .buildinfo | 4 + .doctrees/application.doctree | Bin 0 -> 2431 bytes .doctrees/environment.pickle | Bin 0 -> 912720 bytes .doctrees/index.doctree | Bin 0 -> 5044 bytes .doctrees/main.doctree | Bin 0 -> 2396 bytes .doctrees/models.doctree | Bin 0 -> 103678 bytes .doctrees/models.exception.doctree | Bin 0 -> 28508 bytes .doctrees/models.node.doctree | Bin 0 -> 35791 bytes .doctrees/models.node.generator.doctree | Bin 0 -> 28547 bytes .doctrees/models.node.generator.file.doctree | Bin 0 -> 41536 bytes .doctrees/models.node.output.device.doctree | Bin 0 -> 3778 bytes .doctrees/models.node.output.display.doctree | Bin 0 -> 3739 bytes .doctrees/models.node.output.doctree | Bin 0 -> 11966 bytes .doctrees/models.node.output.file.doctree | Bin 0 -> 18297 bytes .doctrees/models.node.processing.doctree | Bin 0 -> 98701 bytes .../models.node.processing.encoder.doctree | Bin 0 -> 37969 bytes ....node.processing.feature_extractor.doctree | Bin 0 -> 18880 bytes .../models.node.processing.filter.doctree | Bin 0 -> 4119 bytes .../models.node.processing.segmenter.doctree | Bin 0 -> 37852 bytes ...de.processing.trainable.classifier.doctree | Bin 0 -> 4387 bytes .../models.node.processing.trainable.doctree | Bin 0 -> 5030 bytes ...essing.trainable.feature_extractor.doctree | Bin 0 -> 4542 bytes .doctrees/models.utils.doctree | Bin 0 -> 24893 bytes .doctrees/modules.doctree | Bin 0 -> 2811 bytes .nojekyll | 0 _modules/index.html | 288 +++++ .../exception/framework_base_exception.html | 274 +++++ .../exception/invalid_parameter_value.html | 277 +++++ .../models/exception/missing_parameter.html | 274 +++++ .../models/exception/non_compatible_data.html | 275 +++++ _modules/models/framework_data.html | 631 +++++++++++ .../models/node/generator/file/csvfile.html | 420 +++++++ .../node/generator/file/csvfilearray.html | 403 +++++++ .../models/node/generator/generator_node.html | 351 ++++++ .../generator/single_run_generator_node.html | 318 ++++++ _modules/models/node/node.html | 642 +++++++++++ _modules/models/node/output/file/csvfile.html | 397 +++++++ _modules/models/node/output/output_node.html | 364 ++++++ .../processing/encoder/onehottosingle.html | 361 ++++++ .../processing/encoder/singletoonehot.html | 360 ++++++ .../feature_extractor/feature_extractor.html | 354 ++++++ _modules/models/node/processing/fill.html | 443 ++++++++ _modules/models/node/processing/merge.html | 443 ++++++++ .../node/processing/processing_node.html | 407 +++++++ .../segmenter/fixedwindowsegmenter.html | 373 ++++++ .../node/processing/segmenter/segmenter.html | 337 ++++++ .../models/node/processing/signalcheck.html | 303 +++++ .../models/node/processing/synchronize.html | 664 +++++++++++ _modules/models/utils/cue.html | 343 ++++++ _modules/models/utils/script_execution.html | 289 +++++ _sources/application.rst.txt | 7 + _sources/index.rst.txt | 20 + _sources/main.rst.txt | 7 + _sources/models.exception.rst.txt | 45 + _sources/models.node.generator.file.rst.txt | 29 + _sources/models.node.generator.rst.txt | 53 + _sources/models.node.output.device.rst.txt | 21 + _sources/models.node.output.display.rst.txt | 21 + _sources/models.node.output.file.rst.txt | 29 + _sources/models.node.output.rst.txt | 31 + .../models.node.processing.encoder.rst.txt | 29 + ....node.processing.feature_extractor.rst.txt | 21 + .../models.node.processing.filter.rst.txt | 29 + _sources/models.node.processing.rst.txt | 65 ++ .../models.node.processing.segmenter.rst.txt | 29 + ...de.processing.trainable.classifier.rst.txt | 29 + ...essing.trainable.feature_extractor.rst.txt | 29 + .../models.node.processing.trainable.rst.txt | 38 + _sources/models.node.rst.txt | 31 + _sources/models.rst.txt | 31 + _sources/models.utils.rst.txt | 45 + _sources/modules.rst.txt | 9 + _static/basic.css | 903 +++++++++++++++ _static/debug.css | 69 ++ _static/doctools.js | 156 +++ _static/documentation_options.js | 14 + _static/file.png | Bin 0 -> 286 bytes _static/language_data.js | 199 ++++ _static/minus.png | Bin 0 -> 90 bytes _static/plus.png | Bin 0 -> 90 bytes _static/pygments.css | 258 +++++ _static/scripts/furo-extensions.js | 0 _static/scripts/furo.js | 3 + _static/scripts/furo.js.LICENSE.txt | 7 + _static/scripts/furo.js.map | 1 + _static/searchtools.js | 566 ++++++++++ _static/skeleton.css | 296 +++++ _static/sphinx_highlight.js | 144 +++ _static/styles/furo-extensions.css | 2 + _static/styles/furo-extensions.css.map | 1 + _static/styles/furo.css | 2 + _static/styles/furo.css.map | 1 + application.html | 286 +++++ genindex.html | 1003 +++++++++++++++++ index.html | 570 ++++++++++ main.html | 286 +++++ models.exception.html | 368 ++++++ models.html | 767 +++++++++++++ models.node.generator.file.html | 418 +++++++ models.node.generator.html | 423 +++++++ models.node.html | 567 ++++++++++ models.node.output.device.html | 316 ++++++ models.node.output.display.html | 316 ++++++ models.node.output.file.html | 362 ++++++ models.node.output.html | 376 ++++++ models.node.processing.encoder.html | 410 +++++++ models.node.processing.feature_extractor.html | 353 ++++++ models.node.processing.filter.html | 320 ++++++ models.node.processing.html | 718 ++++++++++++ models.node.processing.segmenter.html | 413 +++++++ ....node.processing.trainable.classifier.html | 320 ++++++ ...rocessing.trainable.feature_extractor.html | 320 ++++++ models.node.processing.trainable.html | 342 ++++++ models.utils.html | 384 +++++++ modules.html | 347 ++++++ objects.inv | Bin 0 -> 1776 bytes py-modindex.html | 534 +++++++++ search.html | 275 +++++ searchindex.js | 1 + 119 files changed, 23660 insertions(+) create mode 100644 .buildinfo create mode 100644 .doctrees/application.doctree create mode 100644 .doctrees/environment.pickle create mode 100644 .doctrees/index.doctree create mode 100644 .doctrees/main.doctree create mode 100644 .doctrees/models.doctree create mode 100644 .doctrees/models.exception.doctree create mode 100644 .doctrees/models.node.doctree create mode 100644 .doctrees/models.node.generator.doctree create mode 100644 .doctrees/models.node.generator.file.doctree create mode 100644 .doctrees/models.node.output.device.doctree create mode 100644 .doctrees/models.node.output.display.doctree create mode 100644 .doctrees/models.node.output.doctree create mode 100644 .doctrees/models.node.output.file.doctree create mode 100644 .doctrees/models.node.processing.doctree create mode 100644 .doctrees/models.node.processing.encoder.doctree create mode 100644 .doctrees/models.node.processing.feature_extractor.doctree create mode 100644 .doctrees/models.node.processing.filter.doctree create mode 100644 .doctrees/models.node.processing.segmenter.doctree create mode 100644 .doctrees/models.node.processing.trainable.classifier.doctree create mode 100644 .doctrees/models.node.processing.trainable.doctree create mode 100644 .doctrees/models.node.processing.trainable.feature_extractor.doctree create mode 100644 .doctrees/models.utils.doctree create mode 100644 .doctrees/modules.doctree create mode 100644 .nojekyll create mode 100644 _modules/index.html create mode 100644 _modules/models/exception/framework_base_exception.html create mode 100644 _modules/models/exception/invalid_parameter_value.html create mode 100644 _modules/models/exception/missing_parameter.html create mode 100644 _modules/models/exception/non_compatible_data.html create mode 100644 _modules/models/framework_data.html create mode 100644 _modules/models/node/generator/file/csvfile.html create mode 100644 _modules/models/node/generator/file/csvfilearray.html create mode 100644 _modules/models/node/generator/generator_node.html create mode 100644 _modules/models/node/generator/single_run_generator_node.html create mode 100644 _modules/models/node/node.html create mode 100644 _modules/models/node/output/file/csvfile.html create mode 100644 _modules/models/node/output/output_node.html create mode 100644 _modules/models/node/processing/encoder/onehottosingle.html create mode 100644 _modules/models/node/processing/encoder/singletoonehot.html create mode 100644 _modules/models/node/processing/feature_extractor/feature_extractor.html create mode 100644 _modules/models/node/processing/fill.html create mode 100644 _modules/models/node/processing/merge.html create mode 100644 _modules/models/node/processing/processing_node.html create mode 100644 _modules/models/node/processing/segmenter/fixedwindowsegmenter.html create mode 100644 _modules/models/node/processing/segmenter/segmenter.html create mode 100644 _modules/models/node/processing/signalcheck.html create mode 100644 _modules/models/node/processing/synchronize.html create mode 100644 _modules/models/utils/cue.html create mode 100644 _modules/models/utils/script_execution.html create mode 100644 _sources/application.rst.txt create mode 100644 _sources/index.rst.txt create mode 100644 _sources/main.rst.txt create mode 100644 _sources/models.exception.rst.txt create mode 100644 _sources/models.node.generator.file.rst.txt create mode 100644 _sources/models.node.generator.rst.txt create mode 100644 _sources/models.node.output.device.rst.txt create mode 100644 _sources/models.node.output.display.rst.txt create mode 100644 _sources/models.node.output.file.rst.txt create mode 100644 _sources/models.node.output.rst.txt create mode 100644 _sources/models.node.processing.encoder.rst.txt create mode 100644 _sources/models.node.processing.feature_extractor.rst.txt create mode 100644 _sources/models.node.processing.filter.rst.txt create mode 100644 _sources/models.node.processing.rst.txt create mode 100644 _sources/models.node.processing.segmenter.rst.txt create mode 100644 _sources/models.node.processing.trainable.classifier.rst.txt create mode 100644 _sources/models.node.processing.trainable.feature_extractor.rst.txt create mode 100644 _sources/models.node.processing.trainable.rst.txt create mode 100644 _sources/models.node.rst.txt create mode 100644 _sources/models.rst.txt create mode 100644 _sources/models.utils.rst.txt create mode 100644 _sources/modules.rst.txt create mode 100644 _static/basic.css create mode 100644 _static/debug.css create mode 100644 _static/doctools.js create mode 100644 _static/documentation_options.js create mode 100644 _static/file.png create mode 100644 _static/language_data.js create mode 100644 _static/minus.png create mode 100644 _static/plus.png create mode 100644 _static/pygments.css create mode 100644 _static/scripts/furo-extensions.js create mode 100644 _static/scripts/furo.js create mode 100644 _static/scripts/furo.js.LICENSE.txt create mode 100644 _static/scripts/furo.js.map create mode 100644 _static/searchtools.js create mode 100644 _static/skeleton.css create mode 100644 _static/sphinx_highlight.js create mode 100644 _static/styles/furo-extensions.css create mode 100644 _static/styles/furo-extensions.css.map create mode 100644 _static/styles/furo.css create mode 100644 _static/styles/furo.css.map create mode 100644 application.html create mode 100644 genindex.html create mode 100644 index.html create mode 100644 main.html create mode 100644 models.exception.html create mode 100644 models.html create mode 100644 models.node.generator.file.html create mode 100644 models.node.generator.html create mode 100644 models.node.html create mode 100644 models.node.output.device.html create mode 100644 models.node.output.display.html create mode 100644 models.node.output.file.html create mode 100644 models.node.output.html create mode 100644 models.node.processing.encoder.html create mode 100644 models.node.processing.feature_extractor.html create mode 100644 models.node.processing.filter.html create mode 100644 models.node.processing.html create mode 100644 models.node.processing.segmenter.html create mode 100644 models.node.processing.trainable.classifier.html create mode 100644 models.node.processing.trainable.feature_extractor.html create mode 100644 models.node.processing.trainable.html create mode 100644 models.utils.html create mode 100644 modules.html create mode 100644 objects.inv create mode 100644 py-modindex.html create mode 100644 search.html create mode 100644 searchindex.js diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..8d38e5f --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 6c41e713b3b1afa10fbafed97c047cab +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/application.doctree b/.doctrees/application.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ee8ccf1b8b1999271ea12e7177c0655106290479 GIT binary patch literal 2431 zcmaJ@QEMDG5KipeozK2I+euvtiQ9&frlIy-34JJiY@kp~-BL=)OAxx1?j%ktZ6$4d zelWBTff)1__5b$M?%w+DC^ZZ|RjYrOkK@_n?spshH(DzKLO!)V)-0+}QUV&%89cH5VPx6}>l6 z^h3u>ulU+ccu0#v$&4n8&vU~{TsO)Oe&@>+#DD6%i*;z-f+7$f#c}A9Hgd5Wx=p~B z;enEx$IEg`!#?%i%4zA5Xi98XGMAF*Wr{inA-+4B=JnSeD~r3slx7RdXGy0FJx}N9 zDvCq#SPaAyu`5o)>xnQqpV(4sZYNj9E+)SeT>tRuC-UpH7ekJ4ir$hN#6;M7fUJd4n4jUjXH2TemAzsd$dt7l>YbE%p)hZXLBa+jhQkvodJ0 z6lclyei&t?O{kL=mTlvI2lMp750CtPQSK`VxS z>1XHPojZx|C!3dqTWc&4R5Qgba899SK88b6`b{sL%1aEVTQ^%S#OpAso!$koGJUdn zv1J*KQUVSr3E-oUPz*yw^}M8W4!9Z4JD4Hik>#1Oj4+N~VR%M@8JD4(89hUefI~7; zp!MW3if$Ou(i?Io3Of>v8nQAkNXt5)S_vcwXEjyH;bA2KwA!WG--!yxOJ>M2PkcJ! z%fdKL)-5ZFWS+d0PS*T9BuqLwRVk4s%HFCQ#90_183+DXV+~G+jT)IrRnL}>(-$6b z+@{fo@+NN#^*+F`ZI9sRacU{hM$f@QC3ETH&qvS0sNe+wC>)KLRe%kWWJ(cx>WuJ- z@V;>0PbLt%aZ$~mv9a?>3@1sm3ILkK^Bm>zD90Y;=g+?R7I=>AEZcIQBzNw=T)9W5 z(!|#Vw`0luta<}IKM_7xc&zW~6fMNOh!=a|6okx4+na3y#1)Alx8cZLYfqO%$hlDX z1$iGRlXyRHIYpQKS)!>OfO=G&>myMnqYbpDnV^UVg|C|pC|3}|dQld5BCV`y5j8{L z7VI&Z)H85kH5DGFIpNCbmY&QLd6l7cE2h=5h~P{<-4&{`0lQ>h5H ztL4>#c^{6O{RpzESv}Kk!!Flv(~1gv^(;a2f{IcziRSRcQ#(ekl z+4j}k+zb1d7?~;4Jc!{SGfDwij&Gxu^~Qa d#Z}1;q|Q{y5=G{zTKg=`wq^{ZeOpe){{p8)&hr2O literal 0 HcmV?d00001 diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..98962b9655f62e48e9167ae426162abb776e4c74 GIT binary patch literal 912720 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�%6ZVhax~4+)jxGoRet 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 UqR1juYnP?j){KF)Z_C-_KWMJN0ssI2 literal 0 HcmV?d00001 diff --git a/.doctrees/models.doctree b/.doctrees/models.doctree new file mode 100644 index 0000000000000000000000000000000000000000..436351d1c7899fad393171f73a66258a9e62ea0e GIT binary patch literal 103678 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 literal 0 HcmV?d00001 diff --git a/.doctrees/models.exception.doctree b/.doctrees/models.exception.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a9aa58a2e11c620560dc106394ba4b8ab1bc6a57 GIT binary patch literal 28508 zcmdsAeT*c>Ro}ha@7vqGJKGm0cWckt*tcij?%F1Hq9wK*pKZw;z8Kp|Kt8A4JJYk> zeKXy|bobq!bGGA=>*HX{A6G? zL&x`$;`X>bVNX69FWS>&Jaod2rF_yDv9e17`}-ye8Rp8)nZ=_y08y{>aT@=*TKKT@b3u7Y2QfYTVmPm zqrkzqT7b+1vPM%B&!j5EW~8zNv8*_YiadwfLR}|~H8ZeI8q#E#oI*^QbA;v`$>)^P z-#3`__bSp)f&NFxxZ|~~4aKCHwU_FVOoEB_9copJWUOa8{g~X$B>1sLuB{WPsVGvC znB2t5EY&Y!Pn-y26C3gapnEO~Yj^vngy9Ut{zTw->(HUe{=}H?g0{Iwbmo}cS)0A( z5)y@6lP_P2?!|apNepSFOxw%7v#Zz_q2avshTpE=PNh;|Zv*og1E<@}ST@FXdGN~MtYTx9f2Y-Zip&w;oxJY(^@h?FuQ0~ZX zWR{N2^xaZh*Zz$CEc&(QWGmU9g#n6*IZegP$Y_UrR4j8{lF1i!Oim$_jKe9cr<}PL z3YptSnS;m$njp0L9R~(?r6q1jx=!sr&AXlOAPH%e>}3UHlX6tk=y{Bc&d6N4m}vWK zvQ*u-%T-54y?hsa8Fch5YMYl+y&x04$ZLjC&MA$qit6D>*7$v0jlF!0|H5nhq!<9p zyv^(7gzaA`^ff5RD+$@1;Efr_BV-mL!4?c9#s)-@O1tpEcR!(-6QSJM(UB2N^-7oq z!MfFM`CZfTVzQ%m7UEe*z~KO*S=xJInk5A9Z-p_di0r~(wr4e+w$qF^$utaiY}km& zk=m{RUFO+UR>ukGjqVI`eZZZ7|EYl@4Gq7S(-?31a_=lU`8S}&z7DGWW}@0%${5G3 zSn7R(OTxRmc$LciQN3~tIdxa4Q1)vH55?x_zE@BDhdDKXJqqGgCh5LUPrT471#zjM z#4z1mKu-u%W{Rf1&Jt5}-vPy>DY^&o6-~9S9lD3GM6rQA3ZLp37#DsR8=FR7NJFQb zg^f`+$?c21Nb5Qe%xSuAv2{I7C91ZrXY|C2t&0<{w65RK6EC(dPJCGF`nv_*?5ZB>7K05W0+6XOZG<5gT%6O2?T}2s6HFmvvL`#B;{3whxdU55OflG` zTv0+q0TlqLARvkXQ-PS%UvmLzi&Jqh5u@86!!~us_5_(~N1YCHWg(d{LceK1>=*{I zdk~omKL(KlP33to;C{khV1YL9{y4fhWnR(ry->vw1xSTJ;50_1>wU9ltA>3L!GmD6 zu`1$-)yM7;P{L!pbL=ORJeOkni^w3w-I(T5BN@4(oF1?;*>NE5HaiLZ9HzhKN-VnI==sj$)CiDVAAH^KjMA_8H!0QUb*T=HY1f5LUwdj_^a-wq9hNP(h$ly^u`sxsn?JF)|5GmClvi z)A&j!^ve6B=QFf-lg#o*1ar?qznb@a?(YJggzj;JIwizf7f?EY{G>#ScAH$CD1T`U zT4yO~9Yl2jwFB?Ydc*Nfn;oZh58-%U-9Jq_0k@;diP~2( zCDPGIF*rr5QQeVnG{TDrv;}}~_l2Z_?QSa+5q>^tz&yBBW_)5m9H4~sgnymruV^$} zw7+0~F*Pa)-2!Tz0Jr_HfL+&^qa6V{w8hghkC6QGy88;u4)_GF*d}| z%86In*d9IcVjJVchqbY5^mV=&Hg*-TRMV$1;Rms?>bwBf7YC5;7!122h8zTqzquTZ zFA3ojFrJ3Y2_8=|RYU<90qJtD*zf#p>C#sB(jk+sW{n_Qi|toj|!Rm~R8ETu)QG zd^wnZ8j21A=DQC9U(8w_!Y67$4uL`@38?qd-6RiLkkz!@CWN?k+bTww*u%{|$HnxU1DTV_ROs%x1^WoKmtv zu=N$mFy!aCuqBglrI*Q8cE1Q6f-fvcWl67|ofBe7wy==+SHIjw0s5wem_oHZiW7%<7?jsbhB>$z-Aazr!}*P=BEnD?3y!ui!%m z^%wIYq5kWcyR2F};~;}XR4;Cu?h&m-CGh@rP^b>P|1Lf8Vw{T;uf!nk(GxGmAUN@1 zF^CW7>r_Ie)PACi-KI;fsqR{3!2UzDtumgg7+PY=DG%br0vZDQhbUQPxA?HY{yDu$ zi#gq3wO6h$eOynx*Z?{4N(205J@H}#V>3l$)CCnr%n} zyF|eLU+Ohj%=lNSjMbp)-{^@K+Z!idX>UK!6EC(mPJCE<`)_@nZ-%|SPTQiELu0}Z zVsF)X5p*pa%7+GBZ!8C0bMd)^TQO`YgjC>20dUOE9$w}!Z!mAYK0fq>J$N3X{mpj1lvu%iH{!e1(0G;1}rfYYae zZ3div1fM8yN}sgADaF|qT*iI|IQ=Hb1SiQb{7eB(*^E}%ZY}ai~7&SD2@~$K*zqJ-@fQD0do-luTbFY`XV^?;T52e>W&TCb#9Ls|5@#=L?pxxJ7QS zh^b1*w5U*lBvpXvv0Rx_uvBg^X`E|7F{^Pq{ofk|oBmm1-gRNquVqT4cqN{2 zwVrq}p1_F@iznQyuT!09T+;o~KT@ZYl|iUWz;td-R16d`^^}KmDunu9%m^fsKP-g$ ze!WtQIem}{RSjvi^u&uzkQ1*o!M>h&u?ceG!uEQ3A%Sfy(JLphv8FA17pGu zX<%1Y_(ZAFik+*^>vdRcai5`5R$JVc^u&uTjuWr6xIfnuFSa;NT&iaVP95UG7#mJf z@KD(yFE8uselslZTdYkg)%F8D>&0s0#FbT=b0UlxJ*TXyzOE-;+~9RNpP15)&pOVF z8+8mraE1HJ^%c}>Rk9O)Bb`1&iq)ezL`vsTn07L5Lfb7XO<+YYXR#t#&vCyEhnt9v zv}E-5#0qX#^mx0LzWa|rB73ZpIBBJB=RdBkqGV#iiBFRW$D`-mD(A?tHsT?0)-WE? z)`lnVwaus#@*hg4WP>wTqF&GMhepta!$N*0^6@-f+{otsG*Ug_GOjWWtk_yU(5TLf zOB*jGp}G?C552UpRKB#~6#*LjU>6rB7Nv_DlEvKO#tTrc#^Of3XfU^uw7ZmOqkICEEr`&Q!oL)DO%w*$(MR#Nx z8f2c+NmL@w1LB{gwzR4TIi-P$s}z*uhQy@{G$cVVTjW_zjwDJhX2?~vlc9=Kp>Qcd zdel>q@#G=~`zVGXqhzib_3_FEBe|eqR-~|t8pu>&g(3XB0B)w(i&r|(t0vlgY9g(e zOwhA&0(o}Z{0TC>Zo!oc^w30j0UNf0(Cqf&6L6q3y~V-++Na=khQCJr4!rHg1Ml!+ z2mA`vjk9x{$iBAkhv3jG<>T>DvK#NY@S?7<0S9SyV@R39IF}uTiZ75k$LmF*VR>*YBIJTOToksK-n~SR6g-&z zXju4@0>d`FR>y*$7EBup$wKB!hJ<@78uT2aD|ry552in43X?r3 zLja1hK}8*qDJHu+rner!O(CFhJmzr+Tu4GL>sw8~-!fVjp0Etn;6)23$OLqtHk_OY z8gW_%94X#*HlQz(IWr10^0QgY<`*4 z3#_Q+8*q+1y3PRan} zG(xKj%@aa%OhNk6bvL~e^f}jWH#6ih1y4LPDEaFJc^q)iWKUWBWycEJv<~R@D|XoJ zKxNaRxdy$c725IfDY5`I*)@{xnFzoy5ZEMpg0o&|ZWy++Zg=1x*zZ`!N7J9BvsHsn zS1-UUR?c3Hj^8x7Y8RR|{Ky7EmOkrmpk=B;$bBm6!MSgE{|&v=hWmj{upYnZcx|u& z;TZOztANWiMpjLOyYC#u13oO_coYB2Wu4qE8Q-%endUp)C zss}D6zzb?FkiGn}9Wd5To4K`3veWWT;}th#in$Z$zhH`RaGe94BQ)5F%hYi80#jgG zA$V0V8<^$eO*mv|(dS~rB?Il_%oVwSB^F1f{5z`V3$^Oo~os4?o@GH30C4iwfzJRgY zhfthtck(5>-vz>($bO1x9#7Y!zZ`VWfkXo2$|!?osHKnX^|N4cv>?oR@Mrw=Xa39# zal4R<`+~G;!3?$3^48zPCw_+rs=zI_bdNCWhd4oSaVDTu1!kzFitRDs7yFAq9SF)% zT#-5>7sGQJhilb=fqE@(KhXF$p1cgQ=Mj!wVG3kibBC=Z@JgGO|4JQWENCO9K zmVz;o$j62aHHGDaCPA@G1vEr9WtRhR^FspMTr dG95y9IbO39wQ$H@$FOUrg|Q|N%NTyT{C^H}61@Nb literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.doctree b/.doctrees/models.node.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f13f9994ccf7bfec591022c7c5c93fd0327984ab GIT binary patch literal 35791 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 QA(^g|^^}H2NafQ111-AD7XSbN literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.generator.doctree b/.doctrees/models.node.generator.doctree new file mode 100644 index 0000000000000000000000000000000000000000..0c3a1e04a0523951d6f257ab38d39670a5eec4ff GIT binary patch literal 28547 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 literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.generator.file.doctree b/.doctrees/models.node.generator.file.doctree new file mode 100644 index 0000000000000000000000000000000000000000..2c5f1a11c196b205abffd250e4348b1d452b0b6e GIT binary patch literal 41536 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 literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.output.device.doctree b/.doctrees/models.node.output.device.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f840767ed556d81a4c44fb47af450b46ab003ba4 GIT binary patch literal 3778 zcmb_fTZ4kc2=$DQdcFri$(E>Qq+5sU z8D%R|)M{n#aOa!j;a~~VO0q(W)Fd>PDwa7liM$-#uf6{W4O6i0eHd7GXTVxM0#;>B z&nHwbq(m>IMDI9%dX+y@Y(K&!IvdydP{7prP;AdoYvV!5tILthG!n1j*BkOFZo?15 zjm+S-31b#)OJp&d%oLSSZ;qv_U4mswlv%uOPvumoP*ji*-+E@ey&gGRvBraa%n{z+ z(T@6j$U))C)Q~=`v1gkR9Jq)!*RlPBcpsRCQapCt0kcV+vS33EwVA1&{oq`Myg~|>}>lNnivGF zZcBV)$9BdHwUlb992PM}<<>OKu~-ey5a`~;a-~`tm0-25Wkh_%_PcnlwUaT%ujbz8J zDV9s6Ny7G6;_jccE1V|HvSqi}L;x#IwJGXDE!&FO(2Vh1cb}>ZSmA_XG=-$26^)p8 z%Du2%k)e?imPIngDQ7!Ik9uGC3W4tnM>h#mN-Dx>7AFju(DtTA+S!dzduFt>N-fS_ zoZFdG!T+}1pmb_Lef7f8jk%k4(>qWAB@TQNIOOblLbI{KAON^ytWRR_uxAvDP|Zoq z&_QE7$eo&5|OKCVQd~fu9>B76lz9-jT}6r8*n<4Z8+s z(5Nz6PEVjrb&QOJZ`7DQ&iOAqQZVJuATVBAjCikNLTi@b=ax??&?Xy$g^5Uob`LhM z*>28q0#FzdF)9ID^O7Nj?LIT?r(Em2xHT9+T=esDD(Oo#9yoi}pDYc)NupVb@Mwf% z8S>uMn_mIXt{O#i>b+#D{)<{YGL?G1?lRREOpnSpkn;ns(*%!oG#w&^V$I$CWqT2X zOi7cQjRT}WQDg4VZWafbrW3-&m?!vwyr&ZBdB0Yq6j}D0K~fh0>P)!~OOnWlR?uFI zIE6h3d`LE+TtbN3yC%mIe$Fk2*Qy8{f;}=4*$5n{tHNntCot*EofD}iZz5?(ML%%v zI&dZ(vKaY$024T48jqZfaB7#Zl!}C4Bv-5)J73tXYN!TTlToN?hjx)=dwy`W%b}Ja zc|k=qLxJSbL{l|ps7)Zw7K{S5GzN9hCiY|MV^q5%(lE+G3~i%k(e^2XDH!r4FAU$? z{1t!6@9^9FA^(*>=TD98_+5RF17$xYzB=T04*A1F{`}DJD_-&vbMS56!}+`XDO%$b zjP&hbGTo(=rl_E)^>JYSGBWXS5QAAX?%5bb~Tbo0-C`G zG|;6xmHaiL|IGb}T7dt&P*w21QUUgd2b(f_M7-LFO9HQoEJ{r56K3qWyAu0KUlm0^ IeVAeYKXDenQvd(} literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.output.display.doctree b/.doctrees/models.node.output.display.doctree new file mode 100644 index 0000000000000000000000000000000000000000..52d65409eb64e0a099e8ab0783c74ddd10dcc319 GIT binary patch literal 3739 zcmb_fTWcIQ6n1Ry+Pk*bcG84G;?!wLn7E}ag+hYR&S+P{Goz`b ziPsMyEg>N$B9un`C;fGO>ZiHwC5@?}hK145(a|}dzH{-fjX!_yEaZQ7Q>R=c;~ove zM21W|yBf+Mi&C8)4_})w@JT;DQ+ZL%q<4d+#Ms#SGBatw7m<_0HQ)84EWClq1$d^Q@eUvLfM74$x z-;IRE#n)<>rIW<~-YPcqI+MI={x3_>LX*xr|v~Wl6$R|5&P{{iDmTIHoUYU9cbbP5F3m%`H$|1rNBQNuflLfCspiXj@(DhJ^Wj6L@Y#Yh3$`JW zkd3G6L{UOMNI$y*&y>j1a?dWORH&j%0JX3EtAC)xID4aj_6$57Zyp*)J;PIwvUIjc z2v&Qv$DiBH(pHTWt9f2-O+Y;JMF7IYa#imBl_XV(oG|0R6x8=FUz&OW6pjz)d0jU7 z9S_I_+X*t|3oNP2>3St8%Bo$}%ovf3&|9|aW-(Mbn?h%sKhY?|!&TjeZyws#h@n7I zBbCDaR4*HLn~epqGSpZ+0gW^2FBUVqRvcNY2;R%-I?2&Gr|9|ox2pUf!|81htTQSft;l^$K04y-|P1w*1a?zHF{Ew`p#bVnz;keB!;0^BHb|LLEgQ2_eBc^(SnPGkha=y<^9O1H-p#!8)Xt+CAwL2hWOzPaM10Whzjk#01 zrB4z=$ApU!kMIL|mm}$Uzpi77Ec+!xQfmNpDPI>$63Kv;(C!4B!XG?*k!(OYhY+Wa zvJ_YN@im`G%OY?J_Q*gaLvWy~3KxBy!1OYwCt^?DNYWw|{Sd{iV4!;9-iD+$7HlC zhi6R-7-}z6BS1FD?8Y>Cb2K*sffVr10fY;QuThm=@odwQLJyA#vd04%)%lRCel#bn zwOcb5Th*=kp^G#2(QB0P&F%8Mt#W6{=kB2t-2+XrU|nrTiV<|E2pL w)d2rcp|0RxAPxQ(7uJPzM!Z&wa|*ACB#5%mr_9K+w;lRgUzSBbe`JH+KSr3ZqW}N^ literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.output.doctree b/.doctrees/models.node.output.doctree new file mode 100644 index 0000000000000000000000000000000000000000..cde941a6d35ec19c91a4596fb1f94e12e3b96e3f GIT binary patch literal 11966 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 literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.output.file.doctree b/.doctrees/models.node.output.file.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c2c6611cd15477a659ef0ef2fd3caea012fae607 GIT binary patch literal 18297 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 literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.processing.doctree b/.doctrees/models.node.processing.doctree new file mode 100644 index 0000000000000000000000000000000000000000..b18c4e58aedf4adbc0a14340e4506d402a56cb94 GIT binary patch literal 98701 zcmeHw3zS?(d8Q<5B+ZN-mTbunS#n#(o{=n#Y`_5vzhq0sLef}RvJrMntEcp2{;N8u#2S`{TkR>^UWkc9x zzrP;0s_vuu-tHNV#Nu;2>b_m|zv}<1zN%aG*Xsw~v1rlaMf6{=rZwYM>$78}N~PYY zIIT{wqS7e0r=7ard9t(h4V}}S(O|GyI@xNpn`NgHEJBI0Tdh@^PQCL`Cs<9z{c5c> zCh9M5Ic2}vsE5_v0e6|Z{GraMI~WZ3RlnwFKLwko!B*5Bn`t)6PODX|PZefL<>RF( zr$aSSap@6fmL%$0{!JY&^Rk%|B=kG(+F-C4s^ne}EEAfH2TNP!^ z_X_s{cT-T_={BaFoy~T=?lgCvY&4JWyl2L#-*M-@;-OQ%+o%`sYNC?;2Po0nnQX1G zW(%5b-oKnw<2yI#>6oBM&g2v%y8{idTkg7__sk-IV2 zkgPiz3GLjhvZfgwPjiqlr(TAqH9K$aj0dC1q{b$llHYDRMfh5?RQ4OZ^rp1Z)tWB| z7E+3|oGA*WE~UV%S}#o?Fy7p8f|b>Jxz?^Ylhqp6$$hzd*uBqvh5Je;STS9itvEBj z+u6Sq-dUPqp$1=`sx>A$XM$yJwNgQ3o(Wb7GU0<2_4f3H({w7G{fmMj7Kp7zy><#^ zhY;Y(h}5Wex|>*IE{8AN9`%4=jcC6eC!3|28E99EI>oK1r#S_j$O)Y&7;b5PSdu;! zeXP0Ikcy?y#Ug(0DmNd3o1;D2WIon?YzXv6%E@Q*IeA-i^0m56f*~j*IVye3rxtZU z%oes=Qk)A8QX|KMqEgQ+MV0<<&!_(rn*J9<eW+%9s ztMHPv7$P-00ci$BcUWxEahHwzof5h4``|D_T;7Gb@0Yz`myX61aT$$8FmG_(U1aQ0 zHXIbHb(^ePJAv)zF`{G@by2VsBXK!q)=^k|HT_a-RWZm=Poj9+^xRA)q9SE+l1jLxMuDy^l{NJY=eiYqvb!rD}$0P_= zkwC2J*>^`D0Nn4pKcFc5U&^-b-vJqLRR)}dKfzD4>DJ}JI8bm7~G^WACi9SoLL z>kM~m%$8D5CHe6$isc=4mN4dIsa^AnCrY)pW3mq}YPDx(8co00nl3f{huaOp_h;am z-tD?n3YtVa4&lk(rM&pX_(vc3(~7TS#bv)DeIMfR$rgIru@hD2BmvS+utt6?mg;5K zXohZM)ga~_eyKU-_?_T+MLt5xIYMF&gjo!#R4W~CDMSpG;R`yXjyp~^DH>AqaZ@wR zXBe`<+z39?0pvl*H6}bv_BuxJ2g|q|onWJ-Yl0wr+;Eo#D<<2u8Vdz3)ld=evIxKT zTOIEtgkq21+`&YSeo!T;kNFb-Ro1s4s{a%95n6XyZUA~~6InGU8Vm+0uBHHAUES^X z-BH49Z&zU#dTJ)$u4AuF(L(j@Me6Iv4ux~qaeO_-+?mG5<$|OZMZZFZW-~(pP8J0# zF&(U6R4C4(Npy+sm?KdzC0kyr0vD8O8hP(mNfh4ct~NE$-_Hc_0U!#`LJ;y$|(*<#^zqnnBnI{|Sci#F?F` zRm)W$QyD67vecv*&>$L7_#$&7l8v{jaDP2~ZtSU<2|{=Q>9r|%>>NT5v>31$wkA)r z0V5Ls-*EBIP4EL9UPtn=!1msVj}pfR|9Zr&wh9z`1^nA?IhBInC=kvn_%5E+XWD*Y zqCGk3Gz%xIzFR02%1+aVFBMADSeft%fwfB0Gngli6&Nv22i;NOr0djUWQG_&pYZ@U zMwD1#B&}jzol2I;ST5CV!ad?N8?8b^h)Ptk^5hS3`Dn%w)hPsb|KHm|VTC^wuHtUW zuyA!AIX*h?HMAg9uhPt|7y+joCD8Kf#gRfqbokR+cYpNnV4&UMQs=Ir;=z0N+;?Da zaeVi|y@gRsOt$VqBsc{cV<|ky>3A19%3KfuP{s&ZIChMUd1?$CqqsYEZ0pdz@k93= zDIVOtZ#?_haeK`wBh+mJJ3& z%0D%)+ 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 literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.processing.encoder.doctree b/.doctrees/models.node.processing.encoder.doctree new file mode 100644 index 0000000000000000000000000000000000000000..bbeb1b8bcc1c3df5ea7280f0a5961e33a56333be GIT binary patch literal 37969 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 BImQ40 literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.processing.segmenter.doctree b/.doctrees/models.node.processing.segmenter.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4d41a468e76b1715ba69e0288bebfd3655c052b4 GIT binary patch literal 37852 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 aPQ6@1kRz1)DlO1>92r)LT)>5R7XKg38YCb9 literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.processing.trainable.classifier.doctree b/.doctrees/models.node.processing.trainable.classifier.doctree new file mode 100644 index 0000000000000000000000000000000000000000..727979db4e3cdc07850e5b7e1d27a5ac913e7e1c GIT binary patch literal 4387 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 K>3B*q9sM6{=bN|y literal 0 HcmV?d00001 diff --git a/.doctrees/models.node.processing.trainable.feature_extractor.doctree b/.doctrees/models.node.processing.trainable.feature_extractor.doctree new file mode 100644 index 0000000000000000000000000000000000000000..bfa0d06a7ac5df02f9d61f7a583f0a33958232e4 GIT binary patch literal 4542 zcmb_g-HTjB7N2C&J=62iGm{t*Ox(z#j+pND!3T}(A_f8yoL$yMScnwW_f~h6bMLKd zeIz}I=spNG)SI=C2f-J?KfwQB-}isoU)}HS#9<~l&~WQi)u}qa^E;=`neTf4`R!<< z_;Uw3=OSB-X&h%VX4<>$SVlHwnejjRxBuzMp2Q`X~M=c zMvYbM5n&4mBO}$FoJOZ~&U{b{t=ImEDJZ?TvW@2```(w<_Hzo`jORygKpHUkrt4Q2 zoVaU=$e2H|Q|fl8F-lCW0d@haO%dyW%T|<7ts%sBFQaMswH@2M9ZX?{VzaQux-CQJ zVaoFZ{wm+&xA-Q%?Y^CGnX-wpS;o}liBzYPzvV3Z`2Hv4?`MX~j66`-bp8a4(36Ye z+#)kp8YsN>@T#5i-I5BmFZp3Tb~~ThDRkQe78d?^c|}yA3X|R~O*-MP1>pFffEIrp z{`)h2Z{YV9es2Q_{!W3ws9etP;s(9$2DhWz6KTDDP1;em)52LRJI9>AUKFPeAIFi- z@01wS5L{SIhlyP^Eo`4$4z>p!*tS<-`%7urD8%WgjkHk{X`?FAMoplNVA!ZKtVOy~ zR0RCFA={x+2O-+^^ty9!<#U|#`HMJ5pC*i|>=AiRB3X6Xh1GYRR;k~p)pzDSKz35>53NEwZdLoP2qVrgl@7V8VF1Ll7DN$tlV|Oj5LV0(u#P-7g z!iC5ms9R7#9W@ovOciX6z3YEY6ANP0B^5t7af3O-n@&;Bcno5S3c}Dd$6&WShCufz zhC9{Jssy8bBO?+jhcJuddVzFj-d&$bX)F;;muux2)Tf20MzZ>>%e zrj%5K(=1LHqOBjU8X4~nq&2HrdW9D6Zm-R(so?)}!%}H`fqLt$)rqy8?l2gjff5Hk z2@LXXKcU&&qErRkF~(O>G`ky$MN-8iW~k(191~K;iR&W*XRr})h?wLk48_9pz8g|& zBxyzNssN+*W1HrrVI5E{1On+%Wi$y24+;sO&2;d6E6O#qu_TK$@ad2(a;X{V?kp%0 z8S+?YQS$SE#6pL19EMc4+^VC2-*tO1MuY#fsQf{hY8jb{P#2;GemQ*M5Y1Fr1NR1P zG5o!Y?xGojpGP62K$~n17A7JU#(#SFmK)|QCjf;Z5YZ&y=6gXhrMP>D4EG8*CfD~S z6NvRVFRJ6QRP%{_2%*?;|8U#g1|d_@#Aagv(a3hpFWsR&%M4u*F6KPJ59Ga; z$iVwOol->ER~A970o09RTnPA!sKR z8oA=yM^!@zvL>@Kr!Czk%N~aY%59gq1i=d`;=vUN4nqu8bB5dm;vC^ppq4?C3EIS= zUHS&uZbe$QR1ibktQqt}2%#H;d@Bgc?_>Te|ApV@AMr>0U)*xVf95|~HwY`tS&l1* z#^l!}zrW;%K1>QnTe{qnkPcCR|#=AGqFnZy3*-gNx2SGK&YfsnKaQ< zEPZKB*sLC`XdKk17MrfG=*LT?On4e^uIs91Hrx*KZzOHVuHNlNGD$#F*nkIk>wYEw z5zP7C{{y)M|3N@jLeH-eJ>`K-8eS3aHsT@xc10E?HVy$d58U60!%I;m)lj|I>G=Pv CP~{!~ literal 0 HcmV?d00001 diff --git a/.doctrees/models.utils.doctree b/.doctrees/models.utils.doctree new file mode 100644 index 0000000000000000000000000000000000000000..2d1a8f43999b038448a3da772fed26e96a1eaa62 GIT binary patch literal 24893 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 KK)i2@>G(fjq+s{} literal 0 HcmV?d00001 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 0000000..e0d5ede --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,288 @@ + + + + + + + + Overview: module code - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + +

+ + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ + +
+ + + + + \ No newline at end of file diff --git a/_modules/models/exception/framework_base_exception.html b/_modules/models/exception/framework_base_exception.html new file mode 100644 index 0000000..0c460a0 --- /dev/null +++ b/_modules/models/exception/framework_base_exception.html @@ -0,0 +1,274 @@ + + + + + + + + models.exception.framework_base_exception - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.exception.framework_base_exception

+
[docs]class FrameworkBaseException(Exception): + """ + Base exception for all framework exceptions. + """ + def __init__(self, exception_type: str, module: str, name: str, *args): + super().__init__() + self.message: str = f'error.{exception_type}.{module}.{name}' + + def __str__(self): + return self.message
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/exception/invalid_parameter_value.html b/_modules/models/exception/invalid_parameter_value.html new file mode 100644 index 0000000..19e1b1d --- /dev/null +++ b/_modules/models/exception/invalid_parameter_value.html @@ -0,0 +1,277 @@ + + + + + + + + models.exception.invalid_parameter_value - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.exception.invalid_parameter_value

+from models.exception.framework_base_exception import FrameworkBaseException
+
+
+
[docs]class InvalidParameterValue(FrameworkBaseException): + """ + Exception for invalid parameter value. This exception is used when a parameter value is invalid. + """ + def __init__(self, module: str, name: str, parameter: str, cause: str): + super().__init__(exception_type='invalid.parameter.value', module=module, name=name) + self.message: str = f'{self.message}.{parameter}.{cause}' + + def __str__(self): + return self.message
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/exception/missing_parameter.html b/_modules/models/exception/missing_parameter.html new file mode 100644 index 0000000..b71f1c5 --- /dev/null +++ b/_modules/models/exception/missing_parameter.html @@ -0,0 +1,274 @@ + + + + + + + + models.exception.missing_parameter - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.exception.missing_parameter

+from models.exception.framework_base_exception import FrameworkBaseException
+
+
+
[docs]class MissingParameterError(FrameworkBaseException): + """ + Exception for missing parameter. This exception is used when a parameter is missing. + """ + def __init__(self, module: str, name: str, parameter: str): + super().__init__(exception_type='missing.parameter', module=module, name=name) + self.message: str = f'{self.message}.{parameter}'
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/exception/non_compatible_data.html b/_modules/models/exception/non_compatible_data.html new file mode 100644 index 0000000..2c6b0f0 --- /dev/null +++ b/_modules/models/exception/non_compatible_data.html @@ -0,0 +1,275 @@ + + + + + + + + models.exception.non_compatible_data - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.exception.non_compatible_data

+from models.exception.framework_base_exception import FrameworkBaseException
+
+
+
[docs]class NonCompatibleData(FrameworkBaseException): + """ + Exception for non compatible data. This exception is used when a data is not compatible with the expected data. + """ + def __init__(self, module: str, name: str, cause: str = None): + super().__init__(exception_type='non.compatible.data', module=module, name=name) + if cause is not None: + self.message = f'{self.message}.{cause}'
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/framework_data.html b/_modules/models/framework_data.html new file mode 100644 index 0000000..5230495 --- /dev/null +++ b/_modules/models/framework_data.html @@ -0,0 +1,631 @@ + + + + + + + + models.framework_data - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.framework_data

+from __future__ import annotations
+
+import copy
+from typing import Final, List, Dict
+from models.exception.invalid_parameter_value import InvalidParameterValue
+from models.exception.non_compatible_data import NonCompatibleData
+
+
+
[docs]class FrameworkData: + """This class is used to store data in a format that is compatible with the framework. + It is used to store data that is used by the framework, such as the data that is + used to train the model, or the data that is used to test the model. It is also + used to store the data that is output by the model, such as the predictions that + the model makes, or the data that is used to evaluate the model. + + :param sampling_frequency_hz: The sampling frequency of the data. Defaults to None. + :param channels: The names of the channels that the data is stored on. Defaults to None. + :type sampling_frequency_hz: float, optional + :type channels: List[str], optional + + :raises NonCompatibleData: Raised when the data that is being input is not compatible with the data that is already stored in the ``FrameworkData`` object. + """ + + _MODULE_NAME: Final[str] = 'models.framework_data' + _DEFAULT_CHANNEL_NAME: Final[str] = 'main' + + def __init__(self, sampling_frequency_hz: float = None, channels: List[str] = None, ): + if channels is None: + self._channels_set = None + self.channels = [] + else: + self.channels = channels + self._channels_set = set(self.channels) + self._init_data_dictionary() + self.sampling_frequency = sampling_frequency_hz + +
[docs] @classmethod + def from_single_channel(cls, sampling_frequency_hz: float, data: list): + """This method is used to create a ``FrameworkData`` object from a single channel of data. + + :param sampling_frequency_hz: The sampling frequency of the data. + :param data: The data that is to be stored in the ``FrameworkData`` object. + :type sampling_frequency_hz: float + :type data: list + + :return: A ``FrameworkData`` object that contains the data that was input. + :rtype: FrameworkData + """ + + class_data = cls( + sampling_frequency_hz, + [cls._DEFAULT_CHANNEL_NAME] + ) + class_data.input_data_on_channel(data, cls._DEFAULT_CHANNEL_NAME) + return class_data
+ +
[docs] @classmethod + def from_multi_channel(cls, sampling_frequency_hz: float, channels: List[str], data: List[list]): + """This method is used to create a ``FrameworkData`` object from multiple channels of data. + + :param sampling_frequency_hz: The sampling frequency of the data. + :param channels: The names of the channels that the data is stored on. + :type sampling_frequency_hz: float + :type channels: List[str] + + :return: A ``FrameworkData`` object that contains the data that was input. + + :rtype: FrameworkData + """ + + class_data = cls( + sampling_frequency_hz, + channels + ) + class_data.input_2d_data(data) + return class_data
+ + def _init_data_dictionary(self): + + """This method is used to initialise the dictionary that is used to store the data. + For each channel, an empty list is created. The list is used to store the data + that is input on the channel. The dictionary is created in this class method + because it is only created once, and it is not created every time that the + ``FrameworkData`` object is extended. This is because creating a dictionary is a + computationally expensive operation, and it would be inefficient to create a + dictionary every time that the ``FrameworkData`` object is extended. + + :param None: + + :return: None + """ + + self._data = {} + for channel in self.channels: + self._data[channel] = [] + +
[docs] def rename_channel(self, current_name: str, new_name: str): + """This method is used to rename a given channel stored in ``FrameworkData``. + + :param current_name: Existing channel key + :param new_name: Key to replace existing channel key + + :return: None + :rtype: None + """ + if current_name not in self.channels: + raise InvalidParameterValue(module=self._MODULE_NAME, name='data', + parameter='current_name', + cause='must_be_existing_key') + if new_name in self.channels: + raise InvalidParameterValue(module=self._MODULE_NAME, name='data', + parameter='new_name', + cause='must_be_non_existing_key') + self._data[new_name] = self._data[current_name] + del self._data[current_name] + self.channels.remove(current_name) + self.channels.append(new_name)
+ +
[docs] def get_data_count(self): + """This method is used to get the number of data points that are stored in the + ``FrameworkData`` object. This is normally used to check that the data that is input is + compatible with the data that is already stored in the ``FrameworkData`` object. + + We only return the first channel length because we have already checked that all + channels have the same length. When there is no channels, we return 0 + + :param None: + + :return: The number of data points that are stored in the ``FrameworkData`` object. + :rtype: int + """ + + if len(self.channels) == 0: + return 0 + return len(self._data[self.channels[0]])
+ +
[docs] def get_channels_as_set(self): + """This method is used to get the channels that the data is stored on as a set. If the + channels have not been set, then the channels are set to the default channel name, + and the channels are returned as a set. + + :param None: + + :return: The channels that the data is stored on as a set. + :rtype: set + """ + + if self._channels_set is None: + self._channels_set = set(self.channels) + return self._channels_set
+ +
[docs] def extend(self, input_data: FrameworkData): + """This method is used to extend the ``FrameworkData`` object with the data that is input. + The data that is input is checked to ensure that it is compatible with the data that + is already stored in the ``FrameworkData`` object. If the data is compatible, then the + data is extended. If the data is not compatible, then an exception is raised. + + :param data: The data that is to be extended. + :type data: ``FrameworkData`` + + :raises NonCompatibleData: Raised when the data that is being input is not compatible with the data that is already stored in the ``FrameworkData`` object. + + :return: None + """ + data = copy.deepcopy(input_data) + if len(data.channels) == 0: + return + if not data.has_data(): + return + + if len(self.channels) == 0: + self.channels = data.channels + self.sampling_frequency = data.sampling_frequency + self._init_data_dictionary() + + elif self.sampling_frequency is not None and data.sampling_frequency is not None and self.sampling_frequency != data.sampling_frequency: + raise NonCompatibleData(module=self._MODULE_NAME, name='framework_data') + elif self.get_channels_as_set() != data.get_channels_as_set(): + raise NonCompatibleData(module=self._MODULE_NAME, name='framework_data') + + for channel in self.channels: + try: + self._data[channel].extend(data.get_data_on_channel(channel)) + except KeyError: + raise NonCompatibleData(module=self._MODULE_NAME, name='framework_data')
+ +
[docs] def input_2d_data(self, data: List[list]): + """This method is used to input 2D data into the ``FrameworkData`` object. A 2D data is a + list of lists. Each list in the list of lists is a channel of data. The data is + checked to ensure that it is compatible with the data that is already stored in the + ``FrameworkData`` object. If the data is compatible, then the data is input. If the data + is not compatible, then an exception is raised. + + :param data: The data that is to be input. + :type data: List[list] + + :raises NonCompatibleData: Raised when the data that is being input is not compatible with the data that is already stored in the ``FrameworkData`` object. + + :return: None + """ + + if len(data) == 0: + return + + if len(data[0]) == 0: + return + + self_data_len = len(self._data) + input_data_len = len(data) + if self_data_len == 0: + raise NonCompatibleData(module=self._MODULE_NAME, name='framework_data') + if self_data_len != input_data_len: + raise NonCompatibleData(module=self._MODULE_NAME, name='framework_data') + + for index, channel in enumerate(self._data): + self.input_data_on_channel(data[index], channel)
+ +
[docs] def input_data_on_channel(self, data: list = [], channel: str = None): + """This method is used to input data onto a specific channel in the ``FrameworkData`` + object. + + :param data: The data that is to be input. Defaults to []. + :param channel: The channel that the data is to be input on. Defaults to None. + :type data: list, optional + :type channel: str, optional + + :return: None + """ + + if len(data) == 0: + return + + if channel is None: + if len(self.channels) < 1: + self.channels.append(self._DEFAULT_CHANNEL_NAME) + channel = self.channels[0] + if channel not in self._data: + self._data[channel] = [] + + if channel not in self.channels: + self.channels.append(channel) + self._channels_set = None + + self._data[channel].extend(data)
+ +
[docs] def get_data_single_channel(self) -> list: + """This method is used to get the data that is stored on the first channel in the + ``FrameworkData`` object. Since no channel is specified, the first channel is returned. + + :param None: + + :raises NonCompatibleData: Raised when the data that is being input is not compatible with the data that is already stored in the ``FrameworkData`` object. + + :return: The data that is stored on the first channel in the ``FrameworkData`` object. + :rtype: list + """ + + if not self.is_1d(): + raise NonCompatibleData(module=self._MODULE_NAME, name='framework_data', + cause='operation_allowed_on_single_channel_only') + return self.get_data_on_channel(self.channels[0])
+ +
[docs] def get_data_on_channel(self, channel: str) -> list: + """This method is used to get the data that is stored on a specific channel in the + ``FrameworkData`` object. + + :param channel: The channel that the data is to be retrieved from. + :type channel: str + + :return: The data that is stored on the specified channel in the ``FrameworkData`` object. + :rtype: list + """ + + return self._data[channel]
+ +
[docs] def get_data(self) -> Dict[str, list]: + """This method is used to get the all data that is stored in the ``FrameworkData`` object. + + :param None: + + :return: All the data that is stored in the ``FrameworkData`` object. + :rtype: dict + """ + + return self._data
+ + def __getitem__(self, item: str) -> List: + """This method is used to get the data that is stored on a specific channel in the + ``FrameworkData`` object. This is a wrapper for the get_data_on_channel class method. + + :param item: The channel that the data is to be retrieved from. + :type item: str + + :return: The data that is stored on the specified channel in the ``FrameworkData`` object. + :rtype: list + """ + return self.get_data_on_channel(item) + +
[docs] def get_data_as_2d_array(self) -> List[list]: + """This method is used to get the data that is stored in the ``FrameworkData`` object as a + 2D array. The data is returned as a list of lists. Each list in the list of lists is a + channel of data. + + :param None: + + :return: The data that is stored in the ``FrameworkData`` object as a 2D array. + :rtype: List[list] + """ + return_value = [] + for channel in self.channels: + return_value.append(self._data[channel]) + return return_value
+ +
[docs] def get_data_at_index(self, index: int) -> Dict[str, list]: + """This method is used to get the data that is stored in the ``FrameworkData`` object at a + specific index. It basically returns the data at the specified index for each channel in the + ``FrameworkData`` object. This is used to get the data at a specific time step. + + :param index: The index that you want the data from. + :type index: int + + :return: The data that is stored in the ``FrameworkData`` object at the specified index. + :rtype: Dict[str, list] + """ + + return_value = {} + for channel in self.channels: + return_value[channel] = self._data[channel][index] + return return_value
+ +
[docs] def has_data(self) -> bool: + """This method is used to check if the ``FrameworkData`` object has any data stored in it. + + :param None: + + :return: ``True`` if the ``FrameworkData`` object has data stored in it, ``False`` otherwise. + :rtype: bool + """ + + return len(self._data) > 0 and len(self._data[self.channels[0]]) > 0
+ +
[docs] def is_1d(self) -> bool: + """This method is used to check if the ``FrameworkData`` object has data stored in it on only + one channel. + + :param None: + + :return: ``True`` if the ``FrameworkData`` object has data stored in it on only one channel, otherwise ``False``. + :rtype: bool + """ + return len(self._data) == 1
+ +
[docs] def splice(self, start_index: int, count: int) -> FrameworkData: + """This method is used remove a given number of data points from a starting index and returns the removed items. + + :param start_index: index of removal start + :param count: number of data points to be removed + + :return: ``FrameworkData`` with all original channels, and removed data. + :rtype: FrameworkData + """ + return_value: FrameworkData = FrameworkData(self.sampling_frequency, self.channels) + end_index = start_index + count + for channel in self.channels: + return_value.input_data_on_channel(self._data[channel][start_index:end_index], channel) + del self._data[channel][start_index:end_index] + return return_value
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/generator/file/csvfile.html b/_modules/models/node/generator/file/csvfile.html new file mode 100644 index 0000000..a29e5f6 --- /dev/null +++ b/_modules/models/node/generator/file/csvfile.html @@ -0,0 +1,420 @@ + + + + + + + + models.node.generator.file.csvfile - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.generator.file.csvfile

+import abc
+import os
+import csv
+from typing import List, Dict, Final
+
+from models.exception.invalid_parameter_value import InvalidParameterValue
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.generator.single_run_generator_node import SingleRunGeneratorNode
+
+
+
[docs]class CSVFile(SingleRunGeneratorNode): + """Node that reads data from a CSV file and sends it to its outputs. It can be used to read data from a file + and send it to a processing pipeline. + + When the node is initialized, it reads the CSV file and stores its data in memory(FrameworkData class). When the node is executed, it + sends the data to its outputs. + + If you want to use this node in your pipeline, you must define the following parameters in the pipeline configuration.json file: + + **name** (*str*): Node name.\n + **module** (*str*): Current module name (in this case ``models.node.generator.file.csvfile``).\n + **type** (*str*): Current node type (in this case ``CSVFile``).\n + **file_path** (*str*): Path to the CSV file.\n + **sampling_frequency** (*float*): The sample frequency used to collect the data in the CSV file.\n + **timestamp_column_name** (*str, optional*): Name of the column that contains the timestamp data.\n + **channel_column_names** (*List[str], optional*): List of column names of the channels that will be read from the CSV file.\n + **buffer_options** (*dict*): Buffer options. + **clear_output_buffer_on_generate** (*bool*): If ``True``, the output buffer will be cleared when the node is executed.\n + **outputs** (*dict*): Dictionary containing the node outputs. Where you want to send the data read from the CSV file to, in other words, the next node in the pipeline.\n + """ + + _MODULE_NAME: Final[str] = 'node.generator.file.csvfile' + + OUTPUT_MAIN: Final[str] = 'main' + OUTPUT_TIMESTAMP: Final[str] = 'timestamp' + + def _validate_parameters(self, parameters: dict): + """This method validates the parameters passed to this node. It checks if the required parameters are present and if they have the correct type. + + :param parameters: Parameters passed to this node. + :type parameters: dict + + :raises MissingParameterError: If a required parameter is missing. + :raises InvalidParameterValue: If a parameter has an invalid value. + """ + if 'sampling_frequency' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME,name=self.name, + parameter='sampling_frequency') + if 'file_path' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME,name=self.name, + parameter='file_path') + if type(parameters['sampling_frequency']) is not float and type(parameters['sampling_frequency']) is not int: + raise InvalidParameterValue(module=self._MODULE_NAME,name=self.name, + parameter='sampling_frequency', + cause='must_be_number') + if type(parameters['file_path']) is not str: + raise InvalidParameterValue(module=self._MODULE_NAME,name=self.name, + parameter='file_path', + cause='must_be_string') + if os.path.splitext(parameters['file_path'])[1] != '.csv': + raise InvalidParameterValue(module=self._MODULE_NAME,name=self.name, + parameter='file_path', + cause='must_be_csv_file') + if not os.path.exists(parameters['file_path']): + raise InvalidParameterValue(module=self._MODULE_NAME,name=self.name, + parameter='file_path', + cause='file_doesnt_exist') + if 'timestamp_column_name' in parameters and type(parameters['timestamp_column_name']) is not str: + raise InvalidParameterValue(module=self._MODULE_NAME,name=self.name, + parameter='timestamp_column_name', + cause='must_be_string') + + if 'channel_column_names' in parameters: + if type(parameters['channel_column_names']) is not list: + raise InvalidParameterValue(module=self._MODULE_NAME,name=self.name, + parameter='channel_column_names', + cause='must_be_list') + if len(parameters['channel_column_names']) < 1: + raise InvalidParameterValue(module=self._MODULE_NAME,name=self.name, + parameter='channel_column_names', + cause='is_empty') + if any(type(element) is not str for element in parameters['channel_column_names']): + raise InvalidParameterValue(module=self._MODULE_NAME,name=self.name, + parameter='channel_column_names', + cause='must_contain_strings_only') + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + """This method initializes the parameters of this node. + + :param parameters: Parameters passed to this node. + :type parameters: dict + """ + super()._initialize_parameter_fields(parameters) + self.sampling_frequency = parameters['sampling_frequency'] + self.file_path = parameters['file_path'] + self.channel_column_names = parameters['channel_column_names'] \ + if 'channel_column_names' in parameters \ + else None + self.timestamp_column_name = parameters['timestamp_column_name'] \ + if 'timestamp_column_name' in parameters \ + else None + self._init_csv_reader() + + def _init_csv_reader(self) -> None: + """This method initializes the CSV reader object. It opens the CSV file and creates a CSV reader object that will be used to read the file. + """ + self._csv_file = open(self.file_path) + self._csv_reader = csv.DictReader(self._csv_file) + + def _should_generate_timestamp(self) -> bool: + return self.timestamp_column_name is None + + def _is_next_node_call_enabled(self) -> bool: + return self._output_buffer[self.OUTPUT_TIMESTAMP].has_data() + + def _is_generate_data_condition_satisfied(self) -> bool: + return not self._csv_file.closed + + def _generate_data(self) -> Dict[str, FrameworkData]: + """This method reads the csv file and store the data in a FrameworkData object. + """ + main_data = FrameworkData(self.sampling_frequency, self.channel_column_names) + timestamp_data = FrameworkData(self.sampling_frequency) + for row_index, row in enumerate(self._csv_reader): + if row_index == 0 and self.channel_column_names is None: + self.channel_column_names = row.keys() + for channel_name in self.channel_column_names: + main_data.input_data_on_channel([float(row[channel_name])], channel_name) + row_timestamp = row_index if self._should_generate_timestamp() else row[self.timestamp_column_name] + timestamp_data.input_data_on_channel(data=[row_timestamp]) + self._csv_file.close() + + print(f'{self.file_path} closed') + return { + self.OUTPUT_MAIN: main_data, + self.OUTPUT_TIMESTAMP: timestamp_data + } + + def _get_outputs(self) -> List[str]: + """This method returns the outputs of this node. + + :return: List of outputs of this node. + :rtype: List[str] + """ + return [ + self.OUTPUT_MAIN, + self.OUTPUT_TIMESTAMP + ] + +
[docs] def dispose(self) -> None: + self._clear_output_buffer() + self._clear_input_buffer() + if self._csv_file is not None and not self._csv_file.closed: + self._csv_file.close()
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/generator/file/csvfilearray.html b/_modules/models/node/generator/file/csvfilearray.html new file mode 100644 index 0000000..6261dd1 --- /dev/null +++ b/_modules/models/node/generator/file/csvfilearray.html @@ -0,0 +1,403 @@ + + + + + + + + models.node.generator.file.csvfilearray - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.generator.file.csvfilearray

+import abc
+import os
+import csv
+from typing import List, Dict, Final
+
+from models.exception.invalid_parameter_value import InvalidParameterValue
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.generator.generator_node import GeneratorNode
+from models.node.generator.single_run_generator_node import SingleRunGeneratorNode
+
+
+
[docs]class CSVFileArray(SingleRunGeneratorNode): + """Node that reads data from multiple CSV files and outputs it as a FrameworkData object. + The working principle is similar to the CSVFile node, but it reads multiple files instead of one. + + When the node is initialized, it reads the CSV files and stores their data in memory(FrameworkData class). When the node is executed, it + sends the data to its outputs. + + If you want to use this node in your pipeline, you must define the following parameters in the pipeline configuration.json file: + + **name** (*str*): Node name.\n + **module** (*str*): Current module name (in this case ``models.node.generator.file.csvfilearray``).\n + **type** (*str*): Current node type (in this case ``CSVFileArray``).\n + **file_path** (*List[str]*): List of paths to the CSV files.\n + **sampling_frequency** (*float*): The sample frequency used to collect the data in the CSV file.\n + **timestamp_column_name** (*str, optional*): Name of the column that contains the timestamp data.\n + **channel_column_names** (*List[str], optional*): List of column names of the channels that will be read from the CSV file.\n + **buffer_options** (*dict*): Buffer options. + **clear_output_buffer_on_generate** (*bool*): If ``True``, the output buffer will be cleared when the node is executed.\n + **output** (*dict*): Dictionary containing the node outputs. Where you want to send the data read from the CSV file to, in other words, the next node in the pipeline.\n + """ + _MODULE_NAME: Final[str] = 'node.generator.file.csvfilearray' + + OUTPUT_MAIN: Final[str] = 'main' + OUTPUT_TIMESTAMP: Final[str] = 'timestamp' + + def _validate_parameters(self, parameters: dict): + if 'sampling_frequency' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='sampling_frequency') + if 'file_path' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='file_path') + if type(parameters['sampling_frequency']) is not float and type(parameters['sampling_frequency']) is not int: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='sampling_frequency', + cause='must_be_number') + if type(parameters['file_path']) is not list: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='file_path', + cause='must_be_list') + if len(parameters['file_path']) < 1: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='file_path', + cause='must_be_have_items') + for file_path in parameters['file_path']: + if os.path.splitext(file_path)[1] != '.csv': + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter=f'file_path[{file_path}]', + cause='must_be_csv_file') + if not os.path.exists(file_path): + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter=f'file_path[{file_path}]', + cause='file_doesnt_exist') + if 'timestamp_column_name' in parameters and type(parameters['timestamp_column_name']) is not str: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='timestamp_column_name', + cause='must_be_string') + + if 'channel_column_names' in parameters: + if type(parameters['channel_column_names']) is not list: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='channel_column_names', + cause='must_be_list') + if len(parameters['channel_column_names']) < 1: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='channel_column_names', + cause='is_empty') + if any(type(element) is not str for element in parameters['channel_column_names']): + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='channel_column_names', + cause='must_contain_strings_only') + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + super()._initialize_parameter_fields(parameters) + self.sampling_frequency = parameters['sampling_frequency'] + self.file_paths = parameters['file_path'] + self.channel_column_names = parameters['channel_column_names'] \ + if 'channel_column_names' in parameters \ + else None + self.timestamp_column_name = parameters['timestamp_column_name'] \ + if 'timestamp_column_name' in parameters \ + else None + self._csv_file = None + + def _should_generate_timestamp(self) -> bool: + return self.timestamp_column_name is None + + def _is_next_node_call_enabled(self) -> bool: + return self._output_buffer[self.OUTPUT_TIMESTAMP].has_data() + + def _is_generate_data_condition_satisfied(self) -> bool: + return True + + def _generate_data(self) -> Dict[str, FrameworkData]: + main_data = FrameworkData(self.sampling_frequency, self.channel_column_names) + timestamp_data = FrameworkData(self.sampling_frequency) + for file in self.file_paths: + self._csv_file = open(file) + self.print(f'{file} opened') + csv_reader = csv.DictReader(self._csv_file) + for row_index, row in enumerate(csv_reader): + if row_index == 0 and self.channel_column_names is None: + self.channel_column_names = row.keys() + for channel_name in self.channel_column_names: + main_data.input_data_on_channel([float(row[channel_name])], channel_name) + row_timestamp = row_index if self._should_generate_timestamp() else row[self.timestamp_column_name] + timestamp_data.input_data_on_channel(data=[row_timestamp]) + self._csv_file.close() + self.print('closed') + + return { + self.OUTPUT_MAIN: main_data, + self.OUTPUT_TIMESTAMP: timestamp_data + } + + def _get_outputs(self) -> List[str]: + return [ + self.OUTPUT_MAIN, + self.OUTPUT_TIMESTAMP + ] + +
[docs] def dispose(self) -> None: + self._clear_output_buffer() + self._clear_input_buffer() + if self._csv_file is not None and not self._csv_file.closed: + self._csv_file.close()
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/generator/generator_node.html b/_modules/models/node/generator/generator_node.html new file mode 100644 index 0000000..47754d4 --- /dev/null +++ b/_modules/models/node/generator/generator_node.html @@ -0,0 +1,351 @@ + + + + + + + + models.node.generator.generator_node - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.generator.generator_node

+import abc
+from typing import List, Dict
+
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.node import Node
+
+
+
[docs]class GeneratorNode(Node): + """This node is the basic implementation of the nodes that generates data. It contains the basic methods that are + common to all the generator nodes, so that it can be inherited by the other generator nodes. + + :param parameters: The parameters that were passed to the node. This comes from the configuration file. + :type parameters: dict + + :raises MissingParameterError: The ``buffer_options`` dictionary is required. + """ + + def __init__(self, parameters=None) -> None: + super().__init__(parameters=parameters) + + def _validate_parameters(self, parameters: dict): + """Validates the parameters that were passed to the node. This comes from the configuration file. + + :param parameters: The parameters that were passed to the node. This comes from the configuration file. + :type parameters: dict + + :raises MissingParameterError: The ``buffer_options`` dictionary is required. + + ``config.json`` example: + **clear_output_buffer_on_generate** (*bool*): If ``True``, the output buffer will be cleared when the node is executed. + + """ + super()._validate_parameters(parameters) + if 'clear_output_buffer_on_generate' not in parameters['buffer_options']: + raise MissingParameterError(module=self._MODULE_NAME,name=self.name, + parameter='buffer_options.clear_output_buffer_on_generate') + + def _initialize_parameter_fields(self, parameters: dict): + """Initializes the parameter fields of the node. + """ + super()._initialize_parameter_fields(parameters) + + def _initialize_buffer_options(self, buffer_options: dict) -> None: + """Initializes the buffer options of the node. + """ + self._clear_output_buffer_on_generate = buffer_options['clear_output_buffer_on_generate'] + + def _run(self, data: FrameworkData, input_name: str) -> None: + """This method is called when the node is executed. If the generate data condition is satisfied, it generates + data and inserts it into the output buffer. + """ + if not self._is_generate_data_condition_satisfied(): + return + + if self._clear_output_buffer_on_generate: + super()._clear_output_buffer() + + data = self._generate_data() + for output_name in self._get_outputs(): + self._insert_new_output_data(data[output_name], output_name) + + def _build_graph_inputs(self): + return '' + + @abc.abstractmethod + def _is_next_node_call_enabled(self) -> bool: + raise NotImplementedError() + + @abc.abstractmethod + def _is_generate_data_condition_satisfied(self) -> bool: + raise NotImplementedError() + + @abc.abstractmethod + def _generate_data(self) -> Dict[str, FrameworkData]: + raise NotImplementedError() + + def _get_inputs(self) -> List[str]: + """Returns the input names in list form. + """ + return [] + + @abc.abstractmethod + def _get_outputs(self) -> List[str]: + """Returns the output names in list form. + """ + raise NotImplementedError()
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/generator/single_run_generator_node.html b/_modules/models/node/generator/single_run_generator_node.html new file mode 100644 index 0000000..9bc71a8 --- /dev/null +++ b/_modules/models/node/generator/single_run_generator_node.html @@ -0,0 +1,318 @@ + + + + + + + + models.node.generator.single_run_generator_node - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.generator.single_run_generator_node

+import abc
+from typing import List, Dict
+
+from models.framework_data import FrameworkData
+from models.node.generator.generator_node import GeneratorNode
+
+
+
[docs]class SingleRunGeneratorNode(GeneratorNode): + """This node generates data for a single run. This node is not meant to be used directly, but to be inherited by other nodes that implement the + ``_generate_data`` method. This method is responsible for generating the data for a single run. The node will + generate the data, and then stop executing. + + :param parameters: The parameters of the node(default: None). + :type parameters: dict + """ + + def __init__(self, parameters=None): + self._first_execution = True + super().__init__(parameters) + +
[docs] def run(self, data: FrameworkData = None, input_name: str = None) -> None: + """This method runs the node. It is called by the framework when the node is executed. If this is the first + execution, it will run. If it is not the first execution, it will raise an exception. + + :param data: The data that will be passed to the node. This comes from the previous node in the pipeline(default: None). + :type data: FrameworkData + :param input_name: The name of the input that the data comes from(default: None). + :type input_name: str + + :raises Exception: If this is not the first execution. + """ + if self._first_execution: + super().run() + self._first_execution = False
+ + @abc.abstractmethod + def _is_next_node_call_enabled(self) -> bool: + raise NotImplementedError() + + @abc.abstractmethod + def _is_generate_data_condition_satisfied(self) -> bool: + raise NotImplementedError() + + @abc.abstractmethod + def _generate_data(self) -> Dict[str, FrameworkData]: + raise NotImplementedError() + + @abc.abstractmethod + def _get_outputs(self) -> List[str]: + raise NotImplementedError() + +
[docs] @abc.abstractmethod + def dispose(self) -> None: + raise NotImplementedError()
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/node.html b/_modules/models/node/node.html new file mode 100644 index 0000000..f9391ec --- /dev/null +++ b/_modules/models/node/node.html @@ -0,0 +1,642 @@ + + + + + + + + models.node.node - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.node

+from __future__ import annotations
+import abc
+import copy
+import threading
+import traceback
+import time
+from queue import Queue
+from threading import Thread, Event
+from typing import List, Dict, Final, Any
+
+from models.exception.invalid_parameter_value import InvalidParameterValue
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+
+
+
[docs]class Node: + _MODULE_NAME: Final[str] = 'models.node' + """Abstract base class for processing pipeline execution on this framework. + A node is a component that receives data from its inputs, process it and send it to its outputs. + """ + + def __init__(self, parameters=None) -> None: + super().__init__() + self.name: Final[str] = parameters['name'] + self._enable_log = True + self.print("Initializing") + self._validate_parameters(parameters) + self.parameters = parameters + + self._initialize_buffer_options(parameters['buffer_options']) + self._type: Final[str] = parameters['type'] + + self._initialize_parameter_fields(parameters) + + self._clear_input_buffer() + self._clear_output_buffer() + + self._initialize_children() + + self._child_input_relation: Dict[Node, List[str]] = {} + + # Threading attributes + self.local_storage = Queue() + self.running = False + self.thread = None + self.new_data_available = False + self.condition = threading.Condition() + self._stop_event = Event() + self.is_running_main_process = False + self.thread = Thread(target=self._thread_runner, name=self.name) + self.thread.start() + + def _build_graph_inputs(self): + return f""" + <TR> + <TD BORDER="0"> + <TABLE BORDER="0" CELLBORDER="" CELLSPACING="0" CELLPADDING="0"> + <TR> + <TD WIDTH="20"></TD> + {[f'<TD PORT="in_{input_name}" BORDER="1" CELLPADDING="1"><FONT POINT-SIZE="8">{input_name}</FONT></TD><TD WIDTH="10"></TD>' for input_name in self._get_inputs()]} + <TD WIDTH="10"></TD> + </TR> + </TABLE> + </TD> + </TR> + """ + + def _build_graph_outputs(self): + return f""" + <TR> + <TD BORDER="0"> + <TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" CELLPADDING="0"> + <TR> + <TD WIDTH="20"></TD> + {[f'<TD PORT="out_{output_name}" BORDER="1" CELLPADDING="1"><FONT POINT-SIZE="8">{output_name}</FONT></TD><TD WIDTH="10"></TD>' for output_name in self._get_outputs()]} + <TD WIDTH="10"></TD> + </TR> + </TABLE> + </TD> + </TR> + """ + +
[docs] def build_graphviz_representation(self): + return f""" + {self.name} [ + shape=plaintext + tooltip="{self.parameters}" + label=< + <TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" CELLPADDING="0"> + {self._build_graph_inputs()} + <TR> + <TD BORDER="1" STYLE="ROUNDED" CELLPADDING="4" COLOR="black">{self.name}<BR/><FONT POINT-SIZE="5">{self._MODULE_NAME}</FONT></TD> + </TR> + {self._build_graph_outputs()} + </TABLE> + > + ]; + """
+ + @abc.abstractmethod + def _validate_parameters(self, parameters: dict): + """ + Validates parameters passed to this node. + + :param parameters: Parameters passed to this node. + :type parameters: dict + :raises MissingParameterError: If a required parameter is missing. + """ + if 'module' not in parameters: + raise MissingParameterError( + module=self._MODULE_NAME, name=self.name, + parameter='module' + ) + if 'models.node.' not in parameters['module']: + raise InvalidParameterValue( + module=self._MODULE_NAME, name=self.name, + parameter='module', + cause='must_be_part_of_[models.node]_module' + ) + if 'type' not in parameters: + raise MissingParameterError( + module=self._MODULE_NAME, name=self.name, + parameter='type' + ) + if 'enable_log' not in parameters: + parameters['enable_log'] = False + if 'buffer_options' not in parameters: + raise MissingParameterError( + module=self._MODULE_NAME, name=self.name, + parameter='buffer_options' + ) + if 'outputs' not in parameters: + raise MissingParameterError( + module=self._MODULE_NAME, name=self.name, + parameter='outputs' + ) + if 'name' not in parameters: + raise MissingParameterError( + module=self._MODULE_NAME, name=self.name, + parameter='name' + ) + + if 'print_buffer_size' not in parameters['buffer_options']: + parameters['buffer_options']['print_buffer_size'] = False + elif type(parameters['buffer_options']['print_buffer_size']) is not bool: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='buffer_options.print_buffer_size', + cause='must_be_bool') + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + """ + Initializes parameter fields of this node. This is an abstract method and should be implemented by subclasses. + + :param parameters: Parameters passed to this node. + :type parameters: dict + """ + self._enable_log = parameters['enable_log'] + self._should_print_buffer_size = parameters['buffer_options']['print_buffer_size'] + return + + def _clear_input_buffer(self): + """Sets input buffer to new empty object for each input name + """ + self._input_buffer = {} + for input_name in self._get_inputs(): + self._input_buffer[input_name] = FrameworkData() + + def _clear_output_buffer(self): + """Sets output buffer to new empty object for each output name + """ + self._output_buffer = {} + for output_name in self._get_outputs(): + self._output_buffer[output_name] = FrameworkData() + + @staticmethod + def _insert_data_in_buffer(data: FrameworkData, buffer_data_name: str, buffer: Dict[str, FrameworkData]): + buffer[buffer_data_name].extend(copy.deepcopy(data)) + + def _print_buffer_size(self, buffer_name: str, buffer: Dict[str, FrameworkData]): + formatted_buffer_sizes = f'Buffer:{buffer_name}\t' + for key in buffer: + formatted_buffer_sizes += f'###Key:{key}=Length:{buffer[key].get_data_count()}### ' + self.print(formatted_buffer_sizes) + + def _insert_new_input_data(self, data: FrameworkData, input_name: str): + """Appends new data to the end of already existing input buffer + + :param data: Data to be added. Should be in channel X sample format + :type data: FrameworkData + :param input_name: Node input name. + :type input_name: str + """ + self._input_buffer[input_name].extend(copy.deepcopy(data)) + if self._should_print_buffer_size: + self._print_buffer_size('input', self._input_buffer) + + def _insert_new_output_data(self, data: FrameworkData, output_name: str): + """ + Appends new data to the end of already existing output buffer + + :param data: Data to be added. Should be in channel X sample format + :type data: FrameworkData + :param output_name: Node output name. + :type output_name: str + """ + self._output_buffer[output_name].extend(copy.deepcopy(data)) + if self._should_print_buffer_size: + self._print_buffer_size('output', self._output_buffer) + + def _initialize_children(self): + """Sets child nodes dictionary to a new, empty dict + """ + self._children: Dict[str, List[Dict[str, Any]]] = {} + for output_name in self._get_outputs(): + self._children[output_name] = [] + +
[docs] def add_child(self, output_name: str, node: Node, input_name: str): + """Adds a new child node to child nodes dictionary + + :param output_name: Current node output name, used as key. + :type output_name: str + :param node: Child node object. + :type node: Node + :param input_name: Child node input name. + :type input_name: str + """ + # TODO Melhorar o objeto guardado em self._children + if node not in self._child_input_relation: + self._child_input_relation[node] = [] + if input_name in self._child_input_relation[node]: + raise InvalidParameterValue(module='node', parameter=f'outputs.{output_name}', cause='already_added', + name=self.name) + self._children[output_name].append( + { + 'node': node, + 'run': lambda data: node.run(data, input_name), + 'run_': lambda data: node.run(), + 'dispose': lambda x: node.dispose_all() + } + )
+ + def _dispose_all_children(self): + for output_name in self._get_outputs(): + output_children = self._children[output_name] + for child in output_children: + child['dispose'](child) + + def _call_children(self): + """Calls child nodes to execute their processing given current node output buffer content. + """ + for output_name in self._get_outputs(): + output = self._output_buffer[output_name] + output_children = self._children[output_name] + for child in output_children: + child['run'](output) + + def _thread_runner(self): + while not self._stop_event.is_set(): + with self.condition: + self.condition.wait() + + while not self.local_storage.empty(): + input_name, data = self.local_storage.get() + try: + self.is_running_main_process = True + self._run(data, input_name) + except Exception as e: + self.print(f'Error: {e}', exception=e) + raise e + finally: + self.is_running_main_process = False + if self._is_next_node_call_enabled(): + self._call_children() + self.new_data_available = False + +
[docs] def run(self, data: FrameworkData = None, input_name: str = None) -> None: + self.local_storage.put((input_name, data)) + with self.condition: + self.new_data_available = True + self.condition.notify()
+ +
[docs] def check_input(self, input_name: str) -> None: + if input_name not in self._get_inputs(): + raise ValueError('error' + '.invalid' + '.value' + '.node' + '.input')
+ +
[docs] def check_output(self, output_name: str) -> None: + if output_name not in self._get_outputs(): + raise ValueError('error' + '.invalid' + '.value' + '.node' + '.output')
+ +
[docs] @classmethod + def from_config_json(cls, parameters: dict): + """Returns node instance from given parameters in dict form + + :param parameters: Node parameters in dict form. + :type parameters: dict + """ + return cls(parameters)
+ + @abc.abstractmethod + def _run(self, data: FrameworkData, input_name: str) -> None: + """Node self implementation of processing on input data + + :param data: Node input data. + :type data: FrameworkData + :param input_name: Node input name. + :type input_name: str + """ + raise NotImplementedError() + + @abc.abstractmethod + def _is_next_node_call_enabled(self) -> bool: + """Node self implementation to check if child nodes should be called. + """ + raise NotImplementedError() + + @abc.abstractmethod + def _initialize_buffer_options(self, buffer_options: dict) -> None: + """Node self implementation of buffer behaviour options initialization + + :param buffer_options: Buffer behaviour options. + :type buffer_options: dict + """ + raise NotImplementedError() + + @abc.abstractmethod + def _get_inputs(self) -> List[str]: + """Returns the input names in list form. + """ + raise NotImplementedError() + + @abc.abstractmethod + def _get_outputs(self) -> List[str]: + """Returns the output names in list form. + """ + raise NotImplementedError() + +
[docs] def dispose_all(self) -> None: + """Disposes itself and all its children nodes + """ + self._dispose_all_children() + self.dispose() + self._dispose()
+ + def _dispose(self) -> None: + self.print('Disposing...') + self._stop_event.set() + with self.condition: + self.condition.notify() + if self.thread: + self.thread.join() + self.running = False + return + +
[docs] @abc.abstractmethod + def dispose(self) -> None: + """Node self implementation of disposal of allocated resources. + """ + raise NotImplementedError()
+ +
[docs] def print(self, message: str, exception: Exception = None) -> None: + if self._enable_log or not exception is None: + print(f'{time.time()} - {self._MODULE_NAME}.{self.name} - {message}') + if exception: + print('Stack trace:') + traceback.print_exc()
+ + @property + def module_name(self): + return self._MODULE_NAME
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/output/file/csvfile.html b/_modules/models/node/output/file/csvfile.html new file mode 100644 index 0000000..d5fc7b1 --- /dev/null +++ b/_modules/models/node/output/file/csvfile.html @@ -0,0 +1,397 @@ + + + + + + + + models.node.output.file.csvfile - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.output.file.csvfile

+import csv
+import os
+from typing import List, Final, Dict
+
+from models.exception.invalid_parameter_value import InvalidParameterValue
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.output.output_node import OutputNode
+
+
+
[docs]class CSVFile(OutputNode): + """ This node is capable of creating/writing the output data to a CSV file. + + Attributes: + _MODULE_NAME (str): The name of this module (in this case, 'node.output.file.csvfile'). + INPUT_MAIN (str): The name of the main input (in this case, 'main'). + + ``configuration.json`` usage example: + + **module**: Current module name (in this case ``models.node.output.file``).\n + **name**: Current node instance name (in this case, ``CSVFile``).\n + **file_path** (str): The path to the CSV file that will be created/written to.\n + **buffer_options** (dict): The buffer options.\n + **clear_output_buffer_on_data_input** (bool): Whether to clear the output buffer when data is inputted.\n + **clear_input_buffer_after_process** (bool): Whether to clear the input buffer after the process method is called.\n + **clear_output_buffer_after_process** (bool): Whether to clear the output buffer after the process method is called.\n + """ + + def _is_processing_condition_satisfied(self) -> bool: + return True + + _MODULE_NAME: Final[str] = 'node.output.file.csvfile' + + INPUT_MAIN: Final[str] = 'main' + + def _validate_parameters(self, parameters: dict): + """ Validates the parameters that were passed to the node. + + :param parameters: The parameters that were passed to the node. + :type parameters: dict + + :raises MissingParameterError: The ``file_path`` parameter is required. + :raises InvalidParameterValue: The ``file_path`` parameter must be a string. + :raises InvalidParameterValue: The ``file_path`` parameter must be a CSV file. + + """ + if 'file_path' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='file_path') + if type(parameters['file_path']) is not str: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='file_path', + cause='must_be_string') + if os.path.splitext(parameters['file_path'])[1] != '.csv': + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='file_path', + cause='must_be_csv_file') + + def _initialize_parameter_fields(self, parameters: dict): + """ Initializes the parameters that were passed to the node. + + :param parameters: The parameters that were passed to the node. + :type parameters: dict + """ + super()._initialize_parameter_fields(parameters) + self.file_path = parameters['file_path'] + if os.path.exists(self.file_path): + os.remove(self.file_path) + # self.file_path = f'{self.file_path[:-4]}_{int(time.time() * 1000)}.csv' + self._csv_file = None + + def _get_inputs(self) -> List[str]: + """ Returns the input names of this node. + """ + return [ + self.INPUT_MAIN + ] + + def _init_csv_writer(self, data: FrameworkData) -> None: + """ Initializes the CSV writer. + """ + if self._csv_file is None: + if not os.path.exists(os.sep.join(self.file_path.split(os.sep)[0:-1])): + os.makedirs(os.sep.join(self.file_path.split(os.sep)[0:-1])) + self.print('Creating csv file') + self._csv_file = open(self.file_path, "w", newline='') + self._csv_writer = csv.writer(self._csv_file) + self._channels = None + + def _write_csv_columns(self, channels: List[str]) -> None: + """ Writes the CSV columns labels. + + :param channels: The channels to write. + :type channels: List[str] + """ + if self._channels is not None: + return + + if len(channels) == 0: + return + + self._channels = channels + self.print('Writing columns') + self._csv_writer.writerow(self._channels) + + def _write_data(self, data: FrameworkData) -> None: + """ Writes the data to the CSV file. + + :param data: The data to write. + :type data: FrameworkData + """ + self.print(f'Writing data to file') + formatted_data = zip(*data.get_data().values()) + self._csv_writer.writerows(formatted_data) + self.print(f'Done') + + def _process(self, data: Dict[str, FrameworkData]) -> None: + """ Runs the node. + """ + input_data = data[self.INPUT_MAIN] + self._init_csv_writer(input_data) + self._write_csv_columns(input_data.channels) + self._write_data(input_data) + self._csv_file.flush() + +
[docs] def dispose(self) -> None: + """ Node self implementation of disposal of allocated resources. + """ + self._clear_output_buffer() + self._clear_input_buffer() + if self._csv_file is not None and not self._csv_file.closed: + self._csv_file.close() + self._csv_file = None
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/output/output_node.html b/_modules/models/node/output/output_node.html new file mode 100644 index 0000000..8e2cb00 --- /dev/null +++ b/_modules/models/node/output/output_node.html @@ -0,0 +1,364 @@ + + + + + + + + models.node.output.output_node - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.output.output_node

+import abc
+from typing import List, Dict
+
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.node import Node
+
+
+
[docs]class OutputNode(Node): + """ This is the base class for all output nodes. It is responsible for validating the parameters that + were passed to the node, and for initializing the parameters that were passed to the node. It should + not be used directly, but rather, it should be inherited by all output nodes. + + :param parameters: The parameters that were passed to the node. + :type parameters: dict + """ + + def __init__(self, parameters: dict): + super().__init__(parameters=parameters) + + @abc.abstractmethod + def _validate_parameters(self, parameters: dict) -> None: + """ Validates the parameters that were passed to the node. + """ + parameters['outputs']={} + super()._validate_parameters(parameters) + if 'clear_output_buffer_on_data_input' not in parameters['buffer_options']: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='buffer_options.clear_output_buffer_on_data_input') + if 'clear_input_buffer_after_process' not in parameters['buffer_options']: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='buffer_options.clear_input_buffer_after_process') + if 'clear_output_buffer_after_process' not in parameters['buffer_options']: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='buffer_options.clear_output_buffer_after_process') + + def _run(self, data: FrameworkData, input_name: str) -> None: + self.print(f'Inserting data in input buffer {input_name}') + self._insert_new_input_data(data, input_name) + if self._clear_output_buffer_on_data_input: + self._clear_output_buffer() + self._process_input_buffer() + + def _process_input_buffer(self) -> None: + if not self._is_processing_condition_satisfied(): + return + self.print('Starting processing of input buffer') + self._process(self._input_buffer) + if self._clear_input_buffer_after_process: + self._clear_input_buffer() + if self._clear_output_buffer_after_process: + self._clear_output_buffer() + + + @abc.abstractmethod + def _process(self, data: Dict[str, FrameworkData]) -> None: + """Node self implementation of data processing, relating input. + + :param data: data to be processed. + :type data: Dict[str,FrameworkData] + """ + raise NotImplementedError() + + @abc.abstractmethod + def _is_processing_condition_satisfied(self) -> bool: + """ Runs the node accordingly to the output node's logic. + """ + raise NotImplementedError() + + def _is_next_node_call_enabled(self) -> bool: + """ Returns whether the next node call is enabled or not. + """ + return False + + def _initialize_buffer_options(self, buffer_options: dict) -> None: + """ Initializes the buffer options based on the parameters that were passed to the node. + """ + self._clear_output_buffer_on_data_input = buffer_options['clear_output_buffer_on_data_input'] + self._clear_input_buffer_after_process = buffer_options['clear_input_buffer_after_process'] + self._clear_output_buffer_after_process = buffer_options['clear_output_buffer_after_process'] + + + @abc.abstractmethod + def _get_inputs(self) -> List[str]: + """ Returns the input names of this node. + """ + raise NotImplementedError() + + def _get_outputs(self) -> List[str]: + """ Returns the output names of this node. + """ + return [] + + def _build_graph_outputs(self): + return '' + +
[docs] def dispose(self) -> None: + """ Node self disposal of disposal of allocated resources. + """ + super().dispose()
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/encoder/onehottosingle.html b/_modules/models/node/processing/encoder/onehottosingle.html new file mode 100644 index 0000000..83902cb --- /dev/null +++ b/_modules/models/node/processing/encoder/onehottosingle.html @@ -0,0 +1,361 @@ + + + + + + + + models.node.processing.encoder.onehottosingle - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.encoder.onehottosingle

+import abc
+from typing import Final, Dict
+
+from models.framework_data import FrameworkData
+from models.node.processing.processing_node import ProcessingNode
+from typing import List
+
+
+
[docs]class OneHotToSingle(ProcessingNode): + """ Converts a one-hot encoded signal to a single channel signal. + One-hot encoded signals are signals where each label is represented by a vector of the same length as the number + of labels, where the label is represented by a 1 at the index of the label and 0 everywhere else. + A Single channel signal is a signal where each label is represented by a single channel, where the label is + represented by the index. + This node converts a one-hot encoded labels to a single channel label. The single label count starts at 1, so the + label 1 is represented by the channel 1, the label 2 by the channel 2, etc. There is no label 0. + + Attributes: + _MODULE_NAME (`str`): The name of the module (in his case ``node.processing.encoder.onehottosingle``) + INPUT_MAIN (`str`): The name of the main input signal (in this case ``main``) + OUTPUT_MAIN (`str`): The name of the main output signal (in this case ``main``) + + configuration.json usage: + **module** (*str*): The name of the module (``node.processing.encoder``)\n + **type** (*str*): The type of the node (``OneHotToSingle``)\n + **buffer_options** (*dict*): Buffer options.\n + **clear_output_buffer_on_data_input** (*bool*): Whether to clear the output buffer when new data is inserted in the input buffer.\n + **clear_input_buffer_after_process** (*bool*): Whether to clear the input buffer after processing.\n + **clear_output_buffer_after_process** (*bool*): Whether to clear the output buffer after processing.\n + + """ + _MODULE_NAME: Final[str] = 'node.processing.encoder.onehottosingle' + + INPUT_MAIN: Final[str] = 'main' + OUTPUT_MAIN: Final[str] = 'main' + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + """ Initializes the parameter fields of this node. + + :param parameters: The parameters passed to this node. + :type parameters: dict + """ + super()._initialize_parameter_fields(parameters) + + def _is_next_node_call_enabled(self) -> bool: + """ Returns whether the next node call is enabled. The next node call is enabled if the input buffer is not empty. + """ + return self._output_buffer[self.OUTPUT_MAIN].get_data_count() > 0 + + def _is_processing_condition_satisfied(self) -> bool: + """ Returns whether the processing condition is satisfied. The processing condition is satisfied if the input buffer is not empty. + """ + return self._input_buffer[self.INPUT_MAIN].get_data_count() > 0 + + def _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + """ This method encodes the data labels that before was one-hot encoded to a single channel labels. It does this + by finding the index of the channel that has a value of 1 and then setting the output channel to that index + 1. It + does this for each data point in the dataset. + + :param data: The data to process. + :type data: dict[str, FrameworkData] + + :return: The processed data. + :rtype: dict[str, FrameworkData] + """ + self.print('encoding...') + raw_data = data[self.INPUT_MAIN] + encoded_data: FrameworkData = FrameworkData(sampling_frequency_hz=raw_data.sampling_frequency) + for data_index in range(0, raw_data.get_data_count()): + found_for_index = False + for channel_index, channel in enumerate(raw_data.channels): + if raw_data.get_data_at_index(data_index)[channel] > 0: + encoded_data.input_data_on_channel([channel_index+1]) + found_for_index = True + break + if not found_for_index: + encoded_data.input_data_on_channel([0]) + + self.print('encoded!') + return { + self.OUTPUT_MAIN: encoded_data + } + + def _get_inputs(self) -> List[str]: + """ Returns the inputs of this node. + """ + return [ + self.INPUT_MAIN + ] + + def _get_outputs(self) -> List[str]: + """ Returns the outputs of this node. + """ + return [ + self.OUTPUT_MAIN + ]
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/encoder/singletoonehot.html b/_modules/models/node/processing/encoder/singletoonehot.html new file mode 100644 index 0000000..7a4d5bc --- /dev/null +++ b/_modules/models/node/processing/encoder/singletoonehot.html @@ -0,0 +1,360 @@ + + + + + + + + models.node.processing.encoder.singletoonehot - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.encoder.singletoonehot

+import abc
+from typing import Final, Dict
+
+from models.exception.non_compatible_data import NonCompatibleData
+from models.framework_data import FrameworkData
+from models.node.processing.processing_node import ProcessingNode
+from typing import List
+
+
+
[docs]class SingleToOneHot(ProcessingNode): + """ Converts a single channel encoding (Ordinal encoding) signal to a one-hot encoding. + One-hot encoded signals are signals where each label is represented by a vector of the same length as the number + of labels, where the label is represented by a 1 at the index of the label and 0 everywhere else. + A Single channel encoded (Ordinal encoding) signal is a type of signal where each label is represented by a number, + where the label is represented by the index of the label. + This node converts a single channel labels to a one-hot encoded label. The single label count starts at 1, so the + label 1 is represented by the channel 1, the label 2 by the channel 2, etc. There is no label 0. + + Attributes: + _MODULE_NAME (`str`): The name of the module (in his case ``node.processing.encoder.singletoonehot``) + INPUT_MAIN (`str`): The name of the main input signal (in this case ``main``) + OUTPUT_MAIN (`str`): The name of the main output signal (in this case ``main``) + + configuration.json usage: + **module** (*str*): The name of the module (``node.processing.encoder``)\n + **type** (*str*): The type of the node (``SingleToOneHot``)\n + **buffer_options** (*dict*): Buffer options.\n + **clear_output_buffer_on_data_input** (*bool*): Whether to clear the output buffer when new data is inserted in the input buffer.\n + **clear_input_buffer_after_process** (*bool*): Whether to clear the input buffer after processing.\n + **clear_output_buffer_after_process** (*bool*): Whether to clear the output buffer after processing.\n + """ + _MODULE_NAME: Final[str] = 'node.processing.encoder.singletoonehot' + + INPUT_MAIN: Final[str] = 'main' + OUTPUT_MAIN: Final[str] = 'main' + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + """ Initializes the parameter fields of this node. + + :param parameters: The parameters passed to this node. + :type parameters: dict + """ + super()._initialize_parameter_fields(parameters) + self.labels = parameters['labels'] + + def _is_next_node_call_enabled(self) -> bool: + """ Returns whether the next node call is enabled. The next node call is enabled if the input buffer is not empty. + """ + return self._output_buffer[self.OUTPUT_MAIN].get_data_count() > 0 + + def _is_processing_condition_satisfied(self) -> bool: + """ Returns whether the processing condition is satisfied. The processing condition is satisfied if the input buffer is not empty. + """ + return self._input_buffer[self.INPUT_MAIN].get_data_count() > 0 + + def _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + """ This method encodes the data labels that before was a single channel label (Ordinal encoding) to a one-hot encoded label. It does this + comparing the index of the channel to the label and setting the output channel to 1 if the index is equal to the label and 0 otherwise. It + does this for each data point in the dataset. + + :param data: The data to process. + :type data: dict + + :return: The processed data. + :rtype: dict + """ + self.print('encoding...') + raw_data = data[self.INPUT_MAIN] + if not raw_data.is_1d(): + raise NonCompatibleData(module=self._MODULE_NAME,name=self.name, cause='provided_data_is_multichannel') + + encoded_data: FrameworkData = FrameworkData(sampling_frequency_hz=raw_data.sampling_frequency, + channels=self.labels) + for data_entry in raw_data.get_data_single_channel(): + for channel_index, channel in enumerate(self.labels): + encoded_value = 1 if channel_index == data_entry-1 else 0 + encoded_data.input_data_on_channel([encoded_value], channel) + self.print('encoded!') + return { + self.OUTPUT_MAIN: encoded_data + } + + def _get_inputs(self) -> List[str]: + """ Returns the input fields of this node. + """ + return [ + self.INPUT_MAIN + ] + + def _get_outputs(self) -> List[str]: + """ Returns the output fields of this node. + """ + return [ + self.OUTPUT_MAIN + ]
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/feature_extractor/feature_extractor.html b/_modules/models/node/processing/feature_extractor/feature_extractor.html new file mode 100644 index 0000000..1858678 --- /dev/null +++ b/_modules/models/node/processing/feature_extractor/feature_extractor.html @@ -0,0 +1,354 @@ + + + + + + + + models.node.processing.feature_extractor.feature_extractor - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.feature_extractor.feature_extractor

+import abc
+from typing import List, Dict, Final
+from models.framework_data import FrameworkData
+from models.node.processing.processing_node import ProcessingNode
+
+
+
[docs]class FeatureExtractor(ProcessingNode): + """ This is the base class for all feature extractors. A feature extractor is a node that extracts features from a dataset. + + Attributes: + _MODULE_NAME (`str`): The name of the module (in his case ``node.processing.feature_extractor.feature_extractor``) + + configuration.json usage: + **module** (*str*): The name of the module (``node.processing.feature_extractor``)\n + **type** (*str*): The type of the node (``FeatureExtractor``)\n + **buffer_options** (*dict*): Buffer options.\n + **clear_output_buffer_on_data_input** (*bool*): Whether to clear the output buffer when new data is inserted in the input buffer.\n + **clear_input_buffer_after_process** (*bool*): Whether to clear the input buffer after processing.\n + **clear_output_buffer_after_process** (*bool*): Whether to clear the output buffer after processing.\n + """ + + _MODULE_NAME: Final[str] = 'node.processing.feature_extractor.feature_extractor' + + def __init__(self, parameters: dict): + super().__init__(parameters) + self._validate_parameters(parameters) + + @abc.abstractmethod + def _validate_parameters(self, parameters: dict): + """ Validates the parameters passed to this node. In this case it just calls the super method from ProcessingNode. + + :param parameters: The parameters passed to this node. + :type parameters: dict + """ + super()._validate_parameters(parameters) + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + """ Initializes the parameter fields of this node. In this case it just calls the super method from ProcessingNode. + + :param parameters: The parameters passed to this node. + :type parameters: dict + """ + super()._initialize_parameter_fields(parameters) + +
[docs] @classmethod + def from_config_json(cls, parameters: dict): + """ Adds the configuration.json parameters to a new instance of this class. + + :param parameters: The parameters passed to this node. + :type parameters: dict + """ + return cls(parameters)
+ + def _is_next_node_call_enabled(self) -> bool: + """ Returns whether the next node call is enabled. It's always enabled for this node. + """ + return True + + def _is_processing_condition_satisfied(self) -> bool: + """ Returns whether the processing condition is satisfied. The processing condition is satisfied if the input buffer is not empty. + """ + return self._input_buffer[self.INPUT_MAIN].get_data_count() > 0 + + @abc.abstractmethod + def _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + """ This method extracts features from the data. It should be implemented by the subclasses. + + :param data: The data to process. + :type data: dict[str, FrameworkData] + + :raises NotImplementedError: This method should be implemented by the subclasses. + """ + raise NotImplementedError() + + @abc.abstractmethod + def _get_inputs(self) -> List[str]: + """ Returns the inputs of this node. It should be implemented by the subclasses. + + :raises NotImplementedError: This method should be implemented by the subclasses. + """ + raise NotImplementedError() + + @abc.abstractmethod + def _get_outputs(self) -> List[str]: + """ Returns the outputs of this node. It should be implemented by the subclasses. + + :raises NotImplementedError: This method should be implemented by the subclasses. + """ + raise NotImplementedError()
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/fill.html b/_modules/models/node/processing/fill.html new file mode 100644 index 0000000..828f42c --- /dev/null +++ b/_modules/models/node/processing/fill.html @@ -0,0 +1,443 @@ + + + + + + + + models.node.processing.fill - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.fill

+from typing import List, Dict, Final
+
+from models.exception.invalid_parameter_value import InvalidParameterValue
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.processing.processing_node import ProcessingNode
+
+
+
[docs]class Fill(ProcessingNode): + """ This node is used to fill the input buffer with a certain amount of samples. This is useful when the input buffer + is not filled with the desired amount of samples. This node can fill the input buffer with zeros or with the last + sample in the input buffer. + + Attributes: + _MODULE_NAME (str): The name of the module(in this case ``node.processing.fill``) + INPUT_MAIN (str): The name of the main input(in this case ``main``) + OUTPUT_MAIN (str): The name of the main output(in this case ``main``) + FILL_TYPE_ZEROFILL (str): The name of the fill type that fills the input buffer with zeros(in this case ``zero_fill``) + FILL_TYPE_SAMPLE_AND_HOLD (str): The name of the fill type that fills the input buffer with the last sample(in this case ``sample_and_hold``) + + configuration.json usage: + **module** (*str*): The name of the module (``node.processing.fill``)\n + **type** (*str*): The name of the class (``Fill``)\n + **fill_size** (*int*): The size of the input buffer after filling.\n + **filling_type** (*str*): The type of filling to use. Can be ``zero_fill`` or ``sample_and_hold``.\n + **buffer_options** (*dict*): Buffer options.\n + **clear_output_buffer_after_process** (*bool*): Whether to clear the output buffer after processing.\n + **clear_input_buffer_after_process** (*bool*): Whether to clear the input buffer after processing.\n + **clear_output_buffer_on_data_input** (*bool*): Whether to clear the output buffer when new data is inserted in the input buffer.\n + + """ + _MODULE_NAME: Final[str] = 'node.processing.fill' + + INPUT_MAIN: Final[str] = 'main' + OUTPUT_MAIN: Final[str] = 'main' + + FILL_TYPE_ZEROFILL: Final[str] = 'zero_fill' + FILL_TYPE_SAMPLE_AND_HOLD: Final[str] = 'sample_and_hold' + + def _validate_parameters(self, parameters: dict): + """ Validate the parameters passed to the node. This method will raise an exception if the parameters are not + valid or when they don't exist. + + :param parameters: The parameters passed to the node. + :type parameters: dict + + :raises MissingParameterError: the ``full_size`` parameter is required. + :raises InvalidParameterValue: the ``fill_size`` parameter must be an integer. + :raises MissingParameterError: the ``filling_type`` parameter is required. + :raises InvalidParameterValue: the ``filling_type`` parameter must be ``zero_fill`` or ``sample_and_hold``. + """ + + if 'fill_size' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='fill_size') + if 'filling_type' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='filling_type') + + if type(parameters['fill_size']) is not int: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='fill_size', + cause='must_be_int') + + if parameters['filling_type'] not in [self.FILL_TYPE_ZEROFILL, self.FILL_TYPE_SAMPLE_AND_HOLD]: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='filling_type', + cause=f'not_in_[{self.FILL_TYPE_ZEROFILL},{self.FILL_TYPE_SAMPLE_AND_HOLD}]') + + def _initialize_parameter_fields(self, parameters: dict): + """ Initialize the parameter fields of the node. This method will set the ``_fill_size`` and ``_fill_type`` + attributes and all the parent attributes as well. + + :param parameters: The parameters passed to the node. + :type parameters: dict + """ + super()._initialize_parameter_fields(parameters) + self._zero_fill = parameters['filling_type'] == self.FILL_TYPE_ZEROFILL + self._sample_and_hold = parameters['filling_type'] == self.FILL_TYPE_SAMPLE_AND_HOLD + self._fill_size: int = parameters['fill_size'] + + def _is_next_node_call_enabled(self) -> bool: + """ This method will return ``True`` if the next node call is enabled. This method will always return ``True`` + because the next node call is always enabled. + """ + return True + + def _is_processing_condition_satisfied(self) -> bool: + """ This method will return ``True`` if the processing condition is satisfied. This method will return ``True`` + if the input buffer has data. + + :return: ``True`` if the input buffer has data, ``False`` otherwise. + :rtype: bool + """ + return self._input_buffer[self.INPUT_MAIN].get_data_count() > 0 + + def _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + """ This method will process the data in the input buffer and return the result in the output buffer. This + method will fill the input buffer with a certain amount of samples. This is done using the _fill method. + + :param data: The data to process. + :type data: dict + + :return: The processed data. + :rtype: dict + """ + slave_main = data[self.INPUT_MAIN] + + new_data = FrameworkData(sampling_frequency_hz=slave_main.sampling_frequency, + channels=slave_main.channels) + + for data_index, data_value in enumerate(slave_main.get_data_as_2d_array()[0]): + new_data.extend( + self._fill( + data_index, + slave_main, + new_data.sampling_frequency + ) + ) + return { + self.OUTPUT_MAIN: new_data + } + + def _get_inputs(self) -> List[str]: + """ This method will return the inputs of the node. + + :return: The inputs of the node. + :rtype: list + """ + return [ + self.INPUT_MAIN, + ] + + def _get_outputs(self) -> List[str]: + """ This method will return the outputs of the node. + + :return: The outputs of the node. + :rtype: list + """ + return [ + self.OUTPUT_MAIN + ] + + def _fill(self, + data_index: int, + slave_main: FrameworkData, + sampling_frequency: float) -> FrameworkData: + """ This method will fill the input buffer with a certain amount of samples with the desired filling type. This filling + type can be ``zero_fill`` or ``sample_and_hold``. If the filling type is ``zero_fill`` the input buffer will be filled + with zeros. If the filling type is ``sample_and_hold`` the input buffer will be filled with the last sample in the + input buffer. + + :param data_index: The index of the data to fill. + :type data_index: int + :param slave_main: The INPUT_MAIN data. + :type slave_main: FrameworkData + :param sampling_frequency: The sampling frequency of the data to fill. + :type sampling_frequency: float + + :return: The filled data. + :rtype: FrameworkData + """ + fill_data = FrameworkData(sampling_frequency, slave_main.channels) + + if self._zero_fill: + channel_data = [0] * self._fill_size + input_data = [channel_data] * len(slave_main.channels) + fill_data.input_2d_data(input_data) + elif self._sample_and_hold: + input_data = slave_main.get_data_at_index(data_index) + for channel in input_data: + channel_data = [input_data[channel]] * self._fill_size + fill_data.input_data_on_channel(channel_data, channel) + else: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='filling_type', + cause='not_set') + + return fill_data
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/merge.html b/_modules/models/node/processing/merge.html new file mode 100644 index 0000000..9e534b2 --- /dev/null +++ b/_modules/models/node/processing/merge.html @@ -0,0 +1,443 @@ + + + + + + + + models.node.processing.merge - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.merge

+import abc
+import string
+from random import choices
+from typing import List, Dict, Final
+from models.framework_data import FrameworkData
+from models.node.processing.synchronize import Synchronize
+
+
+# {
+# "nodes": {
+#     "root": {
+#         "node_a": {
+#             ...,
+#             "output": {
+#                 "data_a": [
+#                     {"node": "merge",
+#                     "input": "master_main"}
+#                 ],
+#                 "timestamp": [
+#                     {"node": "merge",
+#                     "input": "master_timestamp"}
+#                 ]
+#             },
+#         },
+#         "node_b": {
+#             ...,
+#             "output": {
+#                 "data_b": [
+#                     {
+#                         "node": "merge",
+#                         "input": "slave_main"
+#                     }
+#                 ],
+#                 "timestamp": [
+#                     {"node": "merge",
+#                     "input": "slave_timestamp"}
+#                 ]
+#             },
+#         }
+#     },
+#     "common": {
+#         "merge": {
+#             "module": "models.node.processing",
+#             "type": "Merge",
+#             ...
+#         }
+#     },
+#     ...
+# }
+#     }
+
+
+
[docs]class Merge(Synchronize): + """ This node merges the data from the master and the slave. The master data is always kept. If the slave data + contains a channel that is also present in the master data, the slave data is renamed to a new channel name and + added to the master data. This node also automatically synchronizes the data if the slave data is not synchronized + with the master data. + This node usage is a bit tricky. It goes in the "common" section of the configuration file, and it needs to have + at least two nodes before him (the master and the slave) that will point their outputs to this "merge" node. Those + previous nodes must have a additional "timestamp" property, that will define if they have a master or a slave timestamp. + The "output" property of this previous node will also have a property that defines if this node will be the master or + the slave. Here's an example of the previous nodes "output" and "timestamp" properties: + + .. code-block:: + + { + "nodes": { + "root": { + "node_a": { + ..., + "output": { + "data_a": [ + { + "node": "merge", + "input": "master_main" + } + ], + "timestamp": [ + { + "node": "merge", + "input": "master_timestamp" + } + ] + }, + }, + "node_b": { + ..., + "output": { + "data_b": [ + { + "node": "merge", + "input": "slave_main" + } + ], + "timestamp": [ + { + "node": "merge", + "input": "slave_timestamp" + } + ] + }, + } + }, + "common": { + "merge": { + "module": "models.node.processing", + "type": "Merge", + ... + } + }, + ... + } + } + + ``configuration.json`` usage: + **module** (*str*): Current module name (in this case ``models.node.processing``).\n + **type** (*str*): Current node type (in this case ``Merge``).\n + **slave_filling** (*str*): Slave filling type. It can be ``zero_fill`` or ``sample_and_hold``.\n + **statistics_enabled** (*bool*): If ``True``, the node will calculate the synchronization error statistics.\n + **buffer_options** (*dict*): Buffer options: + **clear_output_buffer_on_data_input** (*bool*): If ``True``, the output buffer will be cleared when data is inputted.\n + **clear_input_buffer_after_process** (*bool*): If ``True``, the input buffer will be cleared after the node is executed.\n + **clear_output_buffer_after_process** (*bool*): If ``True``, the output buffer will be cleared after the node is executed.\n + """ + _MODULE_NAME: Final[str] = 'node.processing.merge' + + OUTPUT_MERGED_MAIN: Final[str] = 'merged_main' + OUTPUT_MERGED_TIMESTAMP: Final[str] = 'merged_timestamp' + + @abc.abstractmethod + def _validate_parameters(self, parameters: dict): + """Validates the parameters that were passed to the node. In this case it just calls the parent method. + """ + super()._validate_parameters(parameters) + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + """Initializes the parameters that were passed to the node. In this case it just calls the parent method. + """ + super()._initialize_parameter_fields(parameters) + + def _is_next_node_call_enabled(self) -> bool: + """ This method allows the next node call. In this case it enables whenever there's data in the output buffer. + """ + return self._output_buffer[self.OUTPUT_MERGED_MAIN].get_data_count() > 0 + + def _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + """ This method processes the data that was inputted to the node. It merges the master and the slave data. + + :param data: The data that was inputted to the node. + :type data: Dict[str, FrameworkData] + + :return: The merged data. + :rtype: Dict[str, FrameworkData] + """ + synchronized_data: Dict[str, FrameworkData] = super()._process(data) + new_slave_data = synchronized_data[self.OUTPUT_SYNCHRONIZED_SLAVE] + master_main = synchronized_data[self.OUTPUT_SYNCHRONIZED_MASTER] + merged_data = FrameworkData() + merged_data.extend(master_main) + for channel in new_slave_data.channels: + new_channel_name = channel + if channel in merged_data.channels: + rand_id = ''.join(choices(string.ascii_uppercase + string.digits, k=10)) + new_channel_name = f'{channel}{rand_id}' + merged_data.input_data_on_channel(new_slave_data.get_data_on_channel(channel), new_channel_name) + + return { + self.OUTPUT_MERGED_MAIN: merged_data, + self.OUTPUT_MERGED_TIMESTAMP: synchronized_data[self.OUTPUT_SYNCHRONIZED_TIMESTAMP] + } + + def _get_outputs(self) -> List[str]: + """ This method returns the outputs of the node. In this case it returns the merged data and the merged timestamp. + """ + return [ + self.OUTPUT_MERGED_MAIN, + self.OUTPUT_MERGED_TIMESTAMP + ]
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/processing_node.html b/_modules/models/node/processing/processing_node.html new file mode 100644 index 0000000..380775a --- /dev/null +++ b/_modules/models/node/processing/processing_node.html @@ -0,0 +1,407 @@ + + + + + + + + models.node.processing.processing_node - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.processing_node

+import abc
+import copy
+from typing import List, Dict, Final
+
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.node import Node
+
+
+
[docs]class ProcessingNode(Node): + """ + A ProcessingNode is a type of Node that processes data from its input buffer to produce output data, based on its implemented + processing logic. It extends the Node abstract class. + + Attributes: + _MODULE_NAME (Final[str]): a constant string representing the name of the module where this class is defined. + + Methods: + __init__(self, parameters=None): + Initializes a ProcessingNode instance with the specified parameters. + + _validate_parameters(self, parameters: dict): + Validates the specified parameters for the ProcessingNode instance, raising MissingParameterError if any required + parameters are missing. + + _initialize_parameter_fields(self, parameters: dict): + Initializes any custom parameter fields for the ProcessingNode instance. + + _initialize_buffer_options(self, buffer_options: dict) -> None: + Initializes buffer behavior options for the ProcessingNode instance. + + _run(self, data: FrameworkData, input_name: str) -> None: + Runs the ProcessingNode instance by inserting new input data, processing the input buffer, and outputting the processed + data. + + _process_input_buffer(self): + Processes the input buffer to produce output data. + + _is_next_node_call_enabled(self) -> bool: + Returns True if the ProcessingNode instance allows the next node to be called, False otherwise. + + _is_processing_condition_satisfied(self) -> bool: + Returns True if the processing condition for the ProcessingNode instance is satisfied, False otherwise. + + _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + Processes the specified data to produce output data. + + _get_inputs(self) -> List[str]: + Returns a list of input names for the ProcessingNode instance. + + _get_outputs(self) -> List[str]: + Returns a list of output names for the ProcessingNode instance. + + dispose(self) -> None: + Disposes of the ProcessingNode instance. + """ + _MODULE_NAME: Final[str] = 'models.node.processing' + + def __init__(self, parameters=None) -> None: + super().__init__(parameters=parameters) + + @abc.abstractmethod + def _validate_parameters(self, parameters: dict): + super()._validate_parameters(parameters) + if 'clear_output_buffer_on_data_input' not in parameters['buffer_options']: + raise MissingParameterError( + module=self._MODULE_NAME,name=self.name, + parameter='buffer_options.clear_output_buffer_on_data_input' + ) + if 'clear_input_buffer_after_process' not in parameters['buffer_options']: + raise MissingParameterError( + module=self._MODULE_NAME,name=self.name, + parameter='buffer_options.clear_input_buffer_after_process' + ) + if 'clear_output_buffer_after_process' not in parameters['buffer_options']: + raise MissingParameterError( + module=self._MODULE_NAME,name=self.name, + parameter='buffer_options.clear_output_buffer_after_process' + ) + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + super()._initialize_parameter_fields(parameters) + + def _initialize_buffer_options(self, buffer_options: dict) -> None: + """Processing node implementation of buffer behaviour options initialization + + :param buffer_options: Buffer behaviour options. Should contain bool attributes 'clear_output_buffer_on_data_input', 'clear_input_buffer_after_process' and 'clear_output_buffer_after_process' + :type buffer_options: dict + """ + self._clear_output_buffer_on_data_input = buffer_options['clear_output_buffer_on_data_input'] + self._clear_input_buffer_after_process = buffer_options['clear_input_buffer_after_process'] + self._clear_output_buffer_after_process = buffer_options['clear_output_buffer_after_process'] + + def _run(self, data: FrameworkData, input_name: str) -> None: + self.print(f'Inserting data in input buffer {input_name}') + self._insert_new_input_data(data, input_name) + if self._clear_output_buffer_on_data_input: + self._clear_output_buffer() + self._process_input_buffer() + + def _process_input_buffer(self): + if not self._is_processing_condition_satisfied(): + return + self.print('Starting processing of input buffer') + processed_data = self._process(copy.deepcopy(self._input_buffer)) + if self._clear_input_buffer_after_process: + self._clear_input_buffer() + if self._clear_output_buffer_after_process: + self._clear_output_buffer() + self.print('Outputting data') + for output_name in self._get_outputs(): + self._insert_new_output_data(processed_data[output_name], output_name) + + @abc.abstractmethod + def _is_next_node_call_enabled(self) -> bool: + raise NotImplementedError() + + @abc.abstractmethod + def _is_processing_condition_satisfied(self) -> bool: + raise NotImplementedError() + + @abc.abstractmethod + def _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + """Node self implementation of data processing, relating input and outputs. + + :param data: data to be processed. + :type data: Dict[str,FrameworkData] + """ + raise NotImplementedError() + + @abc.abstractmethod + def _get_inputs(self) -> List[str]: + raise NotImplementedError() + + @abc.abstractmethod + def _get_outputs(self) -> List[str]: + raise NotImplementedError() + +
[docs] def dispose(self) -> None: + self._clear_input_buffer() + self._clear_output_buffer() + return
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/segmenter/fixedwindowsegmenter.html b/_modules/models/node/processing/segmenter/fixedwindowsegmenter.html new file mode 100644 index 0000000..4577c8f --- /dev/null +++ b/_modules/models/node/processing/segmenter/fixedwindowsegmenter.html @@ -0,0 +1,373 @@ + + + + + + + + models.node.processing.segmenter.fixedwindowsegmenter - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.segmenter.fixedwindowsegmenter

+import math
+
+from typing import Final
+
+from models.exception.invalid_parameter_value import InvalidParameterValue
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.processing.segmenter.segmenter import Segmenter
+
+
+
[docs]class FixedWindowSegmenter(Segmenter): + """ Segments the input data into fixed size windows. Each window is a list of samples, normally called epoch. + This is important because the other nodes in the pipeline expect the data to be segmented in this way. For exemple, + the trainable feature extractor node expects the input data to be segmented in epochs, so if you segment the data in epochs of + 200 samples and configure the feature extractor training_set_size to be 10, the feature extractor will use 2000 samples + to train the model. If you segment the data in epochs of 100 samples and configure the feature extractor training_set_size + to be 10, the feature extractor will use 1000 samples to train the model. + + Attributes: + _MODULE_NAME (str): The name of the module (in his case ``node.processing.segmenter.fixedwindowsegmenter``) + + configuration.json usage: + **module** (*str*): The name of the module (``node.processing.segmenter``)\n + **type** (*str*): The type of the node (``FixedWindowSegmenter``)\n + **window_size** (*int*): The size of the window (epoch) in samples.\n + **filling_value** (*str*): The value to fill the last window if it's not complete. Can be ``zero`` or ``latest``.\n + **buffer_options** (*dict*): Buffer options.\n + **clear_output_buffer_on_data_input** (*bool*): Whether to clear the output buffer when new data is inserted in the input buffer.\n + **clear_input_buffer_after_process** (*bool*): Whether to clear the input buffer after processing.\n + **clear_output_buffer_after_process** (*bool*): Whether to clear the output buffer after processing.\n + + + """ + _MODULE_NAME: Final[str] = 'node.processing.segmenter.fixedwindowsegmenter' + + def __init__(self, parameters: dict): + super().__init__(parameters) + self.window_size = parameters['window_size'] + self.filling_value = parameters['filling_value'] + + def _is_processing_condition_satisfied(self) -> bool: + """ Returns whether the processing condition is satisfied. In this case it returns True if there is data in the + input buffer. + """ + + return self._input_buffer[self.INPUT_MAIN].get_data_count() >= self.window_size + + def _validate_parameters(self, parameters: dict): + + """ Validates the parameters passed to this node. n this case it checks if the parameters are present and if they + are of the correct type. + + :param parameters: The parameters passed to this node. + :type parameters: dict + + :raises MissingParameterError: the ``window_size`` parameter is required. + :raises InvalidParameterValue: the ``window_size`` parameter must be an int. + :raises InvalidParameterValue: the ``window_size`` parameter must be greater than 0. + :raises MissingParameterError: the ``filling_value`` parameter is required. + :raises InvalidParameterValue: the ``filling_value`` parameter must be a str. + :raises InvalidParameterValue: the ``filling_value`` parameter must be in [``zero``, ``latest``]. + + """ + + super()._validate_parameters(parameters) + + if 'window_size' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='window_size') + if 'filling_value' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='filling_value') + if type(parameters['window_size']) is not int: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='window_size', + cause='must_be_int') + if parameters['window_size'] < 1: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='window_size', + cause='must_be_greater_than_0') + if type(parameters['filling_value']) is not str: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='filling_value', + cause='must_be_str') + if parameters['filling_value'] not in ['zero', 'latest']: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='filling_value', + cause='must_be_in.[zero, latest]') + +
[docs] def segment_data(self, data: FrameworkData) -> FrameworkData: + """Method that segments the data into fixed size windows. It just segments the data on the main input channel, + and if the last window is not complete, it fills it with zeros or with the last sample of the window, depending on + the ``filling_value`` parameter. + + :param data: The data to segment. + :type data: FrameworkData + + :return: The segmented data. + :rtype: FrameworkData + """ + segmented_data: FrameworkData = FrameworkData(sampling_frequency_hz=data.sampling_frequency) + while True: + if data.get_data_count() > self.window_size: + window = data.splice(0, self.window_size) + for channel in window.channels: + segmented_data.input_data_on_channel([window.get_data_on_channel(channel)], channel) + else: + break + return segmented_data
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/segmenter/segmenter.html b/_modules/models/node/processing/segmenter/segmenter.html new file mode 100644 index 0000000..98a72b1 --- /dev/null +++ b/_modules/models/node/processing/segmenter/segmenter.html @@ -0,0 +1,337 @@ + + + + + + + + models.node.processing.segmenter.segmenter - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.segmenter.segmenter

+import abc
+from typing import List, Dict, Final
+from models.framework_data import FrameworkData
+from models.node.processing.processing_node import ProcessingNode
+
+
+
[docs]class Segmenter(ProcessingNode): + """ This is the base class for all segmenters. A segmenter is a node that segments the input data into smaller parts. + In many applications of the signal processing such as automatic analysis of EEG signal, it is needed that signal is + split to smaller parts that each part has the same statistical characterizations such as the amplitude and frequency. + This is called segmentation. This class does that by segmenting the input data into smaller parts. The segmentation + itself is done by the segment_data method that must be implemented by the subclasses. + + Attributes: + _MODULE_NAME (`str`): The name of the module (in his case ``node.processing.segmenter.segmenter``) + INPUT_MAIN (`str`): The name of the main input (``main``) + OUTPUT_MAIN (`str`): The name of the main output (``main``) + """ + _MODULE_NAME: Final[str] = 'node.processing.segmenter.segmenter' + + INPUT_MAIN: Final[str] = 'main' + OUTPUT_MAIN: Final[str] = 'main' + + @abc.abstractmethod + def _validate_parameters(self, parameters: dict): + """ Validates the parameters passed to this node. In this case it just calls the super method from ProcessingNode. + """ + super()._validate_parameters(parameters) + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + """ Initializes the parameter fields of this node. In this case it just calls the super method from ProcessingNode. + """ + super()._initialize_parameter_fields(parameters) + + def _is_next_node_call_enabled(self) -> bool: + """ Returns whether the next node call is enabled. It's enabled whenever there's data in the main output buffer. + """ + return self._output_buffer[self.OUTPUT_MAIN].get_data_count() > 0 + + def _is_processing_condition_satisfied(self) -> bool: + """ Returns whether the processing condition is satisfied. In this case it returns True if there is data in the + input buffer. + """ + return self._input_buffer[self.INPUT_MAIN].get_data_count() > 0 + +
[docs] @abc.abstractmethod + def segment_data(self, data: FrameworkData) -> FrameworkData: + """ This method segments the data. It must be implemented by the subclasses. + """ + raise NotImplementedError()
+ + def _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + """ This method segments the data. It calls the segment_data method for each data in the FrameworkData object. + """ + segmented_data: Dict[str, FrameworkData] = {} + for key in data: + segmented_data[key] = self.segment_data(data[key]) + return segmented_data + + def _get_inputs(self) -> List[str]: + """ Returns the inputs of this node. + """ + return [ + self.INPUT_MAIN + ] + + def _get_outputs(self) -> List[str]: + """ Returns the outputs of this node. + """ + return [ + self.OUTPUT_MAIN + ]
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/signalcheck.html b/_modules/models/node/processing/signalcheck.html new file mode 100644 index 0000000..2779f50 --- /dev/null +++ b/_modules/models/node/processing/signalcheck.html @@ -0,0 +1,303 @@ + + + + + + + + models.node.processing.signalcheck - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.signalcheck

+import abc
+from typing import List, Final, Dict
+
+from models.framework_data import FrameworkData
+from models.node.processing.processing_node import ProcessingNode
+from typing import List
+
+
+
[docs]class SignalCheck(ProcessingNode): + _MODULE_NAME: Final[str] = 'node.processing.signalcheck' + + INPUT_MAIN: Final[str] = 'main' + OUTPUT_MAIN: Final[str] = 'main' + + @abc.abstractmethod + def _initialize_parameter_fields(self, parameters: dict): + super()._initialize_parameter_fields(parameters) + + def _is_next_node_call_enabled(self) -> bool: + return True + + def _is_processing_condition_satisfied(self) -> bool: + # TODO change + return True + + def _process(self, data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + # TODO change + print('SignalCheck!') + return data + + def _get_inputs(self) -> List[str]: + return [ + self.INPUT_MAIN + ] + + def _get_outputs(self) -> List[str]: + return [ + self.OUTPUT_MAIN + ]
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/node/processing/synchronize.html b/_modules/models/node/processing/synchronize.html new file mode 100644 index 0000000..8580c5f --- /dev/null +++ b/_modules/models/node/processing/synchronize.html @@ -0,0 +1,664 @@ + + + + + + + + models.node.processing.synchronize - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.node.processing.synchronize

+import statistics
+import copy
+from bisect import bisect_left
+from typing import List, Dict, Final
+
+from models.exception.invalid_parameter_value import InvalidParameterValue
+from models.exception.missing_parameter import MissingParameterError
+from models.framework_data import FrameworkData
+from models.node.processing.processing_node import ProcessingNode
+
+
+
[docs]class Synchronize(ProcessingNode): + _MODULE_NAME: Final[str] = 'node.processing.synchronize' + + INPUT_MASTER_MAIN: Final[str] = 'master_main' + INPUT_MASTER_TIMESTAMP: Final[str] = 'master_timestamp' + INPUT_SLAVE_MAIN: Final[str] = 'slave_main' + INPUT_SLAVE_TIMESTAMP: Final[str] = 'slave_timestamp' + OUTPUT_SYNCHRONIZED_SLAVE: Final[str] = 'synchronized_slave' + OUTPUT_SYNCHRONIZED_MASTER: Final[str] = 'synchronized_master' + OUTPUT_SYNCHRONIZED_TIMESTAMP: Final[str] = 'synchronized_timestamp' + + FILL_TYPE_ZEROFILL: Final[str] = 'zero_fill' + FILL_TYPE_SAMPLE_AND_HOLD: Final[str] = 'sample_and_hold' + + def _validate_parameters(self, parameters: dict): + parameters['buffer_options']['clear_input_buffer_after_process'] = True + super()._validate_parameters(parameters) + if 'slave_filling' not in parameters: + raise MissingParameterError(module=self._MODULE_NAME, name=self.name, + parameter='slave_filling') + + if parameters['slave_filling'] not in [self.FILL_TYPE_ZEROFILL, self.FILL_TYPE_SAMPLE_AND_HOLD]: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='slave_filling', + cause=f'not_in_[{self.FILL_TYPE_ZEROFILL},{self.FILL_TYPE_SAMPLE_AND_HOLD}]') + if 'statistics_enabled' in parameters and type(parameters['statistics_enabled']) is not bool: + raise InvalidParameterValue(module=self._MODULE_NAME, name=self.name, + parameter='statistics_enabled', + cause='must_be_bool') + + def _initialize_parameter_fields(self, parameters: dict): + super()._initialize_parameter_fields(parameters) + self._statistics_enabled = parameters['statistics_enabled'] if 'statistics_enabled' in parameters else False + self._zero_fill = parameters['slave_filling'] == self.FILL_TYPE_ZEROFILL + self._sample_and_hold = parameters['slave_filling'] == self.FILL_TYPE_SAMPLE_AND_HOLD + self._sync_errors: List[float] = [] + self._exec_index = 0 + self._last_valid_data = None + self._initialize_sync_buffer() + + def _is_next_node_call_enabled(self) -> bool: + return True + + def _initialize_sync_buffer(self): + """Sets sync buffer to new empty object for each input name + """ + self._sync_buffer = {} + for input_name in self._get_inputs(): + self._sync_buffer[input_name] = FrameworkData() + + def _insert_data_in_sync_buffer(self, data: Dict[str, FrameworkData]): + input_data = copy.deepcopy(data) + for input_name in self._get_inputs(): + self._sync_buffer[input_name].extend(input_data[input_name]) + + def _check_for_timestamp_intersection(self, slave_timestamp_data: List[float], + master_timestamp_data: List[float]) -> bool: + slave_start = slave_timestamp_data[0] + slave_end = slave_timestamp_data[-1] + master_start = master_timestamp_data[0] + master_end = master_timestamp_data[-1] + return slave_start < master_end and slave_end > master_start + + def _move_input_buffer_to_sync_buffer(self): + slave_main_length = self._input_buffer[self.INPUT_SLAVE_MAIN].get_data_count() + slave_timestamp_length = self._input_buffer[self.INPUT_SLAVE_TIMESTAMP].get_data_count() + master_main_length = self._input_buffer[self.INPUT_MASTER_MAIN].get_data_count() + master_timestamp_length = self._input_buffer[self.INPUT_MASTER_TIMESTAMP].get_data_count() + slave_main = self._input_buffer[self.INPUT_SLAVE_MAIN] + slave_timestamp = self._input_buffer[self.INPUT_SLAVE_TIMESTAMP] + master_main = self._input_buffer[self.INPUT_MASTER_MAIN] + master_timestamp = self._input_buffer[self.INPUT_MASTER_TIMESTAMP] + self._sync_buffer[self.INPUT_SLAVE_MAIN].extend(slave_main.splice(0, min(slave_main_length, slave_timestamp_length))) + self._sync_buffer[self.INPUT_SLAVE_TIMESTAMP].extend(slave_timestamp.splice(0, min(slave_main_length, slave_timestamp_length))) + self._sync_buffer[self.INPUT_MASTER_MAIN].extend(master_main.splice(0, min(master_main_length, master_timestamp_length))) + self._sync_buffer[self.INPUT_MASTER_TIMESTAMP].extend(master_timestamp.splice(0, min(master_main_length, master_timestamp_length))) + + def _process_input_buffer(self): + self._move_input_buffer_to_sync_buffer() + + if not self._is_processing_condition_satisfied(): + return + + processed_data = self._process(copy.deepcopy(self._sync_buffer)) + + if self._clear_output_buffer_after_process: + self._clear_output_buffer() + self.print('Outputting data') + for output_name in self._get_outputs(): + self._insert_new_output_data(processed_data[output_name], output_name) + + def _is_processing_condition_satisfied(self) -> bool: + input_data = self._sync_buffer + slave_timestamp = input_data[self.INPUT_SLAVE_TIMESTAMP] + master_timestamp = input_data[self.INPUT_MASTER_TIMESTAMP] + slave_main = input_data[self.INPUT_SLAVE_MAIN] + master_main = input_data[self.INPUT_MASTER_MAIN] + + return (slave_timestamp.get_data_count() > 2 + and master_timestamp.get_data_count() > 2 + and slave_main.get_data_count() == slave_timestamp.get_data_count() + and master_main.get_data_count() == master_timestamp.get_data_count() + and self._check_for_timestamp_intersection(slave_timestamp.get_data_single_channel(), master_timestamp.get_data_single_channel())) + + def _process(self, input_data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + self._exec_index += 1 + if self._exec_index == 1: + input_data = self._trim_start(input_data) + input_data = self._trim_end(input_data) + master_timestamp_data = input_data[self.INPUT_MASTER_TIMESTAMP].get_data_single_channel() + slave_main = input_data[self.INPUT_SLAVE_MAIN] + slave_timestamp = input_data[self.INPUT_SLAVE_TIMESTAMP] + slave_timestamp_data = slave_timestamp.get_data_single_channel() + + if slave_timestamp.get_data_count() < 1 or len(master_timestamp_data) < 1: + return { + self.OUTPUT_SYNCHRONIZED_SLAVE: slave_main, + self.OUTPUT_SYNCHRONIZED_MASTER: input_data[self.INPUT_MASTER_MAIN], + self.OUTPUT_SYNCHRONIZED_TIMESTAMP: input_data[self.INPUT_MASTER_TIMESTAMP] + } + + filled_slave_data = self._fill(master_timestamp_data, slave_timestamp_data, slave_main, + input_data[self.INPUT_MASTER_TIMESTAMP].sampling_frequency) + + return { + self.OUTPUT_SYNCHRONIZED_SLAVE: filled_slave_data, + self.OUTPUT_SYNCHRONIZED_MASTER: input_data[self.INPUT_MASTER_MAIN], + self.OUTPUT_SYNCHRONIZED_TIMESTAMP: input_data[self.INPUT_MASTER_TIMESTAMP] + } + + def _statistics(self, sync_error_microseconds: float): + if self._statistics_enabled: + self._sync_errors.append(sync_error_microseconds) + print(f'---------------------------------------------------------------' + f'\nError is:\t\t\t\t{sync_error_microseconds} uS' + f'\nMean Error is:\t\t\t{statistics.mean(self._sync_errors)} uS' + f'\n---------------------------------------------------------------') + + def _get_inputs(self) -> List[str]: + return [ + self.INPUT_MASTER_MAIN, + self.INPUT_MASTER_TIMESTAMP, + self.INPUT_SLAVE_MAIN, + self.INPUT_SLAVE_TIMESTAMP, + ] + + def _get_outputs(self) -> List[str]: + return [ + self.OUTPUT_SYNCHRONIZED_SLAVE, + self.OUTPUT_SYNCHRONIZED_MASTER, + self.OUTPUT_SYNCHRONIZED_TIMESTAMP + ] + + def _get_closest_timestamp_index_in_master( + self, + master_timestamp: List[float], + slave_timestamp: float, + master_timestamp_avg_increment: float, + master_max_index: int) -> int: + + if slave_timestamp < master_timestamp[0]: + return 0 + + estimated_index = int((slave_timestamp - master_timestamp[0]) / master_timestamp_avg_increment) + bisect_index = bisect_left(master_timestamp, slave_timestamp) + if estimated_index < 0: + return 0 + + if estimated_index < 0 and slave_timestamp <= master_timestamp[0]: + return 0 + elif estimated_index > master_max_index and slave_timestamp >= master_timestamp[master_max_index]: + return master_max_index + elif estimated_index == 0 and slave_timestamp < master_timestamp[1]: + return estimated_index + elif estimated_index == master_max_index and (slave_timestamp > master_timestamp[master_max_index - 1]): + return estimated_index + + while 0 < estimated_index < master_max_index: + if master_timestamp[estimated_index - 1] <= slave_timestamp <= master_timestamp[estimated_index + 1]: + return estimated_index + elif slave_timestamp < master_timestamp[estimated_index]: + estimated_index -= 1 + elif slave_timestamp > master_timestamp[estimated_index]: + estimated_index += 1 + + closest_point: int = min(range(len(master_timestamp)), + key=lambda i: abs(master_timestamp[i] - slave_timestamp)) + return closest_point + + def _trim_start(self, input_data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + index = 0 + slave_timestamp = input_data[self.INPUT_SLAVE_TIMESTAMP] + slave_main = input_data[self.INPUT_SLAVE_MAIN] + master_timestamp = input_data[self.INPUT_MASTER_TIMESTAMP] + master_main = input_data[self.INPUT_MASTER_MAIN] + slave_timestamp_data = slave_timestamp.get_data_single_channel() + master_timestamp_data = master_timestamp.get_data_single_channel() + + slave_avg_increment = (slave_timestamp_data[-1] - slave_timestamp_data[0]) / len(slave_timestamp_data) + master_avg_increment = (master_timestamp_data[-1] - master_timestamp_data[0]) / len(master_timestamp_data) + + should_trim_slave = slave_timestamp_data[index] < master_timestamp_data[index] + should_trim_master = master_timestamp_data[index] < slave_timestamp_data[index] + + if should_trim_slave: + slave_index = self._get_closest_timestamp_index_in_master( + slave_timestamp_data, + master_timestamp_data[index], + slave_avg_increment, + len(slave_timestamp_data) - 1 + ) + start_index = 0 + remove_count = slave_index + slave_timestamp.splice(start_index, remove_count) + slave_main.splice(start_index, remove_count) + self._sync_buffer[self.INPUT_SLAVE_TIMESTAMP].splice(0, slave_index) + self._sync_buffer[self.INPUT_SLAVE_MAIN].splice(0, slave_index) + + elif should_trim_master: + master_index = self._get_closest_timestamp_index_in_master( + master_timestamp_data, + slave_timestamp_data[index], + master_avg_increment, + len(master_timestamp_data) - 1 + ) + start_index = 0 + remove_count = master_index + master_timestamp.splice(start_index, remove_count) + master_main.splice(start_index, remove_count) + self._sync_buffer[self.INPUT_MASTER_TIMESTAMP].splice(0, master_index) + self._sync_buffer[self.INPUT_MASTER_MAIN].splice(0, master_index) + + return { + self.INPUT_MASTER_MAIN: master_main, + self.INPUT_MASTER_TIMESTAMP: master_timestamp, + self.INPUT_SLAVE_MAIN: slave_main, + self.INPUT_SLAVE_TIMESTAMP: slave_timestamp + } + + def _trim_end(self, input_data: Dict[str, FrameworkData]) -> Dict[str, FrameworkData]: + index = -1 + slave_timestamp = input_data[self.INPUT_SLAVE_TIMESTAMP] + slave_main = input_data[self.INPUT_SLAVE_MAIN] + master_timestamp = input_data[self.INPUT_MASTER_TIMESTAMP] + master_main = input_data[self.INPUT_MASTER_MAIN] + slave_timestamp_data = slave_timestamp.get_data_single_channel() + master_timestamp_data = master_timestamp.get_data_single_channel() + slave_avg_increment = (slave_timestamp_data[-1] - slave_timestamp_data[0]) / len(slave_timestamp_data) + master_avg_increment = (master_timestamp_data[-1] - master_timestamp_data[0]) / len(master_timestamp_data) + + should_trim_slave = slave_timestamp_data[index] > master_timestamp_data[index] + should_trim_master = master_timestamp_data[index] > slave_timestamp_data[index] + + if should_trim_slave: + while int((slave_timestamp_data[index] - master_timestamp_data[0]) / master_avg_increment) > len( + master_timestamp_data) - 1: + index -= 1 + if index < -len(slave_timestamp_data): + return { + self.INPUT_MASTER_MAIN: FrameworkData(sampling_frequency_hz=master_main.sampling_frequency, + channels=master_main.channels), + self.INPUT_MASTER_TIMESTAMP: FrameworkData( + sampling_frequency_hz=master_timestamp.sampling_frequency, + channels=master_timestamp.channels), + self.INPUT_SLAVE_MAIN: FrameworkData(sampling_frequency_hz=slave_main.sampling_frequency, + channels=slave_main.channels), + self.INPUT_SLAVE_TIMESTAMP: FrameworkData( + sampling_frequency_hz=slave_timestamp.sampling_frequency, channels=slave_timestamp.channels) + } + master_index = self._get_closest_timestamp_index_in_master( + master_timestamp_data, + slave_timestamp_data[index], + master_avg_increment, + len(master_timestamp_data) - 1 + ) + # keep slave data from index to end in sync buffer and remove the rest + self._sync_buffer[self.INPUT_SLAVE_TIMESTAMP].splice(0, len(slave_timestamp_data) + index + 1) + self._sync_buffer[self.INPUT_SLAVE_MAIN].splice(0, len(slave_timestamp_data) + index + 1) + # process slave data from 0 to index + slave_main.splice(len(slave_timestamp_data) + index + 1, -index) + slave_timestamp.splice(len(slave_timestamp_data) + index + 1, -index) + # keep master data from master_index to end in sync buffer and remove the rest + self._sync_buffer[self.INPUT_MASTER_TIMESTAMP].splice(0, master_index + 1) + self._sync_buffer[self.INPUT_MASTER_MAIN].splice(0, master_index + 1) + # process master data from 0 to master_index + master_main.splice(master_index + 1, len(master_timestamp_data) - master_index) + master_timestamp.splice(master_index + 1, len(master_timestamp_data) - master_index) + + elif should_trim_master: + while int((master_timestamp_data[index] - slave_timestamp_data[0]) / slave_avg_increment) > len( + slave_timestamp_data) - 1: + index -= 1 + if index < -len(master_timestamp_data): + # return empty data + return { + self.INPUT_MASTER_MAIN: FrameworkData(sampling_frequency_hz=master_main.sampling_frequency, + channels=master_main.channels), + self.INPUT_MASTER_TIMESTAMP: FrameworkData( + sampling_frequency_hz=master_timestamp.sampling_frequency, + channels=master_timestamp.channels), + self.INPUT_SLAVE_MAIN: FrameworkData(sampling_frequency_hz=slave_main.sampling_frequency, + channels=slave_main.channels), + self.INPUT_SLAVE_TIMESTAMP: FrameworkData( + sampling_frequency_hz=slave_timestamp.sampling_frequency, channels=slave_timestamp.channels) + } + + slave_index = self._get_closest_timestamp_index_in_master( + slave_timestamp_data, + master_timestamp_data[index], + slave_avg_increment, + len(slave_timestamp_data) - 1 + ) + # keep master data from index to end in sync buffer and remove the rest + self._sync_buffer[self.INPUT_MASTER_TIMESTAMP].splice(0, len(master_timestamp_data) + index + 1) + self._sync_buffer[self.INPUT_MASTER_MAIN].splice(0, len(master_timestamp_data) + index + 1) + # process master data from 0 to index + master_main.splice(len(master_timestamp_data) + index + 1, -index) + master_timestamp.splice(len(master_timestamp_data) + index + 1, -index) + # keep slave data from slave_index to end in sync buffer and remove the rest + self._sync_buffer[self.INPUT_SLAVE_TIMESTAMP].splice(0, slave_index + 1) + self._sync_buffer[self.INPUT_SLAVE_MAIN].splice(0, slave_index + 1) + # process slave data from 0 to slave_index + slave_main.splice(slave_index + 1, len(master_timestamp_data) - slave_index) + slave_timestamp.splice(slave_index + 1, len(master_timestamp_data) - slave_index) + + return { + self.INPUT_MASTER_MAIN: master_main, + self.INPUT_MASTER_TIMESTAMP: master_timestamp, + self.INPUT_SLAVE_MAIN: slave_main, + self.INPUT_SLAVE_TIMESTAMP: slave_timestamp + } + + def _fill(self, master_timestamp: List[float], slave_timestamp: List[float], + slave_main: FrameworkData, master_sampling_frequency: float) -> FrameworkData: + """Fills slave data to align with master timestamps using sample-and-hold.""" + + # Create FrameworkData to store filled data + fill_data = FrameworkData(master_sampling_frequency, slave_main.channels) + + # Calculate average increment between master timestamps + max_slave_index = len(slave_timestamp) - 1 + max_master_index = len(master_timestamp) - 1 + previous_master_index = -1 # Start before the first index + # Iterate over slave timestamps + for current_slave_index, slave_time in enumerate(slave_timestamp): + + # Ignore repeated slave timestamps + if current_slave_index > 0 and slave_time == slave_timestamp[current_slave_index - 1]: + continue + + # Use binary search to find the closest master timestamp index + master_index = bisect_left(master_timestamp, slave_time) + + # Ensure master_index does not exceed valid range + if master_index > max_master_index: + master_index = max_master_index + + # Calculate how many master timestamps need to be filled + fill_size = master_index - previous_master_index - 1 + + # If there's a gap, fill it using the last valid data or 0 + if fill_size > 0 and self._last_valid_data is not None: + for channel in slave_main.channels: + fill_content = [self._last_valid_data[channel]] * fill_size if self._sample_and_hold else [ + 0] * fill_size + fill_data.input_data_on_channel(fill_content, channel) + + # If aligning slave data, or it's the first valid data point + if ( + self._last_valid_data is None or master_index >= previous_master_index) and current_slave_index <= max_slave_index: + # Update last valid data with current slave data + self._last_valid_data = slave_main.get_data_at_index(current_slave_index) + + # Store slave data for all channels at the aligned master timestamp + for channel in slave_main.channels: + fill_data.input_data_on_channel([self._last_valid_data[channel]], channel) + + # Update the previous master index for the next iteration + previous_master_index = master_index + + # Fill any remaining master timestamps with sample-and-hold or 0 + remaining_fill_size = max_master_index - previous_master_index + if remaining_fill_size > 0 and self._last_valid_data is not None: + for channel in slave_main.channels: + fill_content = [self._last_valid_data[channel]] * remaining_fill_size if self._sample_and_hold else [ + 0] * remaining_fill_size + fill_data.input_data_on_channel(fill_content, channel) + + return fill_data
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/utils/cue.html b/_modules/models/utils/cue.html new file mode 100644 index 0000000..698b49b --- /dev/null +++ b/_modules/models/utils/cue.html @@ -0,0 +1,343 @@ + + + + + + + + models.utils.cue - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.utils.cue

+import os
+from threading import Thread
+from typing import Any, Final
+
+from models.exception.missing_parameter import MissingParameterError
+from models.utils.script_execution import script_execute
+
+
+
[docs]class Cue: + """This class executes a specific cue (a script/function) defined by the user in a different python file (e.g. Print a value, Save a + velue in a file, etc.). The cue can be anything that the user wants to execute when the trial starts or ends. + + :param function: The function that will be executed when the cue is called. + :type function: Any + :param parameters: The parameters that will be passed to the cue function when it is executed. + :type parameters: dict + + :raises MissingParameterError: The ``function`` parameter is required. + + ``config.json`` example: + + **file** (*str*): Cue file path.\n + **parameters** (*dict*): The parameters that will be passed to the cue function defined in **file** when it is executed. This can + be anything that the user needs to pass to the cue function.\n + + """ + _MODULE_NAME: Final[str] = 'utils.cue' + + def __init__(self, filename: str, function: Any, parameters: dict) -> None: + """Constructor method. Initializes and validates the parameters of the class. + """ + super().__init__() + if function is None: + raise MissingParameterError(module=self._MODULE_NAME, + name='cue', + parameter='function') + if parameters is None: + parameters = {} + self._filename = filename + self._function = function + self._function_parameters = parameters + +
[docs] @classmethod + def from_config_json(cls, parameters: dict): + """Creates a new instance of this class and initializes it with the parameters that were passed to it. + """ + if 'file' not in parameters: + raise MissingParameterError(module=cls._MODULE_NAME, + name='cue', + parameter='file') + if 'parameters' not in parameters: + cue_parameters = {} + else: + cue_parameters = parameters['parameters'] + cue_function_path = parameters['file'] + _locals = script_execute(parameters['file']) + if 'custom_cue' not in _locals: + raise ValueError( + 'session.trial.cue.custom_cue.not.defined.in.script.%s' % cue_function_path) + return cls( + filename=parameters['file'], + function=_locals['custom_cue'], + parameters=cue_parameters + )
+ + def _run_function(self): + """Runs the cue function. + """ + self._function(self._function_parameters) + +
[docs] def execute(self): + """Executes the cue function with the parameters that were passed to it. + """ + thread = Thread(target=self._run_function) + thread.start()
+ # thread.join() + + def __str__(self): + return '{' + f'"file":{self._filename},"parameters":{self._function_parameters}' + '}'
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_modules/models/utils/script_execution.html b/_modules/models/utils/script_execution.html new file mode 100644 index 0000000..0983227 --- /dev/null +++ b/_modules/models/utils/script_execution.html @@ -0,0 +1,289 @@ + + + + + + + + models.utils.script_execution - Open_BCI_Framework 0.0.1 documentation + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for models.utils.script_execution

+import os
+from typing import Dict, Any
+
+
+
[docs]def script_execute(script_path: str) -> Dict[str, Any]: + """This function executes a custom python script and returns the locals dict that was generated by the script. + + :param script_path: The path to the custom python script. + :type script_path: str + + :raises ValueError: The script file doesn't exist. + + :return: The locals dict that was generated by the script. + """ + if not os.path.isfile(script_path): + raise ValueError('utils.script_execute.file.doesnt.exist.%s' % script_path) + # Open and read the given custom python script + file = open(script_path, 'r') + script = file.read() + # Compile the script + compiled_script = compile(script, '', 'exec') + _locals = locals() + # Execute the script, setting _locals dict + exec(compiled_script, _locals) + return _locals
+
+
+
+
+ + +
+
+ + Made with Sphinx and @pradyunsg's + + Furo + +
+
+ +
+
+ +
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/_sources/application.rst.txt b/_sources/application.rst.txt new file mode 100644 index 0000000..29305a2 --- /dev/null +++ b/_sources/application.rst.txt @@ -0,0 +1,7 @@ +application module +================== + +.. automodule:: application + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 0000000..5b01636 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,20 @@ +.. Open_BCI_Framework documentation master file, created by + sphinx-quickstart on Fri Apr 14 11:09:27 2023. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Open_BCI_Framework's documentation! +============================================== + +.. toctree:: + :maxdepth: 10 + :caption: Contents: + + modules + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/_sources/main.rst.txt b/_sources/main.rst.txt new file mode 100644 index 0000000..eace87b --- /dev/null +++ b/_sources/main.rst.txt @@ -0,0 +1,7 @@ +main module +=========== + +.. automodule:: main + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.exception.rst.txt b/_sources/models.exception.rst.txt new file mode 100644 index 0000000..5cfb72c --- /dev/null +++ b/_sources/models.exception.rst.txt @@ -0,0 +1,45 @@ +models.exception package +======================== + +Submodules +---------- + +framework\_base\_exception module +-------------------------------------------------- + +.. automodule:: models.exception.framework_base_exception + :members: + :undoc-members: + :show-inheritance: + +invalid\_parameter\_value module +------------------------------------------------- + +.. automodule:: models.exception.invalid_parameter_value + :members: + :undoc-members: + :show-inheritance: false + +missing\_parameter module +------------------------------------------ + +.. automodule:: models.exception.missing_parameter + :members: + :undoc-members: + :show-inheritance: + +non\_compatible\_data module +--------------------------------------------- + +.. automodule:: models.exception.non_compatible_data + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.exception + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.generator.file.rst.txt b/_sources/models.node.generator.file.rst.txt new file mode 100644 index 0000000..398ead8 --- /dev/null +++ b/_sources/models.node.generator.file.rst.txt @@ -0,0 +1,29 @@ +models.node.generator.file package +================================== + +Submodules +---------- + +models.node.generator.file.csvfile module +----------------------------------------- + +.. automodule:: models.node.generator.file.csvfile + :members: + :undoc-members: + :show-inheritance: + +models.node.generator.file.csvfilearray module +---------------------------------------------- + +.. automodule:: models.node.generator.file.csvfilearray + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.generator.file + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.generator.rst.txt b/_sources/models.node.generator.rst.txt new file mode 100644 index 0000000..446e8eb --- /dev/null +++ b/_sources/models.node.generator.rst.txt @@ -0,0 +1,53 @@ +models.node.generator package +============================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + models.node.generator.file + +Submodules +---------- + +models.node.generator.generator\_node module +-------------------------------------------- + +.. automodule:: models.node.generator.generator_node + :members: + :undoc-members: + :show-inheritance: + +models.node.generator.motorimagery module +----------------------------------------- + +.. automodule:: models.node.generator.motorimagery + :members: + :undoc-members: + :show-inheritance: + +models.node.generator.openbciboard module +----------------------------------------- + +.. automodule:: models.node.generator.openbciboard + :members: + :undoc-members: + :show-inheritance: + +models.node.generator.single\_run\_generator\_node module +--------------------------------------------------------- + +.. automodule:: models.node.generator.single_run_generator_node + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.generator + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.output.device.rst.txt b/_sources/models.node.output.device.rst.txt new file mode 100644 index 0000000..8a1f73f --- /dev/null +++ b/_sources/models.node.output.device.rst.txt @@ -0,0 +1,21 @@ +models.node.output.device package +================================= + +Submodules +---------- + +models.node.output.device.eletroestimuladordopaulo module +--------------------------------------------------------- + +.. automodule:: models.node.output.device.eletroestimuladordopaulo + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.output.device + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.output.display.rst.txt b/_sources/models.node.output.display.rst.txt new file mode 100644 index 0000000..1f8834e --- /dev/null +++ b/_sources/models.node.output.display.rst.txt @@ -0,0 +1,21 @@ +models.node.output.display package +================================== + +Submodules +---------- + +models.node.output.display.simplegraph module +--------------------------------------------- + +.. automodule:: models.node.output.display.simplegraph + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.output.display + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.output.file.rst.txt b/_sources/models.node.output.file.rst.txt new file mode 100644 index 0000000..00a41d8 --- /dev/null +++ b/_sources/models.node.output.file.rst.txt @@ -0,0 +1,29 @@ +models.node.output.file package +=============================== + +Submodules +---------- + +models.node.output.file.csvfile module +-------------------------------------- + +.. automodule:: models.node.output.file.csvfile + :members: + :undoc-members: + :show-inheritance: + +models.node.output.file.writeedf module +--------------------------------------- + +.. automodule:: models.node.output.file.writeedf + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.output.file + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.output.rst.txt b/_sources/models.node.output.rst.txt new file mode 100644 index 0000000..cbe94ae --- /dev/null +++ b/_sources/models.node.output.rst.txt @@ -0,0 +1,31 @@ +models.node.output package +========================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + models.node.output.device + models.node.output.display + models.node.output.file + +Submodules +---------- + +models.node.output.output\_node module +-------------------------------------- + +.. automodule:: models.node.output.output_node + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.output + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.processing.encoder.rst.txt b/_sources/models.node.processing.encoder.rst.txt new file mode 100644 index 0000000..732a296 --- /dev/null +++ b/_sources/models.node.processing.encoder.rst.txt @@ -0,0 +1,29 @@ +models.node.processing.encoder package +====================================== + +Submodules +---------- + +models.node.processing.encoder.onehottosingle module +---------------------------------------------------- + +.. automodule:: models.node.processing.encoder.onehottosingle + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.encoder.singletoonehot module +---------------------------------------------------- + +.. automodule:: models.node.processing.encoder.singletoonehot + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.processing.encoder + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.processing.feature_extractor.rst.txt b/_sources/models.node.processing.feature_extractor.rst.txt new file mode 100644 index 0000000..bd5b920 --- /dev/null +++ b/_sources/models.node.processing.feature_extractor.rst.txt @@ -0,0 +1,21 @@ +models.node.processing.feature\_extractor package +================================================= + +Submodules +---------- + +models.node.processing.feature\_extractor.feature\_extractor module +------------------------------------------------------------------- + +.. automodule:: models.node.processing.feature_extractor.feature_extractor + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.processing.feature_extractor + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.processing.filter.rst.txt b/_sources/models.node.processing.filter.rst.txt new file mode 100644 index 0000000..df36a11 --- /dev/null +++ b/_sources/models.node.processing.filter.rst.txt @@ -0,0 +1,29 @@ +models.node.processing.filter package +===================================== + +Submodules +---------- + +models.node.processing.filter.bandpass module +--------------------------------------------- + +.. automodule:: models.node.processing.filter.bandpass + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.filter.filter module +------------------------------------------- + +.. automodule:: models.node.processing.filter.filter + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.processing.filter + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.processing.rst.txt b/_sources/models.node.processing.rst.txt new file mode 100644 index 0000000..f9fd82f --- /dev/null +++ b/_sources/models.node.processing.rst.txt @@ -0,0 +1,65 @@ +models.node.processing package +============================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + models.node.processing.encoder + models.node.processing.feature_extractor + models.node.processing.filter + models.node.processing.segmenter + models.node.processing.trainable + +Submodules +---------- + +models.node.processing.fill module +---------------------------------- + +.. automodule:: models.node.processing.fill + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.merge module +----------------------------------- + +.. automodule:: models.node.processing.merge + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.processing\_node module +---------------------------------------------- + +.. automodule:: models.node.processing.processing_node + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.signalcheck module +----------------------------------------- + +.. automodule:: models.node.processing.signalcheck + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.synchronize module +----------------------------------------- + +.. automodule:: models.node.processing.synchronize + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.processing + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.processing.segmenter.rst.txt b/_sources/models.node.processing.segmenter.rst.txt new file mode 100644 index 0000000..1428831 --- /dev/null +++ b/_sources/models.node.processing.segmenter.rst.txt @@ -0,0 +1,29 @@ +models.node.processing.segmenter package +======================================== + +Submodules +---------- + +models.node.processing.segmenter.fixedwindowsegmenter module +------------------------------------------------------------ + +.. automodule:: models.node.processing.segmenter.fixedwindowsegmenter + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.segmenter.segmenter module +------------------------------------------------- + +.. automodule:: models.node.processing.segmenter.segmenter + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.processing.segmenter + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.processing.trainable.classifier.rst.txt b/_sources/models.node.processing.trainable.classifier.rst.txt new file mode 100644 index 0000000..392cb6c --- /dev/null +++ b/_sources/models.node.processing.trainable.classifier.rst.txt @@ -0,0 +1,29 @@ +models.node.processing.trainable.classifier package +=================================================== + +Submodules +---------- + +models.node.processing.trainable.classifier.lda module +------------------------------------------------------ + +.. automodule:: models.node.processing.trainable.classifier.lda + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.trainable.classifier.sklearn\_classifier module +---------------------------------------------------------------------- + +.. automodule:: models.node.processing.trainable.classifier.sklearn_classifier + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.processing.trainable.classifier + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.processing.trainable.feature_extractor.rst.txt b/_sources/models.node.processing.trainable.feature_extractor.rst.txt new file mode 100644 index 0000000..9888132 --- /dev/null +++ b/_sources/models.node.processing.trainable.feature_extractor.rst.txt @@ -0,0 +1,29 @@ +models.node.processing.trainable.feature\_extractor package +=========================================================== + +Submodules +---------- + +models.node.processing.trainable.feature\_extractor.csp module +-------------------------------------------------------------- + +.. automodule:: models.node.processing.trainable.feature_extractor.csp + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.trainable.feature\_extractor.sklearn\_feature\_extractor module +-------------------------------------------------------------------------------------- + +.. automodule:: models.node.processing.trainable.feature_extractor.sklearn_feature_extractor + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.processing.trainable.feature_extractor + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.processing.trainable.rst.txt b/_sources/models.node.processing.trainable.rst.txt new file mode 100644 index 0000000..14492ce --- /dev/null +++ b/_sources/models.node.processing.trainable.rst.txt @@ -0,0 +1,38 @@ +models.node.processing.trainable package +======================================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + models.node.processing.trainable.classifier + models.node.processing.trainable.feature_extractor + +Submodules +---------- + +models.node.processing.trainable.sklearn\_compatible\_trainable\_node module +---------------------------------------------------------------------------- + +.. automodule:: models.node.processing.trainable.sklearn_compatible_trainable_node + :members: + :undoc-members: + :show-inheritance: + +models.node.processing.trainable.trainable\_processing\_node module +------------------------------------------------------------------- + +.. automodule:: models.node.processing.trainable.trainable_processing_node + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node.processing.trainable + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.node.rst.txt b/_sources/models.node.rst.txt new file mode 100644 index 0000000..4477615 --- /dev/null +++ b/_sources/models.node.rst.txt @@ -0,0 +1,31 @@ +models.node package +=================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + models.node.generator + models.node.output + models.node.processing + +Submodules +---------- + +models.node.node module +----------------------- + +.. automodule:: models.node.node + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.node + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.rst.txt b/_sources/models.rst.txt new file mode 100644 index 0000000..bf07f06 --- /dev/null +++ b/_sources/models.rst.txt @@ -0,0 +1,31 @@ +models package +============== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + models.exception + models.node + models.utils + +Submodules +---------- + +framework\_data module +----------------------------- + +.. automodule:: models.framework_data + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/models.utils.rst.txt b/_sources/models.utils.rst.txt new file mode 100644 index 0000000..a7fe5e5 --- /dev/null +++ b/_sources/models.utils.rst.txt @@ -0,0 +1,45 @@ +models.utils package +==================== + +Submodules +---------- + +models.utils.cue module +----------------------- + +.. automodule:: models.utils.cue + :members: + :undoc-members: + :show-inheritance: + +models.utils.duration module +---------------------------- + +.. automodule:: models.utils.duration + :members: + :undoc-members: + :show-inheritance: + +models.utils.script\_execution module +------------------------------------- + +.. automodule:: models.utils.script_execution + :members: + :undoc-members: + :show-inheritance: + +models.utils.trial module +------------------------- + +.. automodule:: models.utils.trial + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: models.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/modules.rst.txt b/_sources/modules.rst.txt new file mode 100644 index 0000000..61ce791 --- /dev/null +++ b/_sources/modules.rst.txt @@ -0,0 +1,9 @@ +OpenBCI_Python_Framework +======================== + +.. toctree:: + :maxdepth: 4 + + application + main + models diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..7577acb --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,903 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/debug.css b/_static/debug.css new file mode 100644 index 0000000..74d4aec --- /dev/null +++ b/_static/debug.css @@ -0,0 +1,69 @@ +/* + This CSS file should be overridden by the theme authors. It's + meant for debugging and developing the skeleton that this theme provides. +*/ +body { + font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; + background: lavender; +} +.sb-announcement { + background: rgb(131, 131, 131); +} +.sb-announcement__inner { + background: black; + color: white; +} +.sb-header { + background: lightskyblue; +} +.sb-header__inner { + background: royalblue; + color: white; +} +.sb-header-secondary { + background: lightcyan; +} +.sb-header-secondary__inner { + background: cornflowerblue; + color: white; +} +.sb-sidebar-primary { + background: lightgreen; +} +.sb-main { + background: blanchedalmond; +} +.sb-main__inner { + background: antiquewhite; +} +.sb-header-article { + background: lightsteelblue; +} +.sb-article-container { + background: snow; +} +.sb-article-main { + background: white; +} +.sb-footer-article { + background: lightpink; +} +.sb-sidebar-secondary { + background: lightgoldenrodyellow; +} +.sb-footer-content { + background: plum; +} +.sb-footer-content__inner { + background: palevioletred; +} +.sb-footer { + background: pink; +} +.sb-footer__inner { + background: salmon; +} +.sb-article { + background: white; +} diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..d06a71d --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..ac431ff --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '0.0.1', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 0000000..250f566 --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 0000000..02b4b12 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,258 @@ +.highlight pre { line-height: 125%; } +.highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #204a87; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #000000; font-style: italic } /* Generic.Output */ +.highlight .gp { color: #8f5902 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #204a87 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8 } /* Text.Whitespace */ +.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */ +.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */ +.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */ +.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */ +.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */ +@media not print { +body[data-theme="dark"] .highlight pre { line-height: 125%; } +body[data-theme="dark"] .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight .hll { background-color: #404040 } +body[data-theme="dark"] .highlight { background: #202020; color: #d0d0d0 } +body[data-theme="dark"] .highlight .c { color: #ababab; font-style: italic } /* Comment */ +body[data-theme="dark"] .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +body[data-theme="dark"] .highlight .esc { color: #d0d0d0 } /* Escape */ +body[data-theme="dark"] .highlight .g { color: #d0d0d0 } /* Generic */ +body[data-theme="dark"] .highlight .k { color: #6ebf26; font-weight: bold } /* Keyword */ +body[data-theme="dark"] .highlight .l { color: #d0d0d0 } /* Literal */ +body[data-theme="dark"] .highlight .n { color: #d0d0d0 } /* Name */ +body[data-theme="dark"] .highlight .o { color: #d0d0d0 } /* Operator */ +body[data-theme="dark"] .highlight .x { color: #d0d0d0 } /* Other */ +body[data-theme="dark"] .highlight .p { color: #d0d0d0 } /* Punctuation */ +body[data-theme="dark"] .highlight .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */ +body[data-theme="dark"] .highlight .cm { color: #ababab; font-style: italic } /* Comment.Multiline */ +body[data-theme="dark"] .highlight .cp { color: #ff3a3a; font-weight: bold } /* Comment.Preproc */ +body[data-theme="dark"] .highlight .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */ +body[data-theme="dark"] .highlight .c1 { color: #ababab; font-style: italic } /* Comment.Single */ +body[data-theme="dark"] .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body[data-theme="dark"] .highlight .gd { color: #ff3a3a } /* Generic.Deleted */ +body[data-theme="dark"] .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +body[data-theme="dark"] .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body[data-theme="dark"] .highlight .gr { color: #ff3a3a } /* Generic.Error */ +body[data-theme="dark"] .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +body[data-theme="dark"] .highlight .gi { color: #589819 } /* Generic.Inserted */ +body[data-theme="dark"] .highlight .go { color: #cccccc } /* Generic.Output */ +body[data-theme="dark"] .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +body[data-theme="dark"] .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +body[data-theme="dark"] .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +body[data-theme="dark"] .highlight .gt { color: #ff3a3a } /* Generic.Traceback */ +body[data-theme="dark"] .highlight .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */ +body[data-theme="dark"] .highlight .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */ +body[data-theme="dark"] .highlight .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */ +body[data-theme="dark"] .highlight .kp { color: #6ebf26 } /* Keyword.Pseudo */ +body[data-theme="dark"] .highlight .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */ +body[data-theme="dark"] .highlight .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */ +body[data-theme="dark"] .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +body[data-theme="dark"] .highlight .m { color: #51b2fd } /* Literal.Number */ +body[data-theme="dark"] .highlight .s { color: #ed9d13 } /* Literal.String */ +body[data-theme="dark"] .highlight .na { color: #bbbbbb } /* Name.Attribute */ +body[data-theme="dark"] .highlight .nb { color: #2fbccd } /* Name.Builtin */ +body[data-theme="dark"] .highlight .nc { color: #71adff; text-decoration: underline } /* Name.Class */ +body[data-theme="dark"] .highlight .no { color: #40ffff } /* Name.Constant */ +body[data-theme="dark"] .highlight .nd { color: #ffa500 } /* Name.Decorator */ +body[data-theme="dark"] .highlight .ni { color: #d0d0d0 } /* Name.Entity */ +body[data-theme="dark"] .highlight .ne { color: #bbbbbb } /* Name.Exception */ +body[data-theme="dark"] .highlight .nf { color: #71adff } /* Name.Function */ +body[data-theme="dark"] .highlight .nl { color: #d0d0d0 } /* Name.Label */ +body[data-theme="dark"] .highlight .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */ +body[data-theme="dark"] .highlight .nx { color: #d0d0d0 } /* Name.Other */ +body[data-theme="dark"] .highlight .py { color: #d0d0d0 } /* Name.Property */ +body[data-theme="dark"] .highlight .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */ +body[data-theme="dark"] .highlight .nv { color: #40ffff } /* Name.Variable */ +body[data-theme="dark"] .highlight .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */ +body[data-theme="dark"] .highlight .pm { color: #d0d0d0 } /* Punctuation.Marker */ +body[data-theme="dark"] .highlight .w { color: #666666 } /* Text.Whitespace */ +body[data-theme="dark"] .highlight .mb { color: #51b2fd } /* Literal.Number.Bin */ +body[data-theme="dark"] .highlight .mf { color: #51b2fd } /* Literal.Number.Float */ +body[data-theme="dark"] .highlight .mh { color: #51b2fd } /* Literal.Number.Hex */ +body[data-theme="dark"] .highlight .mi { color: #51b2fd } /* Literal.Number.Integer */ +body[data-theme="dark"] .highlight .mo { color: #51b2fd } /* Literal.Number.Oct */ +body[data-theme="dark"] .highlight .sa { color: #ed9d13 } /* Literal.String.Affix */ +body[data-theme="dark"] .highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +body[data-theme="dark"] .highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +body[data-theme="dark"] .highlight .dl { color: #ed9d13 } /* Literal.String.Delimiter */ +body[data-theme="dark"] .highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +body[data-theme="dark"] .highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +body[data-theme="dark"] .highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +body[data-theme="dark"] .highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +body[data-theme="dark"] .highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +body[data-theme="dark"] .highlight .sx { color: #ffa500 } /* Literal.String.Other */ +body[data-theme="dark"] .highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +body[data-theme="dark"] .highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +body[data-theme="dark"] .highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +body[data-theme="dark"] .highlight .bp { color: #2fbccd } /* Name.Builtin.Pseudo */ +body[data-theme="dark"] .highlight .fm { color: #71adff } /* Name.Function.Magic */ +body[data-theme="dark"] .highlight .vc { color: #40ffff } /* Name.Variable.Class */ +body[data-theme="dark"] .highlight .vg { color: #40ffff } /* Name.Variable.Global */ +body[data-theme="dark"] .highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +body[data-theme="dark"] .highlight .vm { color: #40ffff } /* Name.Variable.Magic */ +body[data-theme="dark"] .highlight .il { color: #51b2fd } /* Literal.Number.Integer.Long */ +@media (prefers-color-scheme: dark) { +body:not([data-theme="light"]) .highlight pre { line-height: 125%; } +body:not([data-theme="light"]) .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight .hll { background-color: #404040 } +body:not([data-theme="light"]) .highlight { background: #202020; color: #d0d0d0 } +body:not([data-theme="light"]) .highlight .c { color: #ababab; font-style: italic } /* Comment */ +body:not([data-theme="light"]) .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +body:not([data-theme="light"]) .highlight .esc { color: #d0d0d0 } /* Escape */ +body:not([data-theme="light"]) .highlight .g { color: #d0d0d0 } /* Generic */ +body:not([data-theme="light"]) .highlight .k { color: #6ebf26; font-weight: bold } /* Keyword */ +body:not([data-theme="light"]) .highlight .l { color: #d0d0d0 } /* Literal */ +body:not([data-theme="light"]) .highlight .n { color: #d0d0d0 } /* Name */ +body:not([data-theme="light"]) .highlight .o { color: #d0d0d0 } /* Operator */ +body:not([data-theme="light"]) .highlight .x { color: #d0d0d0 } /* Other */ +body:not([data-theme="light"]) .highlight .p { color: #d0d0d0 } /* Punctuation */ +body:not([data-theme="light"]) .highlight .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */ +body:not([data-theme="light"]) .highlight .cm { color: #ababab; font-style: italic } /* Comment.Multiline */ +body:not([data-theme="light"]) .highlight .cp { color: #ff3a3a; font-weight: bold } /* Comment.Preproc */ +body:not([data-theme="light"]) .highlight .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */ +body:not([data-theme="light"]) .highlight .c1 { color: #ababab; font-style: italic } /* Comment.Single */ +body:not([data-theme="light"]) .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body:not([data-theme="light"]) .highlight .gd { color: #ff3a3a } /* Generic.Deleted */ +body:not([data-theme="light"]) .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +body:not([data-theme="light"]) .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body:not([data-theme="light"]) .highlight .gr { color: #ff3a3a } /* Generic.Error */ +body:not([data-theme="light"]) .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +body:not([data-theme="light"]) .highlight .gi { color: #589819 } /* Generic.Inserted */ +body:not([data-theme="light"]) .highlight .go { color: #cccccc } /* Generic.Output */ +body:not([data-theme="light"]) .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +body:not([data-theme="light"]) .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +body:not([data-theme="light"]) .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +body:not([data-theme="light"]) .highlight .gt { color: #ff3a3a } /* Generic.Traceback */ +body:not([data-theme="light"]) .highlight .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */ +body:not([data-theme="light"]) .highlight .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */ +body:not([data-theme="light"]) .highlight .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */ +body:not([data-theme="light"]) .highlight .kp { color: #6ebf26 } /* Keyword.Pseudo */ +body:not([data-theme="light"]) .highlight .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */ +body:not([data-theme="light"]) .highlight .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */ +body:not([data-theme="light"]) .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +body:not([data-theme="light"]) .highlight .m { color: #51b2fd } /* Literal.Number */ +body:not([data-theme="light"]) .highlight .s { color: #ed9d13 } /* Literal.String */ +body:not([data-theme="light"]) .highlight .na { color: #bbbbbb } /* Name.Attribute */ +body:not([data-theme="light"]) .highlight .nb { color: #2fbccd } /* Name.Builtin */ +body:not([data-theme="light"]) .highlight .nc { color: #71adff; text-decoration: underline } /* Name.Class */ +body:not([data-theme="light"]) .highlight .no { color: #40ffff } /* Name.Constant */ +body:not([data-theme="light"]) .highlight .nd { color: #ffa500 } /* Name.Decorator */ +body:not([data-theme="light"]) .highlight .ni { color: #d0d0d0 } /* Name.Entity */ +body:not([data-theme="light"]) .highlight .ne { color: #bbbbbb } /* Name.Exception */ +body:not([data-theme="light"]) .highlight .nf { color: #71adff } /* Name.Function */ +body:not([data-theme="light"]) .highlight .nl { color: #d0d0d0 } /* Name.Label */ +body:not([data-theme="light"]) .highlight .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */ +body:not([data-theme="light"]) .highlight .nx { color: #d0d0d0 } /* Name.Other */ +body:not([data-theme="light"]) .highlight .py { color: #d0d0d0 } /* Name.Property */ +body:not([data-theme="light"]) .highlight .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */ +body:not([data-theme="light"]) .highlight .nv { color: #40ffff } /* Name.Variable */ +body:not([data-theme="light"]) .highlight .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */ +body:not([data-theme="light"]) .highlight .pm { color: #d0d0d0 } /* Punctuation.Marker */ +body:not([data-theme="light"]) .highlight .w { color: #666666 } /* Text.Whitespace */ +body:not([data-theme="light"]) .highlight .mb { color: #51b2fd } /* Literal.Number.Bin */ +body:not([data-theme="light"]) .highlight .mf { color: #51b2fd } /* Literal.Number.Float */ +body:not([data-theme="light"]) .highlight .mh { color: #51b2fd } /* Literal.Number.Hex */ +body:not([data-theme="light"]) .highlight .mi { color: #51b2fd } /* Literal.Number.Integer */ +body:not([data-theme="light"]) .highlight .mo { color: #51b2fd } /* Literal.Number.Oct */ +body:not([data-theme="light"]) .highlight .sa { color: #ed9d13 } /* Literal.String.Affix */ +body:not([data-theme="light"]) .highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +body:not([data-theme="light"]) .highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +body:not([data-theme="light"]) .highlight .dl { color: #ed9d13 } /* Literal.String.Delimiter */ +body:not([data-theme="light"]) .highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +body:not([data-theme="light"]) .highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +body:not([data-theme="light"]) .highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +body:not([data-theme="light"]) .highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +body:not([data-theme="light"]) .highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +body:not([data-theme="light"]) .highlight .sx { color: #ffa500 } /* Literal.String.Other */ +body:not([data-theme="light"]) .highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +body:not([data-theme="light"]) .highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +body:not([data-theme="light"]) .highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +body:not([data-theme="light"]) .highlight .bp { color: #2fbccd } /* Name.Builtin.Pseudo */ +body:not([data-theme="light"]) .highlight .fm { color: #71adff } /* Name.Function.Magic */ +body:not([data-theme="light"]) .highlight .vc { color: #40ffff } /* Name.Variable.Class */ +body:not([data-theme="light"]) .highlight .vg { color: #40ffff } /* Name.Variable.Global */ +body:not([data-theme="light"]) .highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +body:not([data-theme="light"]) .highlight .vm { color: #40ffff } /* Name.Variable.Magic */ +body:not([data-theme="light"]) .highlight .il { color: #51b2fd } /* Literal.Number.Integer.Long */ +} +} \ No newline at end of file diff --git a/_static/scripts/furo-extensions.js b/_static/scripts/furo-extensions.js new file mode 100644 index 0000000..e69de29 diff --git a/_static/scripts/furo.js b/_static/scripts/furo.js new file mode 100644 index 0000000..cbf6487 --- /dev/null +++ b/_static/scripts/furo.js @@ -0,0 +1,3 @@ +/*! For license information please see furo.js.LICENSE.txt */ +(()=>{var t={212:function(t,e,n){var o,r;r=void 0!==n.g?n.g:"undefined"!=typeof window?window:this,o=function(){return function(t){"use strict";var e={navClass:"active",contentClass:"active",nested:!1,nestedClass:"active",offset:0,reflow:!1,events:!0},n=function(t,e,n){if(n.settings.events){var o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o)}},o=function(t){var e=0;if(t.offsetParent)for(;t;)e+=t.offsetTop,t=t.offsetParent;return e>=0?e:0},r=function(t){t&&t.sort((function(t,e){return o(t.content)=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.body.clientHeight,document.documentElement.clientHeight)},l=function(t,e){var n=t[t.length-1];if(function(t,e){return!(!s()||!c(t.content,e,!0))}(n,e))return n;for(var o=t.length-1;o>=0;o--)if(c(t[o].content,e))return t[o]},a=function(t,e){if(e.nested&&t.parentNode){var n=t.parentNode.closest("li");n&&(n.classList.remove(e.nestedClass),a(n,e))}},i=function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.remove(e.navClass),t.content.classList.remove(e.contentClass),a(o,e),n("gumshoeDeactivate",o,{link:t.nav,content:t.content,settings:e}))}},u=function(t,e){if(e.nested){var n=t.parentNode.closest("li");n&&(n.classList.add(e.nestedClass),u(n,e))}};return function(o,c){var s,a,d,f,m,v={setup:function(){s=document.querySelectorAll(o),a=[],Array.prototype.forEach.call(s,(function(t){var e=document.getElementById(decodeURIComponent(t.hash.substr(1)));e&&a.push({nav:t,content:e})})),r(a)},detect:function(){var t=l(a,m);t?d&&t.content===d.content||(i(d,m),function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.add(e.navClass),t.content.classList.add(e.contentClass),u(o,e),n("gumshoeActivate",o,{link:t.nav,content:t.content,settings:e}))}}(t,m),d=t):d&&(i(d,m),d=null)}},h=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame(v.detect)},g=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame((function(){r(a),v.detect()}))};return v.destroy=function(){d&&i(d,m),t.removeEventListener("scroll",h,!1),m.reflow&&t.removeEventListener("resize",g,!1),a=null,s=null,d=null,f=null,m=null},m=function(){var t={};return Array.prototype.forEach.call(arguments,(function(e){for(var n in e){if(!e.hasOwnProperty(n))return;t[n]=e[n]}})),t}(e,c||{}),v.setup(),v.detect(),t.addEventListener("scroll",h,!1),m.reflow&&t.addEventListener("resize",g,!1),v}}(r)}.apply(e,[]),void 0===o||(t.exports=o)}},e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o].call(c.exports,c,c.exports,n),c.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=n(212),e=n.n(t),o=null,r=null,c=window.pageYOffset||document.documentElement.scrollTop;function s(){const t=localStorage.getItem("theme")||"auto";var e;"light"!==(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"auto"===t?"light":"light"==t?"dark":"auto":"auto"===t?"dark":"dark"==t?"light":"auto")&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto"),document.body.dataset.theme=e,localStorage.setItem("theme",e),console.log(`Changed to ${e} mode.`)}function l(){!function(){const t=document.getElementsByClassName("theme-toggle");Array.from(t).forEach((t=>{t.addEventListener("click",s)}))}(),function(){let t=0,e=!1;window.addEventListener("scroll",(function(n){t=window.scrollY,e||(window.requestAnimationFrame((function(){var n;n=t,0==Math.floor(r.getBoundingClientRect().top)?r.classList.add("scrolled"):r.classList.remove("scrolled"),function(t){t<64?document.documentElement.classList.remove("show-back-to-top"):tc&&document.documentElement.classList.remove("show-back-to-top"),c=t}(n),function(t){null!==o&&(0==t?o.scrollTo(0,0):Math.ceil(t)>=Math.floor(document.documentElement.scrollHeight-window.innerHeight)?o.scrollTo(0,o.scrollHeight):document.querySelector(".scroll-current"))}(n),e=!1})),e=!0)})),window.scroll()}(),null!==o&&new(e())(".toc-tree a",{reflow:!0,recursive:!0,navClass:"scroll-current",offset:()=>{let t=parseFloat(getComputedStyle(document.documentElement).fontSize);return r.getBoundingClientRect().height+.5*t+1}})}document.addEventListener("DOMContentLoaded",(function(){document.body.parentNode.classList.remove("no-js"),r=document.querySelector("header"),o=document.querySelector(".toc-scroll"),l()}))})()})(); +//# sourceMappingURL=furo.js.map \ No newline at end of file diff --git a/_static/scripts/furo.js.LICENSE.txt b/_static/scripts/furo.js.LICENSE.txt new file mode 100644 index 0000000..1632189 --- /dev/null +++ b/_static/scripts/furo.js.LICENSE.txt @@ -0,0 +1,7 @@ +/*! + * gumshoejs v5.1.2 (patched by @pradyunsg) + * A simple, framework-agnostic scrollspy script. + * (c) 2019 Chris Ferdinandi + * MIT License + * http://github.com/cferdinandi/gumshoe + */ diff --git a/_static/scripts/furo.js.map b/_static/scripts/furo.js.map new file mode 100644 index 0000000..7ed2be8 --- /dev/null +++ b/_static/scripts/furo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"scripts/furo.js","mappings":"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","sources":["webpack:///./src/furo/assets/scripts/gumshoe-patched.js","webpack:///webpack/bootstrap","webpack:///webpack/runtime/compat get default export","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/global","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///./src/furo/assets/scripts/furo.js"],"sourcesContent":["/*!\n * gumshoejs v5.1.2 (patched by @pradyunsg)\n * A simple, framework-agnostic scrollspy script.\n * (c) 2019 Chris Ferdinandi\n * MIT License\n * http://github.com/cferdinandi/gumshoe\n */\n\n(function (root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define([], function () {\n return factory(root);\n });\n } else if (typeof exports === \"object\") {\n module.exports = factory(root);\n } else {\n root.Gumshoe = factory(root);\n }\n})(\n typeof global !== \"undefined\"\n ? global\n : typeof window !== \"undefined\"\n ? window\n : this,\n function (window) {\n \"use strict\";\n\n //\n // Defaults\n //\n\n var defaults = {\n // Active classes\n navClass: \"active\",\n contentClass: \"active\",\n\n // Nested navigation\n nested: false,\n nestedClass: \"active\",\n\n // Offset & reflow\n offset: 0,\n reflow: false,\n\n // Event support\n events: true,\n };\n\n //\n // Methods\n //\n\n /**\n * Merge two or more objects together.\n * @param {Object} objects The objects to merge together\n * @returns {Object} Merged values of defaults and options\n */\n var extend = function () {\n var merged = {};\n Array.prototype.forEach.call(arguments, function (obj) {\n for (var key in obj) {\n if (!obj.hasOwnProperty(key)) return;\n merged[key] = obj[key];\n }\n });\n return merged;\n };\n\n /**\n * Emit a custom event\n * @param {String} type The event type\n * @param {Node} elem The element to attach the event to\n * @param {Object} detail Any details to pass along with the event\n */\n var emitEvent = function (type, elem, detail) {\n // Make sure events are enabled\n if (!detail.settings.events) return;\n\n // Create a new event\n var event = new CustomEvent(type, {\n bubbles: true,\n cancelable: true,\n detail: detail,\n });\n\n // Dispatch the event\n elem.dispatchEvent(event);\n };\n\n /**\n * Get an element's distance from the top of the Document.\n * @param {Node} elem The element\n * @return {Number} Distance from the top in pixels\n */\n var getOffsetTop = function (elem) {\n var location = 0;\n if (elem.offsetParent) {\n while (elem) {\n location += elem.offsetTop;\n elem = elem.offsetParent;\n }\n }\n return location >= 0 ? location : 0;\n };\n\n /**\n * Sort content from first to last in the DOM\n * @param {Array} contents The content areas\n */\n var sortContents = function (contents) {\n if (contents) {\n contents.sort(function (item1, item2) {\n var offset1 = getOffsetTop(item1.content);\n var offset2 = getOffsetTop(item2.content);\n if (offset1 < offset2) return -1;\n return 1;\n });\n }\n };\n\n /**\n * Get the offset to use for calculating position\n * @param {Object} settings The settings for this instantiation\n * @return {Float} The number of pixels to offset the calculations\n */\n var getOffset = function (settings) {\n // if the offset is a function run it\n if (typeof settings.offset === \"function\") {\n return parseFloat(settings.offset());\n }\n\n // Otherwise, return it as-is\n return parseFloat(settings.offset);\n };\n\n /**\n * Get the document element's height\n * @private\n * @returns {Number}\n */\n var getDocumentHeight = function () {\n return Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight,\n document.body.clientHeight,\n document.documentElement.clientHeight,\n );\n };\n\n /**\n * Determine if an element is in view\n * @param {Node} elem The element\n * @param {Object} settings The settings for this instantiation\n * @param {Boolean} bottom If true, check if element is above bottom of viewport instead\n * @return {Boolean} Returns true if element is in the viewport\n */\n var isInView = function (elem, settings, bottom) {\n var bounds = elem.getBoundingClientRect();\n var offset = getOffset(settings);\n if (bottom) {\n return (\n parseInt(bounds.bottom, 10) <\n (window.innerHeight || document.documentElement.clientHeight)\n );\n }\n return parseInt(bounds.top, 10) <= offset;\n };\n\n /**\n * Check if at the bottom of the viewport\n * @return {Boolean} If true, page is at the bottom of the viewport\n */\n var isAtBottom = function () {\n if (\n Math.ceil(window.innerHeight + window.pageYOffset) >=\n getDocumentHeight()\n )\n return true;\n return false;\n };\n\n /**\n * Check if the last item should be used (even if not at the top of the page)\n * @param {Object} item The last item\n * @param {Object} settings The settings for this instantiation\n * @return {Boolean} If true, use the last item\n */\n var useLastItem = function (item, settings) {\n if (isAtBottom() && isInView(item.content, settings, true)) return true;\n return false;\n };\n\n /**\n * Get the active content\n * @param {Array} contents The content areas\n * @param {Object} settings The settings for this instantiation\n * @return {Object} The content area and matching navigation link\n */\n var getActive = function (contents, settings) {\n var last = contents[contents.length - 1];\n if (useLastItem(last, settings)) return last;\n for (var i = contents.length - 1; i >= 0; i--) {\n if (isInView(contents[i].content, settings)) return contents[i];\n }\n };\n\n /**\n * Deactivate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var deactivateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested || !nav.parentNode) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Remove the active class\n li.classList.remove(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n deactivateNested(li, settings);\n };\n\n /**\n * Deactivate a nav and content area\n * @param {Object} items The nav item and content to deactivate\n * @param {Object} settings The settings for this instantiation\n */\n var deactivate = function (items, settings) {\n // Make sure there are items to deactivate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Remove the active class from the nav and content\n li.classList.remove(settings.navClass);\n items.content.classList.remove(settings.contentClass);\n\n // Deactivate any parent navs in a nested navigation\n deactivateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeDeactivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Activate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var activateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Add the active class\n li.classList.add(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n activateNested(li, settings);\n };\n\n /**\n * Activate a nav and content area\n * @param {Object} items The nav item and content to activate\n * @param {Object} settings The settings for this instantiation\n */\n var activate = function (items, settings) {\n // Make sure there are items to activate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Add the active class to the nav and content\n li.classList.add(settings.navClass);\n items.content.classList.add(settings.contentClass);\n\n // Activate any parent navs in a nested navigation\n activateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeActivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Create the Constructor object\n * @param {String} selector The selector to use for navigation items\n * @param {Object} options User options and settings\n */\n var Constructor = function (selector, options) {\n //\n // Variables\n //\n\n var publicAPIs = {};\n var navItems, contents, current, timeout, settings;\n\n //\n // Methods\n //\n\n /**\n * Set variables from DOM elements\n */\n publicAPIs.setup = function () {\n // Get all nav items\n navItems = document.querySelectorAll(selector);\n\n // Create contents array\n contents = [];\n\n // Loop through each item, get it's matching content, and push to the array\n Array.prototype.forEach.call(navItems, function (item) {\n // Get the content for the nav item\n var content = document.getElementById(\n decodeURIComponent(item.hash.substr(1)),\n );\n if (!content) return;\n\n // Push to the contents array\n contents.push({\n nav: item,\n content: content,\n });\n });\n\n // Sort contents by the order they appear in the DOM\n sortContents(contents);\n };\n\n /**\n * Detect which content is currently active\n */\n publicAPIs.detect = function () {\n // Get the active content\n var active = getActive(contents, settings);\n\n // if there's no active content, deactivate and bail\n if (!active) {\n if (current) {\n deactivate(current, settings);\n current = null;\n }\n return;\n }\n\n // If the active content is the one currently active, do nothing\n if (current && active.content === current.content) return;\n\n // Deactivate the current content and activate the new content\n deactivate(current, settings);\n activate(active, settings);\n\n // Update the currently active content\n current = active;\n };\n\n /**\n * Detect the active content on scroll\n * Debounced for performance\n */\n var scrollHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(publicAPIs.detect);\n };\n\n /**\n * Update content sorting on resize\n * Debounced for performance\n */\n var resizeHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(function () {\n sortContents(contents);\n publicAPIs.detect();\n });\n };\n\n /**\n * Destroy the current instantiation\n */\n publicAPIs.destroy = function () {\n // Undo DOM changes\n if (current) {\n deactivate(current, settings);\n }\n\n // Remove event listeners\n window.removeEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.removeEventListener(\"resize\", resizeHandler, false);\n }\n\n // Reset variables\n contents = null;\n navItems = null;\n current = null;\n timeout = null;\n settings = null;\n };\n\n /**\n * Initialize the current instantiation\n */\n var init = function () {\n // Merge user options into defaults\n settings = extend(defaults, options || {});\n\n // Setup variables based on the current DOM\n publicAPIs.setup();\n\n // Find the currently active content\n publicAPIs.detect();\n\n // Setup event listeners\n window.addEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.addEventListener(\"resize\", resizeHandler, false);\n }\n };\n\n //\n // Initialize and return the public APIs\n //\n\n init();\n return publicAPIs;\n };\n\n //\n // Return the Constructor\n //\n\n return Constructor;\n },\n);\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import Gumshoe from \"./gumshoe-patched.js\";\n\n////////////////////////////////////////////////////////////////////////////////\n// Scroll Handling\n////////////////////////////////////////////////////////////////////////////////\nvar tocScroll = null;\nvar header = null;\nvar lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;\nconst GO_TO_TOP_OFFSET = 64;\n\nfunction scrollHandlerForHeader() {\n if (Math.floor(header.getBoundingClientRect().top) == 0) {\n header.classList.add(\"scrolled\");\n } else {\n header.classList.remove(\"scrolled\");\n }\n}\n\nfunction scrollHandlerForBackToTop(positionY) {\n if (positionY < GO_TO_TOP_OFFSET) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n } else {\n if (positionY < lastScrollTop) {\n document.documentElement.classList.add(\"show-back-to-top\");\n } else if (positionY > lastScrollTop) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n }\n }\n lastScrollTop = positionY;\n}\n\nfunction scrollHandlerForTOC(positionY) {\n if (tocScroll === null) {\n return;\n }\n\n // top of page.\n if (positionY == 0) {\n tocScroll.scrollTo(0, 0);\n } else if (\n // bottom of page.\n Math.ceil(positionY) >=\n Math.floor(document.documentElement.scrollHeight - window.innerHeight)\n ) {\n tocScroll.scrollTo(0, tocScroll.scrollHeight);\n } else {\n // somewhere in the middle.\n const current = document.querySelector(\".scroll-current\");\n if (current == null) {\n return;\n }\n\n // https://github.com/pypa/pip/issues/9159 This breaks scroll behaviours.\n // // scroll the currently \"active\" heading in toc, into view.\n // const rect = current.getBoundingClientRect();\n // if (0 > rect.top) {\n // current.scrollIntoView(true); // the argument is \"alignTop\"\n // } else if (rect.bottom > window.innerHeight) {\n // current.scrollIntoView(false);\n // }\n }\n}\n\nfunction scrollHandler(positionY) {\n scrollHandlerForHeader();\n scrollHandlerForBackToTop(positionY);\n scrollHandlerForTOC(positionY);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Theme Toggle\n////////////////////////////////////////////////////////////////////////////////\nfunction setTheme(mode) {\n if (mode !== \"light\" && mode !== \"dark\" && mode !== \"auto\") {\n console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);\n mode = \"auto\";\n }\n\n document.body.dataset.theme = mode;\n localStorage.setItem(\"theme\", mode);\n console.log(`Changed to ${mode} mode.`);\n}\n\nfunction cycleThemeOnce() {\n const currentTheme = localStorage.getItem(\"theme\") || \"auto\";\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\n if (prefersDark) {\n // Auto (dark) -> Light -> Dark\n if (currentTheme === \"auto\") {\n setTheme(\"light\");\n } else if (currentTheme == \"light\") {\n setTheme(\"dark\");\n } else {\n setTheme(\"auto\");\n }\n } else {\n // Auto (light) -> Dark -> Light\n if (currentTheme === \"auto\") {\n setTheme(\"dark\");\n } else if (currentTheme == \"dark\") {\n setTheme(\"light\");\n } else {\n setTheme(\"auto\");\n }\n }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Setup\n////////////////////////////////////////////////////////////////////////////////\nfunction setupScrollHandler() {\n // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event\n let last_known_scroll_position = 0;\n let ticking = false;\n\n window.addEventListener(\"scroll\", function (e) {\n last_known_scroll_position = window.scrollY;\n\n if (!ticking) {\n window.requestAnimationFrame(function () {\n scrollHandler(last_known_scroll_position);\n ticking = false;\n });\n\n ticking = true;\n }\n });\n window.scroll();\n}\n\nfunction setupScrollSpy() {\n if (tocScroll === null) {\n return;\n }\n\n // Scrollspy -- highlight table on contents, based on scroll\n new Gumshoe(\".toc-tree a\", {\n reflow: true,\n recursive: true,\n navClass: \"scroll-current\",\n offset: () => {\n let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return header.getBoundingClientRect().height + 0.5 * rem + 1;\n },\n });\n}\n\nfunction setupTheme() {\n // Attach event handlers for toggling themes\n const buttons = document.getElementsByClassName(\"theme-toggle\");\n Array.from(buttons).forEach((btn) => {\n btn.addEventListener(\"click\", cycleThemeOnce);\n });\n}\n\nfunction setup() {\n setupTheme();\n setupScrollHandler();\n setupScrollSpy();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Main entrypoint\n////////////////////////////////////////////////////////////////////////////////\nfunction main() {\n document.body.parentNode.classList.remove(\"no-js\");\n\n header = document.querySelector(\"header\");\n tocScroll = document.querySelector(\".toc-scroll\");\n\n setup();\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", main);\n"],"names":["root","g","window","this","defaults","navClass","contentClass","nested","nestedClass","offset","reflow","events","emitEvent","type","elem","detail","settings","event","CustomEvent","bubbles","cancelable","dispatchEvent","getOffsetTop","location","offsetParent","offsetTop","sortContents","contents","sort","item1","item2","content","isInView","bottom","bounds","getBoundingClientRect","parseFloat","getOffset","parseInt","innerHeight","document","documentElement","clientHeight","top","isAtBottom","Math","ceil","pageYOffset","max","body","scrollHeight","offsetHeight","getActive","last","length","item","useLastItem","i","deactivateNested","nav","parentNode","li","closest","classList","remove","deactivate","items","link","activateNested","add","selector","options","navItems","current","timeout","publicAPIs","querySelectorAll","Array","prototype","forEach","call","getElementById","decodeURIComponent","hash","substr","push","active","activate","scrollHandler","cancelAnimationFrame","requestAnimationFrame","detect","resizeHandler","destroy","removeEventListener","merged","arguments","obj","key","hasOwnProperty","extend","setup","addEventListener","factory","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","n","getter","__esModule","d","a","definition","o","Object","defineProperty","enumerable","get","globalThis","Function","e","prop","tocScroll","header","lastScrollTop","scrollTop","cycleThemeOnce","currentTheme","localStorage","getItem","mode","matchMedia","matches","console","error","dataset","theme","setItem","log","buttons","getElementsByClassName","from","btn","setupTheme","last_known_scroll_position","ticking","scrollY","positionY","floor","scrollHandlerForBackToTop","scrollTo","querySelector","scrollHandlerForTOC","scroll","setupScrollHandler","recursive","rem","getComputedStyle","fontSize","height"],"sourceRoot":""} \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 0000000..97d56a7 --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,566 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = docUrlRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = docUrlRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/skeleton.css b/_static/skeleton.css new file mode 100644 index 0000000..467c878 --- /dev/null +++ b/_static/skeleton.css @@ -0,0 +1,296 @@ +/* Some sane resets. */ +html { + height: 100%; +} + +body { + margin: 0; + min-height: 100%; +} + +/* All the flexbox magic! */ +body, +.sb-announcement, +.sb-content, +.sb-main, +.sb-container, +.sb-container__inner, +.sb-article-container, +.sb-footer-content, +.sb-header, +.sb-header-secondary, +.sb-footer { + display: flex; +} + +/* These order things vertically */ +body, +.sb-main, +.sb-article-container { + flex-direction: column; +} + +/* Put elements in the center */ +.sb-header, +.sb-header-secondary, +.sb-container, +.sb-content, +.sb-footer, +.sb-footer-content { + justify-content: center; +} +/* Put elements at the ends */ +.sb-article-container { + justify-content: space-between; +} + +/* These elements grow. */ +.sb-main, +.sb-content, +.sb-container, +article { + flex-grow: 1; +} + +/* Because padding making this wider is not fun */ +article { + box-sizing: border-box; +} + +/* The announcements element should never be wider than the page. */ +.sb-announcement { + max-width: 100%; +} + +.sb-sidebar-primary, +.sb-sidebar-secondary { + flex-shrink: 0; + width: 17rem; +} + +.sb-announcement__inner { + justify-content: center; + + box-sizing: border-box; + height: 3rem; + + overflow-x: auto; + white-space: nowrap; +} + +/* Sidebars, with checkbox-based toggle */ +.sb-sidebar-primary, +.sb-sidebar-secondary { + position: fixed; + height: 100%; + top: 0; +} + +.sb-sidebar-primary { + left: -17rem; + transition: left 250ms ease-in-out; +} +.sb-sidebar-secondary { + right: -17rem; + transition: right 250ms ease-in-out; +} + +.sb-sidebar-toggle { + display: none; +} +.sb-sidebar-overlay { + position: fixed; + top: 0; + width: 0; + height: 0; + + transition: width 0ms ease 250ms, height 0ms ease 250ms, opacity 250ms ease; + + opacity: 0; + background-color: rgba(0, 0, 0, 0.54); +} + +#sb-sidebar-toggle--primary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--primary"], +#sb-sidebar-toggle--secondary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--secondary"] { + width: 100%; + height: 100%; + opacity: 1; + transition: width 0ms ease, height 0ms ease, opacity 250ms ease; +} + +#sb-sidebar-toggle--primary:checked ~ .sb-container .sb-sidebar-primary { + left: 0; +} +#sb-sidebar-toggle--secondary:checked ~ .sb-container .sb-sidebar-secondary { + right: 0; +} + +/* Full-width mode */ +.drop-secondary-sidebar-for-full-width-content + .hide-when-secondary-sidebar-shown { + display: none !important; +} +.drop-secondary-sidebar-for-full-width-content .sb-sidebar-secondary { + display: none !important; +} + +/* Mobile views */ +.sb-page-width { + width: 100%; +} + +.sb-article-container, +.sb-footer-content__inner, +.drop-secondary-sidebar-for-full-width-content .sb-article, +.drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 100vw; +} + +.sb-article, +.match-content-width { + padding: 0 1rem; + box-sizing: border-box; +} + +@media (min-width: 32rem) { + .sb-article, + .match-content-width { + padding: 0 2rem; + } +} + +/* Tablet views */ +@media (min-width: 42rem) { + .sb-article-container { + width: auto; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 42rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 46rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 46rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 50rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 50rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Tablet views */ +@media (min-width: 59rem) { + .sb-sidebar-secondary { + position: static; + } + .hide-when-secondary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 63rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 67rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Desktop views */ +@media (min-width: 76rem) { + .sb-sidebar-primary { + position: static; + } + .hide-when-primary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} + +/* Full desktop views */ +@media (min-width: 80rem) { + .sb-article, + .match-content-width { + width: 46rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } +} + +@media (min-width: 84rem) { + .sb-article, + .match-content-width { + width: 50rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } +} + +@media (min-width: 88rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-page-width { + width: 88rem; + } +} diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 0000000..aae669d --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,144 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + parent.insertBefore( + span, + parent.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(SphinxHighlight.highlightSearchWords); +_ready(SphinxHighlight.initEscapeListener); diff --git a/_static/styles/furo-extensions.css b/_static/styles/furo-extensions.css new file mode 100644 index 0000000..bc447f2 --- /dev/null +++ b/_static/styles/furo-extensions.css @@ -0,0 +1,2 @@ +#furo-sidebar-ad-placement{padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)}#furo-sidebar-ad-placement .ethical-sidebar{background:var(--color-background-secondary);border:none;box-shadow:none}#furo-sidebar-ad-placement .ethical-sidebar:hover{background:var(--color-background-hover)}#furo-sidebar-ad-placement .ethical-sidebar a{color:var(--color-foreground-primary)}#furo-sidebar-ad-placement .ethical-callout a{color:var(--color-foreground-secondary)!important}#furo-readthedocs-versions{background:transparent;display:block;position:static;width:100%}#furo-readthedocs-versions .rst-versions{background:#1a1c1e}#furo-readthedocs-versions .rst-current-version{background:var(--color-sidebar-item-background);cursor:unset}#furo-readthedocs-versions .rst-current-version:hover{background:var(--color-sidebar-item-background)}#furo-readthedocs-versions .rst-current-version .fa-book{color:var(--color-foreground-primary)}#furo-readthedocs-versions>.rst-other-versions{padding:0}#furo-readthedocs-versions>.rst-other-versions small{opacity:1}#furo-readthedocs-versions .injected .rst-versions{position:unset}#furo-readthedocs-versions:focus-within,#furo-readthedocs-versions:hover{box-shadow:0 0 0 1px var(--color-sidebar-background-border)}#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:hover .rst-current-version{background:#1a1c1e;font-size:inherit;height:auto;line-height:inherit;padding:12px;text-align:right}#furo-readthedocs-versions:focus-within .rst-current-version .fa-book,#furo-readthedocs-versions:hover .rst-current-version .fa-book{color:#fff;float:left}#furo-readthedocs-versions:focus-within .fa-caret-down,#furo-readthedocs-versions:hover .fa-caret-down{display:none}#furo-readthedocs-versions:focus-within .injected,#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:focus-within .rst-other-versions,#furo-readthedocs-versions:hover .injected,#furo-readthedocs-versions:hover .rst-current-version,#furo-readthedocs-versions:hover .rst-other-versions{display:block}#furo-readthedocs-versions:focus-within>.rst-current-version,#furo-readthedocs-versions:hover>.rst-current-version{display:none}.highlight:hover button.copybtn{color:var(--color-code-foreground)}.highlight button.copybtn{align-items:center;background-color:var(--color-code-background);border:none;color:var(--color-background-item);cursor:pointer;height:1.25em;opacity:1;right:.5rem;top:.625rem;transition:color .3s,opacity .3s;width:1.25em}.highlight button.copybtn:hover{background-color:var(--color-code-background);color:var(--color-brand-content)}.highlight button.copybtn:after{background-color:transparent;color:var(--color-code-foreground);display:none}.highlight button.copybtn.success{color:#22863a;transition:color 0ms}.highlight button.copybtn.success:after{display:block}.highlight button.copybtn svg{padding:0}body{--sd-color-primary:var(--color-brand-primary);--sd-color-primary-highlight:var(--color-brand-content);--sd-color-primary-text:var(--color-background-primary);--sd-color-shadow:rgba(0,0,0,.05);--sd-color-card-border:var(--color-card-border);--sd-color-card-border-hover:var(--color-brand-content);--sd-color-card-background:var(--color-card-background);--sd-color-card-text:var(--color-foreground-primary);--sd-color-card-header:var(--color-card-marginals-background);--sd-color-card-footer:var(--color-card-marginals-background);--sd-color-tabs-label-active:var(--color-brand-content);--sd-color-tabs-label-hover:var(--color-foreground-muted);--sd-color-tabs-label-inactive:var(--color-foreground-muted);--sd-color-tabs-underline-active:var(--color-brand-content);--sd-color-tabs-underline-hover:var(--color-foreground-border);--sd-color-tabs-underline-inactive:var(--color-background-border);--sd-color-tabs-overline:var(--color-background-border);--sd-color-tabs-underline:var(--color-background-border)}.sd-tab-content{box-shadow:0 -2px var(--sd-color-tabs-overline),0 1px var(--sd-color-tabs-underline)}.sd-card{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)}.sd-shadow-sm{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-md{box-shadow:0 .3rem .75rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-lg{box-shadow:0 .6rem 1.5rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-card-hover:hover{transform:none}.sd-cards-carousel{gap:.25rem;padding:.25rem}body{--tabs--label-text:var(--color-foreground-muted);--tabs--label-text--hover:var(--color-foreground-muted);--tabs--label-text--active:var(--color-brand-content);--tabs--label-text--active--hover:var(--color-brand-content);--tabs--label-background:transparent;--tabs--label-background--hover:transparent;--tabs--label-background--active:transparent;--tabs--label-background--active--hover:transparent;--tabs--padding-x:0.25em;--tabs--margin-x:1em;--tabs--border:var(--color-background-border);--tabs--label-border:transparent;--tabs--label-border--hover:var(--color-foreground-muted);--tabs--label-border--active:var(--color-brand-content);--tabs--label-border--active--hover:var(--color-brand-content)}[role=main] .container{max-width:none;padding-left:0;padding-right:0}.shadow.docutils{border:none;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)!important}.sphinx-bs .card{background-color:var(--color-background-secondary);color:var(--color-foreground)} +/*# sourceMappingURL=furo-extensions.css.map*/ \ No newline at end of file diff --git a/_static/styles/furo-extensions.css.map b/_static/styles/furo-extensions.css.map new file mode 100644 index 0000000..9ba5637 --- /dev/null +++ b/_static/styles/furo-extensions.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo-extensions.css","mappings":"AAGA,2BACE,oFACA,4CAKE,6CAHA,YACA,eAEA,CACA,kDACE,yCAEF,8CACE,sCAEJ,8CACE,kDAEJ,2BAGE,uBACA,cAHA,gBACA,UAEA,CAGA,yCACE,mBAEF,gDAEE,gDADA,YACA,CACA,sDACE,gDACF,yDACE,sCAEJ,+CACE,UACA,qDACE,UAGF,mDACE,eAEJ,yEAEE,4DAEA,mHASE,mBAPA,kBAEA,YADA,oBAGA,aADA,gBAIA,CAEA,qIAEE,WADA,UACA,CAEJ,uGACE,aAEF,iUAGE,cAEF,mHACE,aC1EJ,gCACE,mCAEF,0BAKE,mBAUA,8CACA,YAFA,mCAKA,eAZA,cALA,UASA,YADA,YAYA,iCAdA,YAcA,CAEA,gCAEE,8CADA,gCACA,CAEF,gCAGE,6BADA,mCADA,YAEA,CAEF,kCAEE,cADA,oBACA,CACA,wCACE,cAEJ,8BACE,UC5CN,KAEE,6CAA8C,CAC9C,uDAAwD,CACxD,uDAAwD,CAGxD,iCAAsC,CAGtC,+CAAgD,CAChD,uDAAwD,CACxD,uDAAwD,CACxD,oDAAqD,CACrD,6DAA8D,CAC9D,6DAA8D,CAG9D,uDAAwD,CACxD,yDAA0D,CAC1D,4DAA6D,CAC7D,2DAA4D,CAC5D,8DAA+D,CAC/D,iEAAkE,CAClE,uDAAwD,CACxD,wDAAyD,CAG3D,gBACE,qFAGF,SACE,6EAEF,cACE,uFAEF,cACE,uFAEF,cACE,uFAGF,qBACE,eAEF,mBACE,WACA,eChDF,KACE,gDAAiD,CACjD,uDAAwD,CACxD,qDAAsD,CACtD,4DAA6D,CAC7D,oCAAqC,CACrC,2CAA4C,CAC5C,4CAA6C,CAC7C,mDAAoD,CACpD,wBAAyB,CACzB,oBAAqB,CACrB,6CAA8C,CAC9C,gCAAiC,CACjC,yDAA0D,CAC1D,uDAAwD,CACxD,8DAA+D,CCbjE,uBACE,eACA,eACA,gBAGF,iBACE,YACA,+EAGF,iBACE,mDACA","sources":["webpack:///./src/furo/assets/styles/extensions/_readthedocs.sass","webpack:///./src/furo/assets/styles/extensions/_copybutton.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-design.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-inline-tabs.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-panels.sass"],"sourcesContent":["// This file contains the styles used for tweaking how ReadTheDoc's embedded\n// contents would show up inside the theme.\n\n#furo-sidebar-ad-placement\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n .ethical-sidebar\n // Remove the border and box-shadow.\n border: none\n box-shadow: none\n // Manage the background colors.\n background: var(--color-background-secondary)\n &:hover\n background: var(--color-background-hover)\n // Ensure the text is legible.\n a\n color: var(--color-foreground-primary)\n\n .ethical-callout a\n color: var(--color-foreground-secondary) !important\n\n#furo-readthedocs-versions\n position: static\n width: 100%\n background: transparent\n display: block\n\n // Make the background color fit with the theme's aesthetic.\n .rst-versions\n background: rgb(26, 28, 30)\n\n .rst-current-version\n cursor: unset\n background: var(--color-sidebar-item-background)\n &:hover\n background: var(--color-sidebar-item-background)\n .fa-book\n color: var(--color-foreground-primary)\n\n > .rst-other-versions\n padding: 0\n small\n opacity: 1\n\n .injected\n .rst-versions\n position: unset\n\n &:hover,\n &:focus-within\n box-shadow: 0 0 0 1px var(--color-sidebar-background-border)\n\n .rst-current-version\n // Undo the tweaks done in RTD's CSS\n font-size: inherit\n line-height: inherit\n height: auto\n text-align: right\n padding: 12px\n\n // Match the rest of the body\n background: #1a1c1e\n\n .fa-book\n float: left\n color: white\n\n .fa-caret-down\n display: none\n\n .rst-current-version,\n .rst-other-versions,\n .injected\n display: block\n\n > .rst-current-version\n display: none\n",".highlight\n &:hover button.copybtn\n color: var(--color-code-foreground)\n\n button.copybtn\n // Make it visible\n opacity: 1\n\n // Align things correctly\n align-items: center\n\n height: 1.25em\n width: 1.25em\n\n top: 0.625rem // $code-spacing-vertical\n right: 0.5rem\n\n // Make it look better\n color: var(--color-background-item)\n background-color: var(--color-code-background)\n border: none\n\n // Change to cursor to make it obvious that you can click on it\n cursor: pointer\n\n // Transition smoothly, for aesthetics\n transition: color 300ms, opacity 300ms\n\n &:hover\n color: var(--color-brand-content)\n background-color: var(--color-code-background)\n\n &::after\n display: none\n color: var(--color-code-foreground)\n background-color: transparent\n\n &.success\n transition: color 0ms\n color: #22863a\n &::after\n display: block\n\n svg\n padding: 0\n","body\n // Colors\n --sd-color-primary: var(--color-brand-primary)\n --sd-color-primary-highlight: var(--color-brand-content)\n --sd-color-primary-text: var(--color-background-primary)\n\n // Shadows\n --sd-color-shadow: rgba(0, 0, 0, 0.05)\n\n // Cards\n --sd-color-card-border: var(--color-card-border)\n --sd-color-card-border-hover: var(--color-brand-content)\n --sd-color-card-background: var(--color-card-background)\n --sd-color-card-text: var(--color-foreground-primary)\n --sd-color-card-header: var(--color-card-marginals-background)\n --sd-color-card-footer: var(--color-card-marginals-background)\n\n // Tabs\n --sd-color-tabs-label-active: var(--color-brand-content)\n --sd-color-tabs-label-hover: var(--color-foreground-muted)\n --sd-color-tabs-label-inactive: var(--color-foreground-muted)\n --sd-color-tabs-underline-active: var(--color-brand-content)\n --sd-color-tabs-underline-hover: var(--color-foreground-border)\n --sd-color-tabs-underline-inactive: var(--color-background-border)\n --sd-color-tabs-overline: var(--color-background-border)\n --sd-color-tabs-underline: var(--color-background-border)\n\n// Tabs\n.sd-tab-content\n box-shadow: 0 -2px var(--sd-color-tabs-overline), 0 1px var(--sd-color-tabs-underline)\n\n// Shadows\n.sd-card // Have a shadow by default\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n.sd-shadow-sm\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-md\n box-shadow: 0 0.3rem 0.75rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-lg\n box-shadow: 0 0.6rem 1.5rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Cards\n.sd-card-hover:hover // Don't change scale on hover\n transform: none\n\n.sd-cards-carousel // Have a bit of gap in the carousel by default\n gap: 0.25rem\n padding: 0.25rem\n","// This file contains styles to tweak sphinx-inline-tabs to work well with Furo.\n\nbody\n --tabs--label-text: var(--color-foreground-muted)\n --tabs--label-text--hover: var(--color-foreground-muted)\n --tabs--label-text--active: var(--color-brand-content)\n --tabs--label-text--active--hover: var(--color-brand-content)\n --tabs--label-background: transparent\n --tabs--label-background--hover: transparent\n --tabs--label-background--active: transparent\n --tabs--label-background--active--hover: transparent\n --tabs--padding-x: 0.25em\n --tabs--margin-x: 1em\n --tabs--border: var(--color-background-border)\n --tabs--label-border: transparent\n --tabs--label-border--hover: var(--color-foreground-muted)\n --tabs--label-border--active: var(--color-brand-content)\n --tabs--label-border--active--hover: var(--color-brand-content)\n","// This file contains styles to tweak sphinx-panels to work well with Furo.\n\n// sphinx-panels includes Bootstrap 4, which uses .container which can conflict\n// with docutils' `.. container::` directive.\n[role=\"main\"] .container\n max-width: initial\n padding-left: initial\n padding-right: initial\n\n// Make the panels look nicer!\n.shadow.docutils\n border: none\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Make panel colors respond to dark mode\n.sphinx-bs .card\n background-color: var(--color-background-secondary)\n color: var(--color-foreground)\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/_static/styles/furo.css b/_static/styles/furo.css new file mode 100644 index 0000000..b30989d --- /dev/null +++ b/_static/styles/furo.css @@ -0,0 +1,2 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{-webkit-text-size-adjust:100%;line-height:1.15}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}@media print{.content-icon-container,.headerlink,.mobile-header,.related-pages{display:none!important}.highlight{border:.1pt solid var(--color-foreground-border)}a,blockquote,dl,ol,pre,table,ul{page-break-inside:avoid}caption,figure,h1,h2,h3,h4,h5,h6,img{page-break-after:avoid;page-break-inside:avoid}dl,ol,ul{page-break-before:avoid}}.visually-hidden{clip:rect(0,0,0,0)!important;border:0!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:1px!important}:-moz-focusring{outline:auto}body{--font-stack:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;--font-stack--monospace:"SFMono-Regular",Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace;--font-size--normal:100%;--font-size--small:87.5%;--font-size--small--2:81.25%;--font-size--small--3:75%;--font-size--small--4:62.5%;--sidebar-caption-font-size:var(--font-size--small--2);--sidebar-item-font-size:var(--font-size--small);--sidebar-search-input-font-size:var(--font-size--small);--toc-font-size:var(--font-size--small--3);--toc-font-size--mobile:var(--font-size--normal);--toc-title-font-size:var(--font-size--small--4);--admonition-font-size:0.8125rem;--admonition-title-font-size:0.8125rem;--code-font-size:var(--font-size--small--2);--api-font-size:var(--font-size--small);--header-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*4);--header-padding:0.5rem;--sidebar-tree-space-above:1.5rem;--sidebar-caption-space-above:1rem;--sidebar-item-line-height:1rem;--sidebar-item-spacing-vertical:0.5rem;--sidebar-item-spacing-horizontal:1rem;--sidebar-item-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*2);--sidebar-expander-width:var(--sidebar-item-height);--sidebar-search-space-above:0.5rem;--sidebar-search-input-spacing-vertical:0.5rem;--sidebar-search-input-spacing-horizontal:0.5rem;--sidebar-search-input-height:1rem;--sidebar-search-icon-size:var(--sidebar-search-input-height);--toc-title-padding:0.25rem 0;--toc-spacing-vertical:1.5rem;--toc-spacing-horizontal:1.5rem;--toc-item-spacing-vertical:0.4rem;--toc-item-spacing-horizontal:1rem;--icon-search:url('data:image/svg+xml;charset=utf-8,');--icon-pencil:url('data:image/svg+xml;charset=utf-8,');--icon-abstract:url('data:image/svg+xml;charset=utf-8,');--icon-info:url('data:image/svg+xml;charset=utf-8,');--icon-flame:url('data:image/svg+xml;charset=utf-8,');--icon-question:url('data:image/svg+xml;charset=utf-8,');--icon-warning:url('data:image/svg+xml;charset=utf-8,');--icon-failure:url('data:image/svg+xml;charset=utf-8,');--icon-spark:url('data:image/svg+xml;charset=utf-8,');--color-admonition-title--caution:#ff9100;--color-admonition-title-background--caution:rgba(255,145,0,.2);--color-admonition-title--warning:#ff9100;--color-admonition-title-background--warning:rgba(255,145,0,.2);--color-admonition-title--danger:#ff5252;--color-admonition-title-background--danger:rgba(255,82,82,.2);--color-admonition-title--attention:#ff5252;--color-admonition-title-background--attention:rgba(255,82,82,.2);--color-admonition-title--error:#ff5252;--color-admonition-title-background--error:rgba(255,82,82,.2);--color-admonition-title--hint:#00c852;--color-admonition-title-background--hint:rgba(0,200,82,.2);--color-admonition-title--tip:#00c852;--color-admonition-title-background--tip:rgba(0,200,82,.2);--color-admonition-title--important:#00bfa5;--color-admonition-title-background--important:rgba(0,191,165,.2);--color-admonition-title--note:#00b0ff;--color-admonition-title-background--note:rgba(0,176,255,.2);--color-admonition-title--seealso:#448aff;--color-admonition-title-background--seealso:rgba(68,138,255,.2);--color-admonition-title--admonition-todo:grey;--color-admonition-title-background--admonition-todo:hsla(0,0%,50%,.2);--color-admonition-title:#651fff;--color-admonition-title-background:rgba(101,31,255,.2);--icon-admonition-default:var(--icon-abstract);--color-topic-title:#14b8a6;--color-topic-title-background:rgba(20,184,166,.2);--icon-topic-default:var(--icon-pencil);--color-problematic:#b30000;--color-foreground-primary:#000;--color-foreground-secondary:#5a5c63;--color-foreground-muted:#646776;--color-foreground-border:#878787;--color-background-primary:#fff;--color-background-secondary:#f8f9fb;--color-background-hover:#efeff4;--color-background-hover--transparent:#efeff400;--color-background-border:#eeebee;--color-background-item:#ccc;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#2962ff;--color-brand-content:#2a5adf;--color-api-background:var(--color-background-hover--transparent);--color-api-background-hover:var(--color-background-hover);--color-api-overall:var(--color-foreground-secondary);--color-api-name:var(--color-problematic);--color-api-pre-name:var(--color-problematic);--color-api-paren:var(--color-foreground-secondary);--color-api-keyword:var(--color-foreground-primary);--color-highlight-on-target:#ffc;--color-inline-code-background:var(--color-background-secondary);--color-highlighted-background:#def;--color-highlighted-text:var(--color-foreground-primary);--color-guilabel-background:#ddeeff80;--color-guilabel-border:#bedaf580;--color-guilabel-text:var(--color-foreground-primary);--color-admonition-background:transparent;--color-table-header-background:var(--color-background-secondary);--color-table-border:var(--color-background-border);--color-card-border:var(--color-background-secondary);--color-card-background:transparent;--color-card-marginals-background:var(--color-background-secondary);--color-header-background:var(--color-background-primary);--color-header-border:var(--color-background-border);--color-header-text:var(--color-foreground-primary);--color-sidebar-background:var(--color-background-secondary);--color-sidebar-background-border:var(--color-background-border);--color-sidebar-brand-text:var(--color-foreground-primary);--color-sidebar-caption-text:var(--color-foreground-muted);--color-sidebar-link-text:var(--color-foreground-secondary);--color-sidebar-link-text--top-level:var(--color-brand-primary);--color-sidebar-item-background:var(--color-sidebar-background);--color-sidebar-item-background--current:var( --color-sidebar-item-background );--color-sidebar-item-background--hover:linear-gradient(90deg,var(--color-background-hover--transparent) 0%,var(--color-background-hover) var(--sidebar-item-spacing-horizontal),var(--color-background-hover) 100%);--color-sidebar-item-expander-background:transparent;--color-sidebar-item-expander-background--hover:var( --color-background-hover );--color-sidebar-search-text:var(--color-foreground-primary);--color-sidebar-search-background:var(--color-background-secondary);--color-sidebar-search-background--focus:var(--color-background-primary);--color-sidebar-search-border:var(--color-background-border);--color-sidebar-search-icon:var(--color-foreground-muted);--color-toc-background:var(--color-background-primary);--color-toc-title-text:var(--color-foreground-muted);--color-toc-item-text:var(--color-foreground-secondary);--color-toc-item-text--hover:var(--color-foreground-primary);--color-toc-item-text--active:var(--color-brand-primary);--color-content-foreground:var(--color-foreground-primary);--color-content-background:transparent;--color-link:var(--color-brand-content);--color-link--hover:var(--color-brand-content);--color-link-underline:var(--color-background-border);--color-link-underline--hover:var(--color-foreground-border)}.only-light{display:block!important}html body .only-dark{display:none!important}@media not print{body[data-theme=dark]{--color-problematic:#ee5151;--color-foreground-primary:#ffffffcc;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#2b8cee;--color-brand-content:#368ce2;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body[data-theme=dark] .only-light{display:none!important}body[data-theme=dark] .only-dark{display:block!important}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-problematic:#ee5151;--color-foreground-primary:#ffffffcc;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#2b8cee;--color-brand-content:#368ce2;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body:not([data-theme=light]) .only-light{display:none!important}body:not([data-theme=light]) .only-dark{display:block!important}}}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto,body[data-theme=dark] .theme-toggle svg.theme-icon-when-dark,body[data-theme=light] .theme-toggle svg.theme-icon-when-light{display:block}body{font-family:var(--font-stack)}code,kbd,pre,samp{font-family:var(--font-stack--monospace)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}article{line-height:1.5}h1,h2,h3,h4,h5,h6{border-radius:.5rem;font-weight:700;line-height:1.25;margin:.5rem -.5rem;padding-left:.5rem;padding-right:.5rem}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p{margin-top:0}h1{font-size:2.5em;margin-bottom:1rem}h1,h2{margin-top:1.75rem}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.25em}h5{font-size:1.125em}h6{font-size:1em}small{font-size:80%;opacity:75%}p{margin-bottom:.75rem;margin-top:.5rem}hr.docutils{background-color:var(--color-background-border);border:0;height:1px;margin:2rem 0;padding:0}.centered{text-align:center}a{color:var(--color-link);text-decoration:underline;-webkit-text-decoration-color:var(--color-link-underline);text-decoration-color:var(--color-link-underline)}a:hover{color:var(--color-link--hover);-webkit-text-decoration-color:var(--color-link-underline--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link{color:inherit}a.muted-link:hover{color:var(--color-link);-webkit-text-decoration-color:var(--color-link-underline--hover);text-decoration-color:var(--color-link-underline--hover)}html{overflow-x:hidden;overflow-y:scroll;scroll-behavior:smooth}.sidebar-scroll,.toc-scroll,article[role=main] *{scrollbar-color:var(--color-foreground-border) transparent;scrollbar-width:thin}.sidebar-scroll::-webkit-scrollbar,.toc-scroll::-webkit-scrollbar,article[role=main] ::-webkit-scrollbar{height:.25rem;width:.25rem}.sidebar-scroll::-webkit-scrollbar-thumb,.toc-scroll::-webkit-scrollbar-thumb,article[role=main] ::-webkit-scrollbar-thumb{background-color:var(--color-foreground-border);border-radius:.125rem}body,html{background:var(--color-background-primary);color:var(--color-foreground-primary);height:100%}article{background:var(--color-content-background);color:var(--color-content-foreground)}.page{display:flex;min-height:100%}.mobile-header{background-color:var(--color-header-background);border-bottom:1px solid var(--color-header-border);color:var(--color-header-text);display:none;height:var(--header-height);width:100%;z-index:10}.mobile-header.scrolled{border-bottom:none;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2)}.mobile-header .header-center a{color:var(--color-header-text);text-decoration:none}.main{display:flex;flex:1}.sidebar-drawer{background:var(--color-sidebar-background);border-right:1px solid var(--color-sidebar-background-border);box-sizing:border-box;display:flex;justify-content:flex-end;min-width:15em;width:calc(50% - 26em)}.sidebar-container,.toc-drawer{box-sizing:border-box;width:15em}.toc-drawer{background:var(--color-toc-background);padding-right:1rem}.sidebar-sticky,.toc-sticky{display:flex;flex-direction:column;height:min(100%,100vh);height:100vh;position:-webkit-sticky;position:sticky;top:0}.sidebar-scroll,.toc-scroll{flex-grow:1;flex-shrink:1;overflow:auto;scroll-behavior:smooth}.content{display:flex;flex-direction:column;justify-content:space-between;padding:0 3em;width:46em}.icon{display:inline-block;height:1rem;width:1rem}.icon svg{height:100%;width:100%}.announcement{align-items:center;background-color:var(--color-announcement-background);color:var(--color-announcement-text);display:flex;height:var(--header-height);overflow-x:auto}.announcement+.page{min-height:calc(100% - var(--header-height))}.announcement-content{box-sizing:border-box;min-width:100%;padding:.5rem;text-align:center;white-space:nowrap}.announcement-content a{color:var(--color-announcement-text);-webkit-text-decoration-color:var(--color-announcement-text);text-decoration-color:var(--color-announcement-text)}.announcement-content a:hover{color:var(--color-announcement-text);-webkit-text-decoration-color:var(--color-link--hover);text-decoration-color:var(--color-link--hover)}.no-js .theme-toggle-container{display:none}.theme-toggle-container{vertical-align:middle}.theme-toggle{background:transparent;border:none;cursor:pointer;padding:0}.theme-toggle svg{color:var(--color-foreground-primary);display:none;height:1rem;vertical-align:middle;width:1rem}.theme-toggle-header{float:left;padding:1rem .5rem}.nav-overlay-icon,.toc-overlay-icon{cursor:pointer;display:none}.nav-overlay-icon .icon,.toc-overlay-icon .icon{color:var(--color-foreground-secondary);height:1rem;width:1rem}.nav-overlay-icon,.toc-header-icon{align-items:center;justify-content:center}.toc-content-icon{height:1.5rem;width:1.5rem}.content-icon-container{display:flex;float:right;gap:.5rem;margin-bottom:1rem;margin-left:1rem;margin-top:1.5rem}.content-icon-container .edit-this-page svg{color:inherit;height:1rem;width:1rem}.sidebar-toggle{display:none;position:absolute}.sidebar-toggle[name=__toc]{left:20px}.sidebar-toggle:checked{left:40px}.overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms,height 0ms,opacity .25s ease-out;width:0}.sidebar-overlay{z-index:20}.toc-overlay{z-index:40}.sidebar-drawer{transition:left .25s ease-in-out;z-index:30}.toc-drawer{transition:right .25s ease-in-out;z-index:50}#__navigation:checked~.sidebar-overlay{height:100%;opacity:1;width:100%}#__navigation:checked~.page .sidebar-drawer{left:0;top:0}#__toc:checked~.toc-overlay{height:100%;opacity:1;width:100%}#__toc:checked~.page .toc-drawer{right:0;top:0}.back-to-top{background:var(--color-background-primary);border-radius:1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 1px 0 hsla(220,9%,46%,.502);display:none;font-size:.8125rem;left:0;margin-left:50%;padding:.5rem .75rem .5rem .5rem;position:fixed;text-decoration:none;top:1rem;transform:translateX(-50%);z-index:10}.back-to-top svg{fill:currentColor;display:inline-block;height:1rem;width:1rem}.back-to-top span{margin-left:.25rem}.show-back-to-top .back-to-top{align-items:center;display:flex}@media(min-width:97em){html{font-size:110%}}@media(max-width:82em){.toc-content-icon{display:flex}.toc-drawer{border-left:1px solid var(--color-background-muted);height:100vh;position:fixed;right:-15em;top:0}.toc-tree{border-left:none;font-size:var(--toc-font-size--mobile)}.sidebar-drawer{width:calc(50% - 18.5em)}}@media(max-width:67em){.nav-overlay-icon{display:flex}.sidebar-drawer{height:100vh;left:-15em;position:fixed;top:0;width:15em}.toc-header-icon{display:flex}.theme-toggle-content,.toc-content-icon{display:none}.theme-toggle-header{display:block}.mobile-header{align-items:center;display:flex;justify-content:space-between;position:-webkit-sticky;position:sticky;top:0}.mobile-header .header-left,.mobile-header .header-right{display:flex;height:var(--header-height);padding:0 var(--header-padding)}.mobile-header .header-left label,.mobile-header .header-right label{height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.nav-overlay-icon .icon,.theme-toggle svg{height:1.25rem;width:1.25rem}:target{scroll-margin-top:var(--header-height)}.back-to-top{top:calc(var(--header-height) + .5rem)}.page{flex-direction:column;justify-content:center}.content{margin-left:auto;margin-right:auto}}@media(max-width:52em){.content{overflow-x:auto;width:100%}}@media(max-width:46em){.content{padding:0 1em}article aside.sidebar{float:none;margin:1rem 0;width:100%}}.admonition,.topic{background:var(--color-admonition-background);border-radius:.2rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);font-size:var(--admonition-font-size);margin:1rem auto;overflow:hidden;padding:0 .5rem .5rem;page-break-inside:avoid}.admonition>:nth-child(2),.topic>:nth-child(2){margin-top:0}.admonition>:last-child,.topic>:last-child{margin-bottom:0}p.admonition-title,p.topic-title{font-size:var(--admonition-title-font-size);font-weight:500;line-height:1.3;margin:0 -.5rem .5rem;padding:.4rem .5rem .4rem 2rem;position:relative}p.admonition-title:before,p.topic-title:before{content:"";height:1rem;left:.5rem;position:absolute;width:1rem}p.admonition-title{background-color:var(--color-admonition-title-background)}p.admonition-title:before{background-color:var(--color-admonition-title);-webkit-mask-image:var(--icon-admonition-default);mask-image:var(--icon-admonition-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}p.topic-title{background-color:var(--color-topic-title-background)}p.topic-title:before{background-color:var(--color-topic-title);-webkit-mask-image:var(--icon-topic-default);mask-image:var(--icon-topic-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.admonition{border-left:.2rem solid var(--color-admonition-title)}.admonition.caution{border-left-color:var(--color-admonition-title--caution)}.admonition.caution>.admonition-title{background-color:var(--color-admonition-title-background--caution)}.admonition.caution>.admonition-title:before{background-color:var(--color-admonition-title--caution);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.warning{border-left-color:var(--color-admonition-title--warning)}.admonition.warning>.admonition-title{background-color:var(--color-admonition-title-background--warning)}.admonition.warning>.admonition-title:before{background-color:var(--color-admonition-title--warning);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.danger{border-left-color:var(--color-admonition-title--danger)}.admonition.danger>.admonition-title{background-color:var(--color-admonition-title-background--danger)}.admonition.danger>.admonition-title:before{background-color:var(--color-admonition-title--danger);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.attention{border-left-color:var(--color-admonition-title--attention)}.admonition.attention>.admonition-title{background-color:var(--color-admonition-title-background--attention)}.admonition.attention>.admonition-title:before{background-color:var(--color-admonition-title--attention);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.error{border-left-color:var(--color-admonition-title--error)}.admonition.error>.admonition-title{background-color:var(--color-admonition-title-background--error)}.admonition.error>.admonition-title:before{background-color:var(--color-admonition-title--error);-webkit-mask-image:var(--icon-failure);mask-image:var(--icon-failure)}.admonition.hint{border-left-color:var(--color-admonition-title--hint)}.admonition.hint>.admonition-title{background-color:var(--color-admonition-title-background--hint)}.admonition.hint>.admonition-title:before{background-color:var(--color-admonition-title--hint);-webkit-mask-image:var(--icon-question);mask-image:var(--icon-question)}.admonition.tip{border-left-color:var(--color-admonition-title--tip)}.admonition.tip>.admonition-title{background-color:var(--color-admonition-title-background--tip)}.admonition.tip>.admonition-title:before{background-color:var(--color-admonition-title--tip);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.important{border-left-color:var(--color-admonition-title--important)}.admonition.important>.admonition-title{background-color:var(--color-admonition-title-background--important)}.admonition.important>.admonition-title:before{background-color:var(--color-admonition-title--important);-webkit-mask-image:var(--icon-flame);mask-image:var(--icon-flame)}.admonition.note{border-left-color:var(--color-admonition-title--note)}.admonition.note>.admonition-title{background-color:var(--color-admonition-title-background--note)}.admonition.note>.admonition-title:before{background-color:var(--color-admonition-title--note);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition.seealso{border-left-color:var(--color-admonition-title--seealso)}.admonition.seealso>.admonition-title{background-color:var(--color-admonition-title-background--seealso)}.admonition.seealso>.admonition-title:before{background-color:var(--color-admonition-title--seealso);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.admonition-todo{border-left-color:var(--color-admonition-title--admonition-todo)}.admonition.admonition-todo>.admonition-title{background-color:var(--color-admonition-title-background--admonition-todo)}.admonition.admonition-todo>.admonition-title:before{background-color:var(--color-admonition-title--admonition-todo);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition-todo>.admonition-title{text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd{margin-left:2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:first-child{margin-top:.125rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list,dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:last-child{margin-bottom:.75rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list>dt{font-size:var(--font-size--small);text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd:empty{margin-bottom:.5rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul{margin-left:-1.2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p:nth-child(2){margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p+p:last-child:empty{margin-bottom:0;margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{color:var(--color-api-overall)}.sig:not(.sig-inline){background:var(--color-api-background);border-radius:.25rem;font-family:var(--font-stack--monospace);font-size:var(--api-font-size);font-weight:700;margin-left:-.25rem;margin-right:-.25rem;padding:.25rem .5rem .25rem 3em;text-indent:-2.5em;transition:background .1s ease-out}.sig:not(.sig-inline):hover{background:var(--color-api-background-hover)}.sig:not(.sig-inline) a.reference .viewcode-link{font-weight:400;width:3.5rem}.sig:not(.sig-inline) span.pre{overflow-wrap:anywhere}em.property{font-style:normal}em.property:first-child{color:var(--color-api-keyword)}.sig-name{color:var(--color-api-name)}.sig-prename{color:var(--color-api-pre-name);font-weight:400}.sig-paren{color:var(--color-api-paren)}.sig-param{font-style:normal}.versionmodified{font-style:italic}div.deprecated p,div.versionadded p,div.versionchanged p{margin-bottom:.125rem;margin-top:.125rem}.viewcode-back,.viewcode-link{float:right;text-align:right}.line-block{margin-bottom:.75rem;margin-top:.5rem}.line-block .line-block{margin-bottom:0;margin-top:0;padding-left:1rem}.code-block-caption,article p.caption,table>caption{font-size:var(--font-size--small);text-align:center}.toctree-wrapper.compound .caption,.toctree-wrapper.compound :not(.caption)>.caption-text{font-size:var(--font-size--small);margin-bottom:0;text-align:initial;text-transform:uppercase}.toctree-wrapper.compound>ul{margin-bottom:0;margin-top:0}.sig-inline,code.literal{background:var(--color-inline-code-background);border-radius:.2em;font-size:var(--font-size--small--2);overflow-wrap:break-word;padding:.1em .2em}p .sig-inline,p code.literal{border:1px solid var(--color-background-border)}.sig-inline{font-family:var(--font-stack--monospace)}div[class*=" highlight-"],div[class^=highlight-]{display:flex;margin:1em 0}div[class*=" highlight-"] .table-wrapper,div[class^=highlight-] .table-wrapper,pre{margin:0;padding:0}pre{overflow:auto}article[role=main] .highlight pre{line-height:1.5}.highlight pre,pre.literal-block{font-size:var(--code-font-size);padding:.625rem .875rem}pre.literal-block{background-color:var(--color-code-background);border-radius:.2rem;color:var(--color-code-foreground);margin-bottom:1rem;margin-top:1rem}.highlight{border-radius:.2rem;width:100%}.highlight .gp,.highlight span.linenos{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlight .hll{display:block;margin-left:-.875rem;margin-right:-.875rem;padding-left:.875rem;padding-right:.875rem}.code-block-caption{background-color:var(--color-code-background);border-bottom:1px solid;border-radius:.25rem;border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:var(--color-background-border);color:var(--color-code-foreground);display:flex;font-weight:300;padding:.625rem .875rem}.code-block-caption+div[class]{margin-top:0}.code-block-caption+div[class] pre{border-top-left-radius:0;border-top-right-radius:0}.highlighttable{display:block;width:100%}.highlighttable tbody{display:block}.highlighttable tr{display:flex}.highlighttable td.linenos{background-color:var(--color-code-background);border-bottom-left-radius:.2rem;border-top-left-radius:.2rem;color:var(--color-code-foreground);padding:.625rem 0 .625rem .875rem}.highlighttable .linenodiv{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;font-size:var(--code-font-size);padding-right:.875rem}.highlighttable td.code{display:block;flex:1;overflow:hidden;padding:0}.highlighttable td.code .highlight{border-bottom-left-radius:0;border-top-left-radius:0}.highlight span.linenos{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;display:inline-block;margin-right:.875rem;padding-left:0;padding-right:.875rem}.footnote-reference{font-size:var(--font-size--small--4);vertical-align:super}dl.footnote.brackets{color:var(--color-foreground-secondary);display:grid;font-size:var(--font-size--small);grid-template-columns:-webkit-max-content auto;grid-template-columns:max-content auto}dl.footnote.brackets dt{margin:0}dl.footnote.brackets dt>.fn-backref{margin-left:.25rem}dl.footnote.brackets dt:after{content:":"}dl.footnote.brackets dt .brackets:before{content:"["}dl.footnote.brackets dt .brackets:after{content:"]"}dl.footnote.brackets dd{margin:0;padding:0 1rem}aside.footnote{color:var(--color-foreground-secondary);font-size:var(--font-size--small)}aside.footnote>span,div.citation>span{float:left;font-weight:500;padding-right:.25rem}aside.footnote>p,div.citation>p{margin-left:2rem}img{box-sizing:border-box;height:auto;max-width:100%}article .figure,article figure{border-radius:.2rem;margin:0}article .figure :last-child,article figure :last-child{margin-bottom:0}article .align-left{clear:left;float:left;margin:0 1rem 1rem}article .align-right{clear:right;float:right;margin:0 1rem 1rem}article .align-center,article .align-default{display:block;margin-left:auto;margin-right:auto;text-align:center}article table.align-default{display:table;text-align:initial}.domainindex-jumpbox,.genindex-jumpbox{border-bottom:1px solid var(--color-background-border);border-top:1px solid var(--color-background-border);padding:.25rem}.domainindex-section h2,.genindex-section h2{margin-bottom:.5rem;margin-top:.75rem}.domainindex-section ul,.genindex-section ul{margin-bottom:0;margin-top:0}ol,ul{margin-bottom:1rem;margin-top:1rem;padding-left:1.2rem}ol li>p:first-child,ul li>p:first-child{margin-bottom:.25rem;margin-top:.25rem}ol li>p:last-child,ul li>p:last-child{margin-top:.25rem}ol li>ol,ol li>ul,ul li>ol,ul li>ul{margin-bottom:.5rem;margin-top:.5rem}ol.arabic{list-style:decimal}ol.loweralpha{list-style:lower-alpha}ol.upperalpha{list-style:upper-alpha}ol.lowerroman{list-style:lower-roman}ol.upperroman{list-style:upper-roman}.simple li>ol,.simple li>ul,.toctree-wrapper li>ol,.toctree-wrapper li>ul{margin-bottom:0;margin-top:0}.field-list dt,.option-list dt,dl.footnote dt,dl.glossary dt,dl.simple dt,dl:not([class]) dt{font-weight:500;margin-top:.25rem}.field-list dt+dt,.option-list dt+dt,dl.footnote dt+dt,dl.glossary dt+dt,dl.simple dt+dt,dl:not([class]) dt+dt{margin-top:0}.field-list dt .classifier:before,.option-list dt .classifier:before,dl.footnote dt .classifier:before,dl.glossary dt .classifier:before,dl.simple dt .classifier:before,dl:not([class]) dt .classifier:before{content:":";margin-left:.2rem;margin-right:.2rem}.field-list dd ul,.field-list dd>p:first-child,.option-list dd ul,.option-list dd>p:first-child,dl.footnote dd ul,dl.footnote dd>p:first-child,dl.glossary dd ul,dl.glossary dd>p:first-child,dl.simple dd ul,dl.simple dd>p:first-child,dl:not([class]) dd ul,dl:not([class]) dd>p:first-child{margin-top:.125rem}.field-list dd ul,.option-list dd ul,dl.footnote dd ul,dl.glossary dd ul,dl.simple dd ul,dl:not([class]) dd ul{margin-bottom:.125rem}.math-wrapper{overflow-x:auto;width:100%}div.math{position:relative;text-align:center}div.math .headerlink,div.math:focus .headerlink{display:none}div.math:hover .headerlink{display:inline-block}div.math span.eqno{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);z-index:1}abbr[title]{cursor:help}.problematic{color:var(--color-problematic)}kbd:not(.compound){background-color:var(--color-background-secondary);border:1px solid var(--color-foreground-border);border-radius:.2rem;box-shadow:0 .0625rem 0 rgba(0,0,0,.2),inset 0 0 0 .125rem var(--color-background-primary);color:var(--color-foreground-primary);display:inline-block;font-size:var(--font-size--small--3);margin:0 .2rem;padding:0 .2rem;vertical-align:text-bottom}blockquote{background:var(--color-background-secondary);border-left:4px solid var(--color-background-border);margin-left:0;margin-right:0;padding:.5rem 1rem}blockquote .attribution{font-weight:600;text-align:right}blockquote.highlights,blockquote.pull-quote{font-size:1.25em}blockquote.epigraph,blockquote.pull-quote{border-left-width:0;border-radius:.5rem}blockquote.highlights{background:transparent;border-left-width:0}p .reference img{vertical-align:middle}p.rubric{font-size:1.125em;font-weight:700;line-height:1.25}dd p.rubric{font-size:var(--font-size--small);font-weight:inherit;line-height:inherit;text-transform:uppercase}article .sidebar{background-color:var(--color-background-secondary);border:1px solid var(--color-background-border);border-radius:.2rem;clear:right;float:right;margin-left:1rem;margin-right:0;width:30%}article .sidebar>*{padding-left:1rem;padding-right:1rem}article .sidebar>ol,article .sidebar>ul{padding-left:2.2rem}article .sidebar .sidebar-title{border-bottom:1px solid var(--color-background-border);font-weight:500;margin:0;padding:.5rem 1rem}.table-wrapper{margin-bottom:.5rem;margin-top:1rem;overflow-x:auto;padding:.2rem .2rem .75rem;width:100%}table.docutils{border-collapse:collapse;border-radius:.2rem;border-spacing:0;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)}table.docutils th{background:var(--color-table-header-background)}table.docutils td,table.docutils th{border-bottom:1px solid var(--color-table-border);border-left:1px solid var(--color-table-border);border-right:1px solid var(--color-table-border);padding:0 .25rem}table.docutils td p,table.docutils th p{margin:.25rem}table.docutils td:first-child,table.docutils th:first-child{border-left:none}table.docutils td:last-child,table.docutils th:last-child{border-right:none}table.docutils td.text-left,table.docutils th.text-left{text-align:left}table.docutils td.text-right,table.docutils th.text-right{text-align:right}table.docutils td.text-center,table.docutils th.text-center{text-align:center}:target{scroll-margin-top:.5rem}@media(max-width:67em){:target{scroll-margin-top:calc(.5rem + var(--header-height))}section>span:target{scroll-margin-top:calc(.8rem + var(--header-height))}}.headerlink{font-weight:100;-webkit-user-select:none;-moz-user-select:none;user-select:none}.code-block-caption>.headerlink,dl dt>.headerlink,figcaption p>.headerlink,h1>.headerlink,h2>.headerlink,h3>.headerlink,h4>.headerlink,h5>.headerlink,h6>.headerlink,p.caption>.headerlink,table>caption>.headerlink{margin-left:.5rem;visibility:hidden}.code-block-caption:hover>.headerlink,dl dt:hover>.headerlink,figcaption p:hover>.headerlink,h1:hover>.headerlink,h2:hover>.headerlink,h3:hover>.headerlink,h4:hover>.headerlink,h5:hover>.headerlink,h6:hover>.headerlink,p.caption:hover>.headerlink,table>caption:hover>.headerlink{visibility:visible}.code-block-caption>.toc-backref,dl dt>.toc-backref,figcaption p>.toc-backref,h1>.toc-backref,h2>.toc-backref,h3>.toc-backref,h4>.toc-backref,h5>.toc-backref,h6>.toc-backref,p.caption>.toc-backref,table>caption>.toc-backref{color:inherit;-webkit-text-decoration-line:none;text-decoration-line:none}figure:hover>figcaption>p>.headerlink,table:hover>caption>.headerlink{visibility:visible}:target>h1:first-of-type,:target>h2:first-of-type,:target>h3:first-of-type,:target>h4:first-of-type,:target>h5:first-of-type,:target>h6:first-of-type,span:target~h1:first-of-type,span:target~h2:first-of-type,span:target~h3:first-of-type,span:target~h4:first-of-type,span:target~h5:first-of-type,span:target~h6:first-of-type{background-color:var(--color-highlight-on-target)}:target>h1:first-of-type code.literal,:target>h2:first-of-type code.literal,:target>h3:first-of-type code.literal,:target>h4:first-of-type code.literal,:target>h5:first-of-type code.literal,:target>h6:first-of-type code.literal,span:target~h1:first-of-type code.literal,span:target~h2:first-of-type code.literal,span:target~h3:first-of-type code.literal,span:target~h4:first-of-type code.literal,span:target~h5:first-of-type code.literal,span:target~h6:first-of-type code.literal{background-color:transparent}.literal-block-wrapper:target .code-block-caption,.this-will-duplicate-information-and-it-is-still-useful-here li :target,figure:target,table:target>caption{background-color:var(--color-highlight-on-target)}dt:target{background-color:var(--color-highlight-on-target)!important}.footnote-reference:target,.footnote>dt:target+dd{background-color:var(--color-highlight-on-target)}.guilabel{background-color:var(--color-guilabel-background);border:1px solid var(--color-guilabel-border);border-radius:.5em;color:var(--color-guilabel-text);font-size:.9em;padding:0 .3em}footer{display:flex;flex-direction:column;font-size:var(--font-size--small);margin-top:2rem}.bottom-of-page{align-items:center;border-top:1px solid var(--color-background-border);color:var(--color-foreground-secondary);display:flex;justify-content:space-between;line-height:1.5;margin-top:1rem;padding-bottom:1rem;padding-top:1rem}@media(max-width:46em){.bottom-of-page{flex-direction:column-reverse;gap:.25rem;text-align:center}}.bottom-of-page .left-details{font-size:var(--font-size--small)}.bottom-of-page .right-details{display:flex;flex-direction:column;gap:.25rem;text-align:right}.bottom-of-page .icons{display:flex;font-size:1rem;gap:.25rem;justify-content:flex-end}.bottom-of-page .icons a{text-decoration:none}.bottom-of-page .icons img,.bottom-of-page .icons svg{font-size:1.125rem;height:1em;width:1em}.related-pages a{align-items:center;display:flex;text-decoration:none}.related-pages a:hover .page-info .title{color:var(--color-link);text-decoration:underline;-webkit-text-decoration-color:var(--color-link-underline);text-decoration-color:var(--color-link-underline)}.related-pages a svg.furo-related-icon,.related-pages a svg.furo-related-icon>use{color:var(--color-foreground-border);flex-shrink:0;height:.75rem;margin:0 .5rem;width:.75rem}.related-pages a.next-page{clear:right;float:right;max-width:50%;text-align:right}.related-pages a.prev-page{clear:left;float:left;max-width:50%}.related-pages a.prev-page svg{transform:rotate(180deg)}.page-info{display:flex;flex-direction:column;overflow-wrap:anywhere}.next-page .page-info{align-items:flex-end}.page-info .context{align-items:center;color:var(--color-foreground-muted);display:flex;font-size:var(--font-size--small);padding-bottom:.1rem;text-decoration:none}ul.search{list-style:none;padding-left:0}ul.search li{border-bottom:1px solid var(--color-background-border);padding:1rem 0}[role=main] .highlighted{background-color:var(--color-highlighted-background);color:var(--color-highlighted-text)}.sidebar-brand{display:flex;flex-direction:column;flex-shrink:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none}.sidebar-brand-text{color:var(--color-sidebar-brand-text);font-size:1.5rem;overflow-wrap:break-word}.sidebar-brand-text,.sidebar-logo-container{margin:var(--sidebar-item-spacing-vertical) 0}.sidebar-logo{display:block;margin:0 auto;max-width:100%}.sidebar-search-container{align-items:center;background:var(--color-sidebar-search-background);display:flex;margin-top:var(--sidebar-search-space-above);position:relative}.sidebar-search-container:focus-within,.sidebar-search-container:hover{background:var(--color-sidebar-search-background--focus)}.sidebar-search-container:before{background-color:var(--color-sidebar-search-icon);content:"";height:var(--sidebar-search-icon-size);left:var(--sidebar-item-spacing-horizontal);-webkit-mask-image:var(--icon-search);mask-image:var(--icon-search);position:absolute;width:var(--sidebar-search-icon-size)}.sidebar-search{background:transparent;border:none;border-bottom:1px solid var(--color-sidebar-search-border);border-top:1px solid var(--color-sidebar-search-border);box-sizing:border-box;color:var(--color-sidebar-search-foreground);padding:var(--sidebar-search-input-spacing-vertical) var(--sidebar-search-input-spacing-horizontal) var(--sidebar-search-input-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size));width:100%;z-index:10}.sidebar-search:focus{outline:none}.sidebar-search::-moz-placeholder{font-size:var(--sidebar-search-input-font-size)}.sidebar-search::placeholder{font-size:var(--sidebar-search-input-font-size)}#searchbox .highlight-link{margin:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0;text-align:center}#searchbox .highlight-link a{color:var(--color-sidebar-search-icon);font-size:var(--font-size--small--2)}.sidebar-tree{font-size:var(--sidebar-item-font-size);margin-bottom:var(--sidebar-item-spacing-vertical);margin-top:var(--sidebar-tree-space-above)}.sidebar-tree ul{display:flex;flex-direction:column;list-style:none;margin-bottom:0;margin-top:0;padding:0}.sidebar-tree li{margin:0;position:relative}.sidebar-tree li>ul{margin-left:var(--sidebar-item-spacing-horizontal)}.sidebar-tree .icon,.sidebar-tree .reference{color:var(--color-sidebar-link-text)}.sidebar-tree .reference{box-sizing:border-box;display:inline-block;height:100%;line-height:var(--sidebar-item-line-height);overflow-wrap:anywhere;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none;width:100%}.sidebar-tree .reference:hover{background:var(--color-sidebar-item-background--hover)}.sidebar-tree .reference.external:after{color:var(--color-sidebar-link-text);content:url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23607D8B' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M0 0h24v24H0z' stroke='none'/%3E%3Cpath d='M11 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-5M10 14 20 4M15 4h5v5'/%3E%3C/svg%3E");margin:0 .25rem;vertical-align:middle}.sidebar-tree .current-page>.reference{font-weight:700}.sidebar-tree label{align-items:center;cursor:pointer;display:flex;height:var(--sidebar-item-height);justify-content:center;position:absolute;right:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--sidebar-expander-width)}.sidebar-tree .caption,.sidebar-tree :not(.caption)>.caption-text{color:var(--color-sidebar-caption-text);font-size:var(--sidebar-caption-font-size);font-weight:700;margin:var(--sidebar-caption-space-above) 0 0 0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-transform:uppercase}.sidebar-tree li.has-children>.reference{padding-right:var(--sidebar-expander-width)}.sidebar-tree .toctree-l1>.reference,.sidebar-tree .toctree-l1>label .icon{color:var(--color-sidebar-link-text--top-level)}.sidebar-tree label{background:var(--color-sidebar-item-expander-background)}.sidebar-tree label:hover{background:var(--color-sidebar-item-expander-background--hover)}.sidebar-tree .current>.reference{background:var(--color-sidebar-item-background--current)}.sidebar-tree .current>.reference:hover{background:var(--color-sidebar-item-background--hover)}.toctree-checkbox{display:none;position:absolute}.toctree-checkbox~ul{display:none}.toctree-checkbox~label .icon svg{transform:rotate(90deg)}.toctree-checkbox:checked~ul{display:block}.toctree-checkbox:checked~label .icon svg{transform:rotate(-90deg)}.toc-title-container{padding:var(--toc-title-padding);padding-top:var(--toc-spacing-vertical)}.toc-title{color:var(--color-toc-title-text);font-size:var(--toc-title-font-size);padding-left:var(--toc-spacing-horizontal);text-transform:uppercase}.no-toc{display:none}.toc-tree-container{padding-bottom:var(--toc-spacing-vertical)}.toc-tree{border-left:1px solid var(--color-background-border);font-size:var(--toc-font-size);line-height:1.3;padding-left:calc(var(--toc-spacing-horizontal) - var(--toc-item-spacing-horizontal))}.toc-tree>ul>li:first-child{padding-top:0}.toc-tree>ul>li:first-child>ul{padding-left:0}.toc-tree>ul>li:first-child>a{display:none}.toc-tree ul{list-style-type:none;margin-bottom:0;margin-top:0;padding-left:var(--toc-item-spacing-horizontal)}.toc-tree li{padding-top:var(--toc-item-spacing-vertical)}.toc-tree li.scroll-current>.reference{color:var(--color-toc-item-text--active);font-weight:700}.toc-tree .reference{color:var(--color-toc-item-text);overflow-wrap:anywhere;text-decoration:none}.toc-scroll{max-height:100vh;overflow-y:scroll}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here){background:rgba(255,0,0,.25);color:var(--color-problematic)}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here):before{content:"ERROR: Adding a table of contents in Furo-based documentation is unnecessary, and does not work well with existing styling.Add a 'this-will-duplicate-information-and-it-is-still-useful-here' class, if you want an escape hatch."}.text-align\:left>p{text-align:left}.text-align\:center>p{text-align:center}.text-align\:right>p{text-align:right} +/*# sourceMappingURL=furo.css.map*/ \ No newline at end of file diff --git a/_static/styles/furo.css.map b/_static/styles/furo.css.map new file mode 100644 index 0000000..92af407 --- /dev/null +++ b/_static/styles/furo.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo.css","mappings":"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","sources":["webpack:///./node_modules/normalize.css/normalize.css","webpack:///./src/furo/assets/styles/base/_print.sass","webpack:///./src/furo/assets/styles/base/_screen-readers.sass","webpack:///./src/furo/assets/styles/base/_theme.sass","webpack:///./src/furo/assets/styles/variables/_fonts.scss","webpack:///./src/furo/assets/styles/variables/_spacing.scss","webpack:///./src/furo/assets/styles/variables/_icons.scss","webpack:///./src/furo/assets/styles/variables/_admonitions.scss","webpack:///./src/furo/assets/styles/variables/_colors.scss","webpack:///./src/furo/assets/styles/base/_typography.sass","webpack:///./src/furo/assets/styles/_scaffold.sass","webpack:///./src/furo/assets/styles/variables/_layout.scss","webpack:///./src/furo/assets/styles/content/_admonitions.sass","webpack:///./src/furo/assets/styles/content/_api.sass","webpack:///./src/furo/assets/styles/content/_blocks.sass","webpack:///./src/furo/assets/styles/content/_captions.sass","webpack:///./src/furo/assets/styles/content/_code.sass","webpack:///./src/furo/assets/styles/content/_footnotes.sass","webpack:///./src/furo/assets/styles/content/_images.sass","webpack:///./src/furo/assets/styles/content/_indexes.sass","webpack:///./src/furo/assets/styles/content/_lists.sass","webpack:///./src/furo/assets/styles/content/_math.sass","webpack:///./src/furo/assets/styles/content/_misc.sass","webpack:///./src/furo/assets/styles/content/_rubrics.sass","webpack:///./src/furo/assets/styles/content/_sidebar.sass","webpack:///./src/furo/assets/styles/content/_tables.sass","webpack:///./src/furo/assets/styles/content/_target.sass","webpack:///./src/furo/assets/styles/content/_gui-labels.sass","webpack:///./src/furo/assets/styles/components/_footer.sass","webpack:///./src/furo/assets/styles/components/_search.sass","webpack:///./src/furo/assets/styles/components/_sidebar.sass","webpack:///./src/furo/assets/styles/components/_table_of_contents.sass","webpack:///./src/furo/assets/styles/_shame.sass"],"sourcesContent":["/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\nsmall {\n font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\nimg {\n border-style: none;\n}\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\nfieldset {\n padding: 0.35em 0.75em 0.625em;\n}\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\ndetails {\n display: block;\n}\n\n/*\n * Add the correct display in all browsers.\n */\n\nsummary {\n display: list-item;\n}\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n","// This file contains styles for managing print media.\n\n////////////////////////////////////////////////////////////////////////////////\n// Hide elements not relevant to print media.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Hide icon container.\n .content-icon-container\n display: none !important\n\n // Hide showing header links if hovering over when printing.\n .headerlink\n display: none !important\n\n // Hide mobile header.\n .mobile-header\n display: none !important\n\n // Hide navigation links.\n .related-pages\n display: none !important\n\n////////////////////////////////////////////////////////////////////////////////\n// Tweaks related to decolorization.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Apply a border around code which no longer have a color background.\n .highlight\n border: 0.1pt solid var(--color-foreground-border)\n\n////////////////////////////////////////////////////////////////////////////////\n// Avoid page break in some relevant cases.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n ul, ol, dl, a, table, pre, blockquote\n page-break-inside: avoid\n\n h1, h2, h3, h4, h5, h6, img, figure, caption\n page-break-inside: avoid\n page-break-after: avoid\n\n ul, ol, dl\n page-break-before: avoid\n",".visually-hidden\n position: absolute !important\n width: 1px !important\n height: 1px !important\n padding: 0 !important\n margin: -1px !important\n overflow: hidden !important\n clip: rect(0,0,0,0) !important\n white-space: nowrap !important\n border: 0 !important\n\n:-moz-focusring\n outline: auto\n","// This file serves as the \"skeleton\" of the theming logic.\n//\n// This contains the bulk of the logic for handling dark mode, color scheme\n// toggling and the handling of color-scheme-specific hiding of elements.\n\nbody\n @include fonts\n @include spacing\n @include icons\n @include admonitions\n @include default-admonition(#651fff, \"abstract\")\n @include default-topic(#14B8A6, \"pencil\")\n\n @include colors\n\n.only-light\n display: block !important\nhtml body .only-dark\n display: none !important\n\n// Ignore dark-mode hints if print media.\n@media not print\n // Enable dark-mode, if requested.\n body[data-theme=\"dark\"]\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n // Enable dark mode, unless explicitly told to avoid.\n @media (prefers-color-scheme: dark)\n body:not([data-theme=\"light\"])\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n//\n// Theme toggle presentation\n//\nbody[data-theme=\"auto\"]\n .theme-toggle svg.theme-icon-when-auto\n display: block\n\nbody[data-theme=\"dark\"]\n .theme-toggle svg.theme-icon-when-dark\n display: block\n\nbody[data-theme=\"light\"]\n .theme-toggle svg.theme-icon-when-light\n display: block\n","// Fonts used by this theme.\n//\n// There are basically two things here -- using the system font stack and\n// defining sizes for various elements in %ages. We could have also used `em`\n// but %age is easier to reason about for me.\n\n@mixin fonts {\n // These are adapted from https://systemfontstack.com/\n --font-stack: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,\n sans-serif, Apple Color Emoji, Segoe UI Emoji;\n --font-stack--monospace: \"SFMono-Regular\", Menlo, Consolas, Monaco,\n Liberation Mono, Lucida Console, monospace;\n\n --font-size--normal: 100%;\n --font-size--small: 87.5%;\n --font-size--small--2: 81.25%;\n --font-size--small--3: 75%;\n --font-size--small--4: 62.5%;\n\n // Sidebar\n --sidebar-caption-font-size: var(--font-size--small--2);\n --sidebar-item-font-size: var(--font-size--small);\n --sidebar-search-input-font-size: var(--font-size--small);\n\n // Table of Contents\n --toc-font-size: var(--font-size--small--3);\n --toc-font-size--mobile: var(--font-size--normal);\n --toc-title-font-size: var(--font-size--small--4);\n\n // Admonitions\n //\n // These aren't defined in terms of %ages, since nesting these is permitted.\n --admonition-font-size: 0.8125rem;\n --admonition-title-font-size: 0.8125rem;\n\n // Code\n --code-font-size: var(--font-size--small--2);\n\n // API\n --api-font-size: var(--font-size--small);\n}\n","// Spacing for various elements on the page\n//\n// If the user wants to tweak things in a certain way, they are permitted to.\n// They also have to deal with the consequences though!\n\n@mixin spacing {\n // Header!\n --header-height: calc(\n var(--sidebar-item-line-height) + 4 * #{var(--sidebar-item-spacing-vertical)}\n );\n --header-padding: 0.5rem;\n\n // Sidebar\n --sidebar-tree-space-above: 1.5rem;\n --sidebar-caption-space-above: 1rem;\n\n --sidebar-item-line-height: 1rem;\n --sidebar-item-spacing-vertical: 0.5rem;\n --sidebar-item-spacing-horizontal: 1rem;\n --sidebar-item-height: calc(\n var(--sidebar-item-line-height) + 2 *#{var(--sidebar-item-spacing-vertical)}\n );\n\n --sidebar-expander-width: var(--sidebar-item-height); // be square\n\n --sidebar-search-space-above: 0.5rem;\n --sidebar-search-input-spacing-vertical: 0.5rem;\n --sidebar-search-input-spacing-horizontal: 0.5rem;\n --sidebar-search-input-height: 1rem;\n --sidebar-search-icon-size: var(--sidebar-search-input-height);\n\n // Table of Contents\n --toc-title-padding: 0.25rem 0;\n --toc-spacing-vertical: 1.5rem;\n --toc-spacing-horizontal: 1.5rem;\n --toc-item-spacing-vertical: 0.4rem;\n --toc-item-spacing-horizontal: 1rem;\n}\n","// Expose theme icons as CSS variables.\n\n$icons: (\n // Adapted from tabler-icons\n // url: https://tablericons.com/\n \"search\":\n url('data:image/svg+xml;charset=utf-8,'),\n // Factored out from mkdocs-material on 24-Aug-2020.\n // url: https://squidfunk.github.io/mkdocs-material/reference/admonitions/\n \"pencil\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"abstract\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"info\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"flame\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"question\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"warning\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"failure\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"spark\":\n url('data:image/svg+xml;charset=utf-8,')\n);\n\n@mixin icons {\n @each $name, $glyph in $icons {\n --icon-#{$name}: #{$glyph};\n }\n}\n","// Admonitions\n\n// Structure of these is:\n// admonition-class: color \"icon-name\";\n//\n// The colors are translated into CSS variables below. The icons are\n// used directly in the main declarations to set the `mask-image` in\n// the title.\n\n// prettier-ignore\n$admonitions: (\n // Each of these has an reST directives for it.\n \"caution\": #ff9100 \"spark\",\n \"warning\": #ff9100 \"warning\",\n \"danger\": #ff5252 \"spark\",\n \"attention\": #ff5252 \"warning\",\n \"error\": #ff5252 \"failure\",\n \"hint\": #00c852 \"question\",\n \"tip\": #00c852 \"info\",\n \"important\": #00bfa5 \"flame\",\n \"note\": #00b0ff \"pencil\",\n \"seealso\": #448aff \"info\",\n \"admonition-todo\": #808080 \"pencil\"\n);\n\n@mixin default-admonition($color, $icon-name) {\n --color-admonition-title: #{$color};\n --color-admonition-title-background: #{rgba($color, 0.2)};\n\n --icon-admonition-default: var(--icon-#{$icon-name});\n}\n\n@mixin default-topic($color, $icon-name) {\n --color-topic-title: #{$color};\n --color-topic-title-background: #{rgba($color, 0.2)};\n\n --icon-topic-default: var(--icon-#{$icon-name});\n}\n\n@mixin admonitions {\n @each $name, $values in $admonitions {\n --color-admonition-title--#{$name}: #{nth($values, 1)};\n --color-admonition-title-background--#{$name}: #{rgba(\n nth($values, 1),\n 0.2\n )};\n }\n}\n","// Colors used throughout this theme.\n//\n// The aim is to give the user more control. Thus, instead of hard-coding colors\n// in various parts of the stylesheet, the approach taken is to define all\n// colors as CSS variables and reusing them in all the places.\n//\n// `colors-dark` depends on `colors` being included at a lower specificity.\n\n@mixin colors {\n --color-problematic: #b30000;\n\n // Base Colors\n --color-foreground-primary: black; // for main text and headings\n --color-foreground-secondary: #5a5c63; // for secondary text\n --color-foreground-muted: #646776; // for muted text\n --color-foreground-border: #878787; // for content borders\n\n --color-background-primary: white; // for content\n --color-background-secondary: #f8f9fb; // for navigation + ToC\n --color-background-hover: #efeff4ff; // for navigation-item hover\n --color-background-hover--transparent: #efeff400;\n --color-background-border: #eeebee; // for UI borders\n --color-background-item: #ccc; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #2962ff;\n --color-brand-content: #2a5adf;\n\n // API documentation\n --color-api-background: var(--color-background-hover--transparent);\n --color-api-background-hover: var(--color-background-hover);\n --color-api-overall: var(--color-foreground-secondary);\n --color-api-name: var(--color-problematic);\n --color-api-pre-name: var(--color-problematic);\n --color-api-paren: var(--color-foreground-secondary);\n --color-api-keyword: var(--color-foreground-primary);\n --color-highlight-on-target: #ffffcc;\n\n // Inline code background\n --color-inline-code-background: var(--color-background-secondary);\n\n // Highlighted text (search)\n --color-highlighted-background: #ddeeff;\n --color-highlighted-text: var(--color-foreground-primary);\n\n // GUI Labels\n --color-guilabel-background: #ddeeff80;\n --color-guilabel-border: #bedaf580;\n --color-guilabel-text: var(--color-foreground-primary);\n\n // Admonitions!\n --color-admonition-background: transparent;\n\n //////////////////////////////////////////////////////////////////////////////\n // Everything below this should be one of:\n // - var(...)\n // - *-gradient(...)\n // - special literal values (eg: transparent, none)\n //////////////////////////////////////////////////////////////////////////////\n\n // Tables\n --color-table-header-background: var(--color-background-secondary);\n --color-table-border: var(--color-background-border);\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: transparent;\n --color-card-marginals-background: var(--color-background-secondary);\n\n // Header\n --color-header-background: var(--color-background-primary);\n --color-header-border: var(--color-background-border);\n --color-header-text: var(--color-foreground-primary);\n\n // Sidebar (left)\n --color-sidebar-background: var(--color-background-secondary);\n --color-sidebar-background-border: var(--color-background-border);\n\n --color-sidebar-brand-text: var(--color-foreground-primary);\n --color-sidebar-caption-text: var(--color-foreground-muted);\n --color-sidebar-link-text: var(--color-foreground-secondary);\n --color-sidebar-link-text--top-level: var(--color-brand-primary);\n\n --color-sidebar-item-background: var(--color-sidebar-background);\n --color-sidebar-item-background--current: var(\n --color-sidebar-item-background\n );\n --color-sidebar-item-background--hover: linear-gradient(\n 90deg,\n var(--color-background-hover--transparent) 0%,\n var(--color-background-hover) var(--sidebar-item-spacing-horizontal),\n var(--color-background-hover) 100%\n );\n\n --color-sidebar-item-expander-background: transparent;\n --color-sidebar-item-expander-background--hover: var(\n --color-background-hover\n );\n\n --color-sidebar-search-text: var(--color-foreground-primary);\n --color-sidebar-search-background: var(--color-background-secondary);\n --color-sidebar-search-background--focus: var(--color-background-primary);\n --color-sidebar-search-border: var(--color-background-border);\n --color-sidebar-search-icon: var(--color-foreground-muted);\n\n // Table of Contents (right)\n --color-toc-background: var(--color-background-primary);\n --color-toc-title-text: var(--color-foreground-muted);\n --color-toc-item-text: var(--color-foreground-secondary);\n --color-toc-item-text--hover: var(--color-foreground-primary);\n --color-toc-item-text--active: var(--color-brand-primary);\n\n // Actual page contents\n --color-content-foreground: var(--color-foreground-primary);\n --color-content-background: transparent;\n\n // Links\n --color-link: var(--color-brand-content);\n --color-link--hover: var(--color-brand-content);\n --color-link-underline: var(--color-background-border);\n --color-link-underline--hover: var(--color-foreground-border);\n}\n\n@mixin colors-dark {\n --color-problematic: #ee5151;\n\n // Base Colors\n --color-foreground-primary: #ffffffcc; // for main text and headings\n --color-foreground-secondary: #9ca0a5; // for secondary text\n --color-foreground-muted: #81868d; // for muted text\n --color-foreground-border: #666666; // for content borders\n\n --color-background-primary: #131416; // for content\n --color-background-secondary: #1a1c1e; // for navigation + ToC\n --color-background-hover: #1e2124ff; // for navigation-item hover\n --color-background-hover--transparent: #1e212400;\n --color-background-border: #303335; // for UI borders\n --color-background-item: #444; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #2b8cee;\n --color-brand-content: #368ce2;\n\n // Highlighted text (search)\n --color-highlighted-background: #083563;\n\n // GUI Labels\n --color-guilabel-background: #08356380;\n --color-guilabel-border: #13395f80;\n\n // API documentation\n --color-api-keyword: var(--color-foreground-secondary);\n --color-highlight-on-target: #333300;\n\n // Admonitions\n --color-admonition-background: #18181a;\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: #18181a;\n --color-card-marginals-background: var(--color-background-hover);\n}\n","// This file contains the styling for making the content throughout the page,\n// including fonts, paragraphs, headings and spacing among these elements.\n\nbody\n font-family: var(--font-stack)\npre,\ncode,\nkbd,\nsamp\n font-family: var(--font-stack--monospace)\n\n// Make fonts look slightly nicer.\nbody\n -webkit-font-smoothing: antialiased\n -moz-osx-font-smoothing: grayscale\n\n// Line height from Bootstrap 4.1\narticle\n line-height: 1.5\n\n//\n// Headings\n//\nh1,\nh2,\nh3,\nh4,\nh5,\nh6\n line-height: 1.25\n font-weight: bold\n\n border-radius: 0.5rem\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n margin-left: -0.5rem\n margin-right: -0.5rem\n padding-left: 0.5rem\n padding-right: 0.5rem\n\n + p\n margin-top: 0\n\nh1\n font-size: 2.5em\n margin-top: 1.75rem\n margin-bottom: 1rem\nh2\n font-size: 2em\n margin-top: 1.75rem\nh3\n font-size: 1.5em\nh4\n font-size: 1.25em\nh5\n font-size: 1.125em\nh6\n font-size: 1em\n\nsmall\n opacity: 75%\n font-size: 80%\n\n// Paragraph\np\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n\n// Horizontal rules\nhr.docutils\n height: 1px\n padding: 0\n margin: 2rem 0\n background-color: var(--color-background-border)\n border: 0\n\n.centered\n text-align: center\n\n// Links\na\n text-decoration: underline\n\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &.muted-link\n color: inherit\n &:hover\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline--hover)\n","// This file contains the styles for the overall layouting of the documentation\n// skeleton, including the responsive changes as well as sidebar toggles.\n//\n// This is implemented as a mobile-last design, which isn't ideal, but it is\n// reasonably good-enough and I got pretty tired by the time I'd finished this\n// to move the rules around to fix this. Shouldn't take more than 3-4 hours,\n// if you know what you're doing tho.\n\n// HACK: Not all browsers account for the scrollbar width in media queries.\n// This results in horizontal scrollbars in the breakpoint where we go\n// from displaying everything to hiding the ToC. We accomodate for this by\n// adding a bit of padding to the TOC drawer, disabling the horizontal\n// scrollbar and allowing the scrollbars to cover the padding.\n// https://www.456bereastreet.com/archive/201301/media_query_width_and_vertical_scrollbars/\n\n// HACK: Always having the scrollbar visible, prevents certain browsers from\n// causing the content to stutter horizontally between taller-than-viewport and\n// not-taller-than-viewport pages.\n\nhtml\n overflow-x: hidden\n overflow-y: scroll\n scroll-behavior: smooth\n\n.sidebar-scroll, .toc-scroll, article[role=main] *\n // Override Firefox scrollbar style\n scrollbar-width: thin\n scrollbar-color: var(--color-foreground-border) transparent\n\n // Override Chrome scrollbar styles\n &::-webkit-scrollbar\n width: 0.25rem\n height: 0.25rem\n &::-webkit-scrollbar-thumb\n background-color: var(--color-foreground-border)\n border-radius: 0.125rem\n\n//\n// Overalls\n//\nhtml,\nbody\n height: 100%\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\narticle\n color: var(--color-content-foreground)\n background: var(--color-content-background)\n\n.page\n display: flex\n // fill the viewport for pages with little content.\n min-height: 100%\n\n.mobile-header\n width: 100%\n height: var(--header-height)\n background-color: var(--color-header-background)\n color: var(--color-header-text)\n border-bottom: 1px solid var(--color-header-border)\n\n // Looks like sub-script/super-script have this, and we need this to\n // be \"on top\" of those.\n z-index: 10\n\n // We don't show the header on large screens.\n display: none\n\n // Add shadow when scrolled\n &.scrolled\n border-bottom: none\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2)\n\n .header-center\n a\n color: var(--color-header-text)\n text-decoration: none\n\n.main\n display: flex\n flex: 1\n\n// Sidebar (left) also covers the entire left portion of screen.\n.sidebar-drawer\n box-sizing: border-box\n\n border-right: 1px solid var(--color-sidebar-background-border)\n background: var(--color-sidebar-background)\n\n display: flex\n justify-content: flex-end\n // These next two lines took me two days to figure out.\n width: calc((100% - #{$full-width}) / 2 + #{$sidebar-width})\n min-width: $sidebar-width\n\n// Scroll-along sidebars\n.sidebar-container,\n.toc-drawer\n box-sizing: border-box\n width: $sidebar-width\n\n.toc-drawer\n background: var(--color-toc-background)\n // See HACK described on top of this document\n padding-right: 1rem\n\n.sidebar-sticky,\n.toc-sticky\n position: sticky\n top: 0\n height: min(100%, 100vh)\n height: 100vh\n\n display: flex\n flex-direction: column\n\n.sidebar-scroll,\n.toc-scroll\n flex-grow: 1\n flex-shrink: 1\n\n overflow: auto\n scroll-behavior: smooth\n\n// Central items.\n.content\n padding: 0 $content-padding\n width: $content-width\n\n display: flex\n flex-direction: column\n justify-content: space-between\n\n.icon\n display: inline-block\n height: 1rem\n width: 1rem\n svg\n width: 100%\n height: 100%\n\n//\n// Accommodate announcement banner\n//\n.announcement\n background-color: var(--color-announcement-background)\n color: var(--color-announcement-text)\n\n height: var(--header-height)\n display: flex\n align-items: center\n overflow-x: auto\n & + .page\n min-height: calc(100% - var(--header-height))\n\n.announcement-content\n box-sizing: border-box\n padding: 0.5rem\n min-width: 100%\n white-space: nowrap\n text-align: center\n\n a\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-announcement-text)\n\n &:hover\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-link--hover)\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for theme\n////////////////////////////////////////////////////////////////////////////////\n.no-js .theme-toggle-container // don't show theme toggle if there's no JS\n display: none\n\n.theme-toggle-container\n vertical-align: middle\n\n.theme-toggle\n cursor: pointer\n border: none\n padding: 0\n background: transparent\n\n.theme-toggle svg\n vertical-align: middle\n height: 1rem\n width: 1rem\n color: var(--color-foreground-primary)\n display: none\n\n.theme-toggle-header\n float: left\n padding: 1rem 0.5rem\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for elements\n////////////////////////////////////////////////////////////////////////////////\n.toc-overlay-icon, .nav-overlay-icon\n display: none\n cursor: pointer\n\n .icon\n color: var(--color-foreground-secondary)\n height: 1rem\n width: 1rem\n\n.toc-header-icon, .nav-overlay-icon\n // for when we set display: flex\n justify-content: center\n align-items: center\n\n.toc-content-icon\n height: 1.5rem\n width: 1.5rem\n\n.content-icon-container\n float: right\n display: flex\n margin-top: 1.5rem\n margin-left: 1rem\n margin-bottom: 1rem\n gap: 0.5rem\n\n .edit-this-page svg\n color: inherit\n height: 1rem\n width: 1rem\n\n.sidebar-toggle\n position: absolute\n display: none\n// \n.sidebar-toggle[name=\"__toc\"]\n left: 20px\n.sidebar-toggle:checked\n left: 40px\n// \n\n.overlay\n position: fixed\n top: 0\n width: 0\n height: 0\n\n transition: width 0ms, height 0ms, opacity 250ms ease-out\n\n opacity: 0\n background-color: rgba(0, 0, 0, 0.54)\n.sidebar-overlay\n z-index: 20\n.toc-overlay\n z-index: 40\n\n// Keep things on top and smooth.\n.sidebar-drawer\n z-index: 30\n transition: left 250ms ease-in-out\n.toc-drawer\n z-index: 50\n transition: right 250ms ease-in-out\n\n// Show the Sidebar\n#__navigation:checked\n & ~ .sidebar-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .sidebar-drawer\n top: 0\n left: 0\n // Show the toc sidebar\n#__toc:checked\n & ~ .toc-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .toc-drawer\n top: 0\n right: 0\n\n////////////////////////////////////////////////////////////////////////////////\n// Back to top\n////////////////////////////////////////////////////////////////////////////////\n.back-to-top\n text-decoration: none\n\n display: none\n position: fixed\n left: 0\n top: 1rem\n padding: 0.5rem\n padding-right: 0.75rem\n border-radius: 1rem\n font-size: 0.8125rem\n\n background: var(--color-background-primary)\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), #6b728080 0px 0px 1px 0px\n\n z-index: 10\n\n margin-left: 50%\n transform: translateX(-50%)\n svg\n height: 1rem\n width: 1rem\n fill: currentColor\n display: inline-block\n\n span\n margin-left: 0.25rem\n\n .show-back-to-top &\n display: flex\n align-items: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Responsive layouting\n////////////////////////////////////////////////////////////////////////////////\n// Make things a bit bigger on bigger screens.\n@media (min-width: $full-width + $sidebar-width)\n html\n font-size: 110%\n\n@media (max-width: $full-width)\n // Collapse \"toc\" into the icon.\n .toc-content-icon\n display: flex\n .toc-drawer\n position: fixed\n height: 100vh\n top: 0\n right: -$sidebar-width\n border-left: 1px solid var(--color-background-muted)\n .toc-tree\n border-left: none\n font-size: var(--toc-font-size--mobile)\n\n // Accomodate for a changed content width.\n .sidebar-drawer\n width: calc((100% - #{$full-width - $sidebar-width}) / 2 + #{$sidebar-width})\n\n@media (max-width: $full-width - $sidebar-width)\n // Collapse \"navigation\".\n .nav-overlay-icon\n display: flex\n .sidebar-drawer\n position: fixed\n height: 100vh\n width: $sidebar-width\n\n top: 0\n left: -$sidebar-width\n\n // Swap which icon is visible.\n .toc-header-icon\n display: flex\n .toc-content-icon, .theme-toggle-content\n display: none\n .theme-toggle-header\n display: block\n\n // Show the header.\n .mobile-header\n position: sticky\n top: 0\n display: flex\n justify-content: space-between\n align-items: center\n\n .header-left,\n .header-right\n display: flex\n height: var(--header-height)\n padding: 0 var(--header-padding)\n label\n height: 100%\n width: 100%\n user-select: none\n\n .nav-overlay-icon .icon,\n .theme-toggle svg\n height: 1.25rem\n width: 1.25rem\n\n // Add a scroll margin for the content\n :target\n scroll-margin-top: var(--header-height)\n\n // Show back-to-top below the header\n .back-to-top\n top: calc(var(--header-height) + 0.5rem)\n\n // Center the page, and accommodate for the header.\n .page\n flex-direction: column\n justify-content: center\n .content\n margin-left: auto\n margin-right: auto\n\n@media (max-width: $content-width + 2* $content-padding)\n // Content should respect window limits.\n .content\n width: 100%\n overflow-x: auto\n\n@media (max-width: $content-width)\n .content\n padding: 0 $content-padding--small\n // Don't float sidebars to the right.\n article aside.sidebar\n float: none\n width: 100%\n margin: 1rem 0\n","// Overall Layout Variables\n//\n// Because CSS variables can't be used in media queries. The fact that this\n// makes the layout non-user-configurable is a good thing.\n$content-padding: 3em;\n$content-padding--small: 1em;\n$content-width: 46em;\n$sidebar-width: 15em;\n$full-width: $content-width + 2 * ($content-padding + $sidebar-width);\n","//\n// The design here is strongly inspired by mkdocs-material.\n.admonition, .topic\n margin: 1rem auto\n padding: 0 0.5rem 0.5rem 0.5rem\n\n background: var(--color-admonition-background)\n\n border-radius: 0.2rem\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n font-size: var(--admonition-font-size)\n\n overflow: hidden\n page-break-inside: avoid\n\n // First element should have no margin, since the title has it.\n > :nth-child(2)\n margin-top: 0\n\n // Last item should have no margin, since we'll control that w/ padding\n > :last-child\n margin-bottom: 0\n\np.admonition-title, p.topic-title\n position: relative\n margin: 0 -0.5rem 0.5rem\n padding-left: 2rem\n padding-right: .5rem\n padding-top: .4rem\n padding-bottom: .4rem\n\n font-weight: 500\n font-size: var(--admonition-title-font-size)\n line-height: 1.3\n\n // Our fancy icon\n &::before\n content: \"\"\n position: absolute\n left: 0.5rem\n width: 1rem\n height: 1rem\n\n// Default styles\np.admonition-title\n background-color: var(--color-admonition-title-background)\n &::before\n background-color: var(--color-admonition-title)\n mask-image: var(--icon-admonition-default)\n mask-repeat: no-repeat\n\np.topic-title\n background-color: var(--color-topic-title-background)\n &::before\n background-color: var(--color-topic-title)\n mask-image: var(--icon-topic-default)\n mask-repeat: no-repeat\n\n//\n// Variants\n//\n.admonition\n border-left: 0.2rem solid var(--color-admonition-title)\n\n @each $type, $value in $admonitions\n &.#{$type}\n border-left-color: var(--color-admonition-title--#{$type})\n > .admonition-title\n background-color: var(--color-admonition-title-background--#{$type})\n &::before\n background-color: var(--color-admonition-title--#{$type})\n mask-image: var(--icon-#{nth($value, 2)})\n\n.admonition-todo > .admonition-title\n text-transform: uppercase\n","// This file stylizes the API documentation (stuff generated by autodoc). It's\n// deeply nested due to how autodoc structures the HTML without enough classes\n// to select the relevant items.\n\n// API docs!\ndl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)\n // Tweak the spacing of all the things!\n dd\n margin-left: 2rem\n > :first-child\n margin-top: 0.125rem\n > :last-child\n margin-bottom: 0.75rem\n\n // This is used for the arguments\n .field-list\n margin-bottom: 0.75rem\n\n // \"Headings\" (like \"Parameters\" and \"Return\")\n > dt\n text-transform: uppercase\n font-size: var(--font-size--small)\n\n dd:empty\n margin-bottom: 0.5rem\n dd > ul\n margin-left: -1.2rem\n > li\n > p:nth-child(2)\n margin-top: 0\n // When the last-empty-paragraph follows a paragraph, it doesn't need\n // to augument the existing spacing.\n > p + p:last-child:empty\n margin-top: 0\n margin-bottom: 0\n\n // Colorize the elements\n > dt\n color: var(--color-api-overall)\n\n.sig:not(.sig-inline)\n font-weight: bold\n\n font-size: var(--api-font-size)\n font-family: var(--font-stack--monospace)\n\n margin-left: -0.25rem\n margin-right: -0.25rem\n padding-top: 0.25rem\n padding-bottom: 0.25rem\n padding-right: 0.5rem\n\n // These are intentionally em, to properly match the font size.\n padding-left: 3em\n text-indent: -2.5em\n\n border-radius: 0.25rem\n\n background: var(--color-api-background)\n transition: background 100ms ease-out\n\n &:hover\n background: var(--color-api-background-hover)\n\n // adjust the size of the [source] link on the right.\n a.reference\n .viewcode-link\n font-weight: normal\n width: 3.5rem\n\n // Break words when they're too long\n span.pre\n overflow-wrap: anywhere\n\nem.property\n font-style: normal\n &:first-child\n color: var(--color-api-keyword)\n.sig-name\n color: var(--color-api-name)\n.sig-prename\n font-weight: normal\n color: var(--color-api-pre-name)\n.sig-paren\n color: var(--color-api-paren)\n.sig-param\n font-style: normal\n\n.versionmodified\n font-style: italic\ndiv.versionadded, div.versionchanged, div.deprecated\n p\n margin-top: 0.125rem\n margin-bottom: 0.125rem\n\n// Align the [docs] and [source] to the right.\n.viewcode-link, .viewcode-back\n float: right\n text-align: right\n",".line-block\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n .line-block\n margin-top: 0rem\n margin-bottom: 0rem\n padding-left: 1rem\n","// Captions\narticle p.caption,\ntable > caption,\n.code-block-caption\n font-size: var(--font-size--small)\n text-align: center\n\n// Caption above a TOCTree\n.toctree-wrapper.compound\n .caption, :not(.caption) > .caption-text\n font-size: var(--font-size--small)\n text-transform: uppercase\n\n text-align: initial\n margin-bottom: 0\n\n > ul\n margin-top: 0\n margin-bottom: 0\n","// Inline code\ncode.literal, .sig-inline\n background: var(--color-inline-code-background)\n border-radius: 0.2em\n // Make the font smaller, and use padding to recover.\n font-size: var(--font-size--small--2)\n padding: 0.1em 0.2em\n\n overflow-wrap: break-word\n\n p &\n border: 1px solid var(--color-background-border)\n\n.sig-inline\n font-family: var(--font-stack--monospace)\n\n// Code and Literal Blocks\n$code-spacing-vertical: 0.625rem\n$code-spacing-horizontal: 0.875rem\n\n// Wraps every literal block + line numbers.\ndiv[class*=\" highlight-\"],\ndiv[class^=\"highlight-\"]\n margin: 1em 0\n display: flex\n\n .table-wrapper\n margin: 0\n padding: 0\n\npre\n margin: 0\n padding: 0\n overflow: auto\n\n // Needed to have more specificity than pygments' \"pre\" selector. :(\n article[role=\"main\"] .highlight &\n line-height: 1.5\n\n &.literal-block,\n .highlight &\n font-size: var(--code-font-size)\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n // Make it look like all the other blocks.\n &.literal-block\n margin-top: 1rem\n margin-bottom: 1rem\n\n border-radius: 0.2rem\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n\n// All code is always contained in this.\n.highlight\n width: 100%\n border-radius: 0.2rem\n\n // Make line numbers and prompts un-selectable.\n .gp, span.linenos\n user-select: none\n pointer-events: none\n\n // Expand the line-highlighting.\n .hll\n display: block\n margin-left: -$code-spacing-horizontal\n margin-right: -$code-spacing-horizontal\n padding-left: $code-spacing-horizontal\n padding-right: $code-spacing-horizontal\n\n/* Make code block captions be nicely integrated */\n.code-block-caption\n display: flex\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n border-radius: 0.25rem\n border-bottom-left-radius: 0\n border-bottom-right-radius: 0\n font-weight: 300\n border-bottom: 1px solid\n\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n border-color: var(--color-background-border)\n\n + div[class]\n margin-top: 0\n pre\n border-top-left-radius: 0\n border-top-right-radius: 0\n\n// When `html_codeblock_linenos_style` is table.\n.highlighttable\n width: 100%\n display: block\n tbody\n display: block\n\n tr\n display: flex\n\n // Line numbers\n td.linenos\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n padding: $code-spacing-vertical $code-spacing-horizontal\n padding-right: 0\n border-top-left-radius: 0.2rem\n border-bottom-left-radius: 0.2rem\n\n .linenodiv\n padding-right: $code-spacing-horizontal\n font-size: var(--code-font-size)\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n\n // Actual code\n td.code\n padding: 0\n display: block\n flex: 1\n overflow: hidden\n\n .highlight\n border-top-left-radius: 0\n border-bottom-left-radius: 0\n\n// When `html_codeblock_linenos_style` is inline.\n.highlight\n span.linenos\n display: inline-block\n padding-left: 0\n padding-right: $code-spacing-horizontal\n margin-right: $code-spacing-horizontal\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n","// Inline Footnote Reference\n.footnote-reference\n font-size: var(--font-size--small--4)\n vertical-align: super\n\n// Definition list, listing the content of each note.\n// docutils <= 0.17\ndl.footnote.brackets\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\n display: grid\n grid-template-columns: max-content auto\n dt\n margin: 0\n > .fn-backref\n margin-left: 0.25rem\n\n &:after\n content: \":\"\n\n .brackets\n &:before\n content: \"[\"\n &:after\n content: \"]\"\n\n dd\n margin: 0\n padding: 0 1rem\n\n// docutils >= 0.18\naside.footnote\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\naside.footnote > span,\ndiv.citation > span\n float: left\n font-weight: 500\n padding-right: 0.25rem\n\naside.footnote > p,\ndiv.citation > p\n margin-left: 2rem\n","//\n// Figures\n//\nimg\n box-sizing: border-box\n max-width: 100%\n height: auto\n\narticle\n figure, .figure\n border-radius: 0.2rem\n\n margin: 0\n :last-child\n margin-bottom: 0\n\n .align-left\n float: left\n clear: left\n margin: 0 1rem 1rem\n\n .align-right\n float: right\n clear: right\n margin: 0 1rem 1rem\n\n .align-default,\n .align-center\n display: block\n text-align: center\n margin-left: auto\n margin-right: auto\n\n // WELL, table needs to be stylised like a table.\n table.align-default\n display: table\n text-align: initial\n",".genindex-jumpbox, .domainindex-jumpbox\n border-top: 1px solid var(--color-background-border)\n border-bottom: 1px solid var(--color-background-border)\n padding: 0.25rem\n\n.genindex-section, .domainindex-section\n h2\n margin-top: 0.75rem\n margin-bottom: 0.5rem\n ul\n margin-top: 0\n margin-bottom: 0\n","ul,\nol\n padding-left: 1.2rem\n\n // Space lists out like paragraphs\n margin-top: 1rem\n margin-bottom: 1rem\n // reduce margins within li.\n li\n > p:first-child\n margin-top: 0.25rem\n margin-bottom: 0.25rem\n\n > p:last-child\n margin-top: 0.25rem\n\n > ul,\n > ol\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n\nol\n &.arabic\n list-style: decimal\n &.loweralpha\n list-style: lower-alpha\n &.upperalpha\n list-style: upper-alpha\n &.lowerroman\n list-style: lower-roman\n &.upperroman\n list-style: upper-roman\n\n// Don't space lists out when they're \"simple\" or in a `.. toctree::`\n.simple,\n.toctree-wrapper\n li\n > ul,\n > ol\n margin-top: 0\n margin-bottom: 0\n\n// Definition Lists\n.field-list,\n.option-list,\ndl:not([class]),\ndl.simple,\ndl.footnote,\ndl.glossary\n dt\n font-weight: 500\n margin-top: 0.25rem\n + dt\n margin-top: 0\n\n .classifier::before\n content: \":\"\n margin-left: 0.2rem\n margin-right: 0.2rem\n\n dd\n > p:first-child,\n ul\n margin-top: 0.125rem\n\n ul\n margin-bottom: 0.125rem\n",".math-wrapper\n width: 100%\n overflow-x: auto\n\ndiv.math\n position: relative\n text-align: center\n\n .headerlink,\n &:focus .headerlink\n display: none\n\n &:hover .headerlink\n display: inline-block\n\n span.eqno\n position: absolute\n right: 0.5rem\n top: 50%\n transform: translate(0, -50%)\n z-index: 1\n","// Abbreviations\nabbr[title]\n cursor: help\n\n// \"Problematic\" content, as identified by Sphinx\n.problematic\n color: var(--color-problematic)\n\n// Keyboard / Mouse \"instructions\"\nkbd:not(.compound)\n margin: 0 0.2rem\n padding: 0 0.2rem\n border-radius: 0.2rem\n border: 1px solid var(--color-foreground-border)\n color: var(--color-foreground-primary)\n vertical-align: text-bottom\n\n font-size: var(--font-size--small--3)\n display: inline-block\n\n box-shadow: 0 0.0625rem 0 rgba(0, 0, 0, 0.2), inset 0 0 0 0.125rem var(--color-background-primary)\n\n background-color: var(--color-background-secondary)\n\n// Blockquote\nblockquote\n border-left: 4px solid var(--color-background-border)\n background: var(--color-background-secondary)\n\n margin-left: 0\n margin-right: 0\n padding: 0.5rem 1rem\n\n .attribution\n font-weight: 600\n text-align: right\n\n &.pull-quote,\n &.highlights\n font-size: 1.25em\n\n &.epigraph,\n &.pull-quote\n border-left-width: 0\n border-radius: 0.5rem\n\n &.highlights\n border-left-width: 0\n background: transparent\n\n// Center align embedded-in-text images\np .reference img\n vertical-align: middle\n","p.rubric\n line-height: 1.25\n font-weight: bold\n font-size: 1.125em\n\n // For Numpy-style documentation that's got rubrics within it.\n // https://github.com/pradyunsg/furo/discussions/505\n dd &\n line-height: inherit\n font-weight: inherit\n\n font-size: var(--font-size--small)\n text-transform: uppercase\n","article .sidebar\n float: right\n clear: right\n width: 30%\n\n margin-left: 1rem\n margin-right: 0\n\n border-radius: 0.2rem\n background-color: var(--color-background-secondary)\n border: var(--color-background-border) 1px solid\n\n > *\n padding-left: 1rem\n padding-right: 1rem\n\n > ul, > ol // lists need additional padding, because bullets.\n padding-left: 2.2rem\n\n .sidebar-title\n margin: 0\n padding: 0.5rem 1rem\n border-bottom: var(--color-background-border) 1px solid\n\n font-weight: 500\n\n// TODO: subtitle\n// TODO: dedicated variables?\n",".table-wrapper\n width: 100%\n overflow-x: auto\n margin-top: 1rem\n margin-bottom: 0.5rem\n padding: 0.2rem 0.2rem 0.75rem\n\ntable.docutils\n border-radius: 0.2rem\n border-spacing: 0\n border-collapse: collapse\n\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n th\n background: var(--color-table-header-background)\n\n td,\n th\n // Space things out properly\n padding: 0 0.25rem\n\n // Get the borders looking just-right.\n border-left: 1px solid var(--color-table-border)\n border-right: 1px solid var(--color-table-border)\n border-bottom: 1px solid var(--color-table-border)\n\n p\n margin: 0.25rem\n\n &:first-child\n border-left: none\n &:last-child\n border-right: none\n\n // MyST-parser tables set these classes for control of column alignment\n &.text-left\n text-align: left\n &.text-right\n text-align: right\n &.text-center\n text-align: center\n",":target\n scroll-margin-top: 0.5rem\n\n@media (max-width: $full-width - $sidebar-width)\n :target\n scroll-margin-top: calc(0.5rem + var(--header-height))\n\n // When a heading is selected\n section > span:target\n scroll-margin-top: calc(0.8rem + var(--header-height))\n\n// Permalinks\n.headerlink\n font-weight: 100\n user-select: none\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\ndl dt,\np.caption,\nfigcaption p,\ntable > caption,\n.code-block-caption\n > .headerlink\n margin-left: 0.5rem\n visibility: hidden\n &:hover > .headerlink\n visibility: visible\n\n // Don't change to link-like, if someone adds the contents directive.\n > .toc-backref\n color: inherit\n text-decoration-line: none\n\n// Figure and table captions are special.\nfigure:hover > figcaption > p > .headerlink,\ntable:hover > caption > .headerlink\n visibility: visible\n\n:target >, // Regular section[id] style anchors\nspan:target ~ // Non-regular span[id] style \"extra\" anchors\n h1,\n h2,\n h3,\n h4,\n h5,\n h6\n &:nth-of-type(1)\n background-color: var(--color-highlight-on-target)\n // .headerlink\n // visibility: visible\n code.literal\n background-color: transparent\n\ntable:target > caption,\nfigure:target\n background-color: var(--color-highlight-on-target)\n\n// Inline page contents\n.this-will-duplicate-information-and-it-is-still-useful-here li :target\n background-color: var(--color-highlight-on-target)\n\n// Code block permalinks\n.literal-block-wrapper:target .code-block-caption\n background-color: var(--color-highlight-on-target)\n\n// When a definition list item is selected\n//\n// There isn't really an alternative to !important here, due to the\n// high-specificity of API documentation's selector.\ndt:target\n background-color: var(--color-highlight-on-target) !important\n\n// When a footnote reference is selected\n.footnote > dt:target + dd,\n.footnote-reference:target\n background-color: var(--color-highlight-on-target)\n",".guilabel\n background-color: var(--color-guilabel-background)\n border: 1px solid var(--color-guilabel-border)\n color: var(--color-guilabel-text)\n\n padding: 0 0.3em\n border-radius: 0.5em\n font-size: 0.9em\n","// This file contains the styles used for stylizing the footer that's shown\n// below the content.\n\nfooter\n font-size: var(--font-size--small)\n display: flex\n flex-direction: column\n\n margin-top: 2rem\n\n// Bottom of page information\n.bottom-of-page\n display: flex\n align-items: center\n justify-content: space-between\n\n margin-top: 1rem\n padding-top: 1rem\n padding-bottom: 1rem\n\n color: var(--color-foreground-secondary)\n border-top: 1px solid var(--color-background-border)\n\n line-height: 1.5\n\n @media (max-width: $content-width)\n text-align: center\n flex-direction: column-reverse\n gap: 0.25rem\n\n .left-details\n font-size: var(--font-size--small)\n\n .right-details\n display: flex\n flex-direction: column\n gap: 0.25rem\n text-align: right\n\n .icons\n display: flex\n justify-content: flex-end\n gap: 0.25rem\n font-size: 1rem\n\n a\n text-decoration: none\n\n svg,\n img\n font-size: 1.125rem\n height: 1em\n width: 1em\n\n// Next/Prev page information\n.related-pages\n a\n display: flex\n align-items: center\n\n text-decoration: none\n &:hover .page-info .title\n text-decoration: underline\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n svg.furo-related-icon,\n svg.furo-related-icon > use\n flex-shrink: 0\n\n color: var(--color-foreground-border)\n\n width: 0.75rem\n height: 0.75rem\n margin: 0 0.5rem\n\n &.next-page\n max-width: 50%\n\n float: right\n clear: right\n text-align: right\n\n &.prev-page\n max-width: 50%\n\n float: left\n clear: left\n\n svg\n transform: rotate(180deg)\n\n.page-info\n display: flex\n flex-direction: column\n overflow-wrap: anywhere\n\n .next-page &\n align-items: flex-end\n\n .context\n display: flex\n align-items: center\n\n padding-bottom: 0.1rem\n\n color: var(--color-foreground-muted)\n font-size: var(--font-size--small)\n text-decoration: none\n","//\n// Search Page Listing\n//\nul.search\n padding-left: 0\n list-style: none\n\n li\n padding: 1rem 0\n border-bottom: 1px solid var(--color-background-border)\n\n//\n// Highlighted by links in search page\n//\n[role=main] .highlighted\n background-color: var(--color-highlighted-background)\n color: var(--color-highlighted-text)\n","// This file contains the styles for the contents of the left sidebar, which\n// contains the navigation tree, logo, search etc.\n\n////////////////////////////////////////////////////////////////////////////////\n// Brand on top of the scrollable tree.\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-brand\n display: flex\n flex-direction: column\n flex-shrink: 0\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n text-decoration: none\n\n.sidebar-brand-text\n color: var(--color-sidebar-brand-text)\n overflow-wrap: break-word\n margin: var(--sidebar-item-spacing-vertical) 0\n font-size: 1.5rem\n\n.sidebar-logo-container\n margin: var(--sidebar-item-spacing-vertical) 0\n\n.sidebar-logo\n margin: 0 auto\n display: block\n max-width: 100%\n\n////////////////////////////////////////////////////////////////////////////////\n// Search\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-search-container\n display: flex\n align-items: center\n margin-top: var(--sidebar-search-space-above)\n\n position: relative\n\n background: var(--color-sidebar-search-background)\n &:hover,\n &:focus-within\n background: var(--color-sidebar-search-background--focus)\n\n &::before\n content: \"\"\n position: absolute\n left: var(--sidebar-item-spacing-horizontal)\n width: var(--sidebar-search-icon-size)\n height: var(--sidebar-search-icon-size)\n\n background-color: var(--color-sidebar-search-icon)\n mask-image: var(--icon-search)\n\n.sidebar-search\n box-sizing: border-box\n\n border: none\n border-top: 1px solid var(--color-sidebar-search-border)\n border-bottom: 1px solid var(--color-sidebar-search-border)\n\n padding-top: var(--sidebar-search-input-spacing-vertical)\n padding-bottom: var(--sidebar-search-input-spacing-vertical)\n padding-right: var(--sidebar-search-input-spacing-horizontal)\n padding-left: calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size))\n\n width: 100%\n\n color: var(--color-sidebar-search-foreground)\n background: transparent\n z-index: 10\n\n &:focus\n outline: none\n\n &::placeholder\n font-size: var(--sidebar-search-input-font-size)\n\n//\n// Hide Search Matches link\n//\n#searchbox .highlight-link\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0\n margin: 0\n text-align: center\n\n a\n color: var(--color-sidebar-search-icon)\n font-size: var(--font-size--small--2)\n\n////////////////////////////////////////////////////////////////////////////////\n// Structure/Skeleton of the navigation tree (left)\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-tree\n font-size: var(--sidebar-item-font-size)\n margin-top: var(--sidebar-tree-space-above)\n margin-bottom: var(--sidebar-item-spacing-vertical)\n\n ul\n padding: 0\n margin-top: 0\n margin-bottom: 0\n\n display: flex\n flex-direction: column\n\n list-style: none\n\n li\n position: relative\n margin: 0\n\n > ul\n margin-left: var(--sidebar-item-spacing-horizontal)\n\n .icon\n color: var(--color-sidebar-link-text)\n\n .reference\n box-sizing: border-box\n color: var(--color-sidebar-link-text)\n\n // Fill the parent.\n display: inline-block\n line-height: var(--sidebar-item-line-height)\n text-decoration: none\n\n // Don't allow long words to cause wrapping.\n overflow-wrap: anywhere\n\n height: 100%\n width: 100%\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n &:hover\n background: var(--color-sidebar-item-background--hover)\n\n // Add a nice little \"external-link\" arrow here.\n &.external::after\n content: url('data:image/svg+xml,')\n margin: 0 0.25rem\n vertical-align: middle\n color: var(--color-sidebar-link-text)\n\n // Make the current page reference bold.\n .current-page > .reference\n font-weight: bold\n\n label\n position: absolute\n top: 0\n right: 0\n height: var(--sidebar-item-height)\n width: var(--sidebar-expander-width)\n\n cursor: pointer\n user-select: none\n\n display: flex\n justify-content: center\n align-items: center\n\n .caption, :not(.caption) > .caption-text\n font-size: var(--sidebar-caption-font-size)\n color: var(--color-sidebar-caption-text)\n\n font-weight: bold\n text-transform: uppercase\n\n margin: var(--sidebar-caption-space-above) 0 0 0\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n // If it has children, add a bit more padding to wrap the content to avoid\n // overlapping with the