From 0b6e6dc12c0b842d6b38f59e85d020bc5147a4ab Mon Sep 17 00:00:00 2001 From: Timm Ortloff Date: Mon, 9 Jan 2023 12:43:27 +0100 Subject: [PATCH 001/105] CI: Update Checkout Action to v3 --- .github/workflows/php.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 8311e74..06acb02 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout code base - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 From 4143019412a07acb1a9035677f3aa181981fed32 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 6 Jun 2023 15:07:04 +0200 Subject: [PATCH 002/105] IcingaDbState: `last_state_change` is now a DateTime Obj ref https://github.com/Icinga/icingadb-web/pull/753 --- library/Businessprocess/State/IcingaDbState.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/State/IcingaDbState.php b/library/Businessprocess/State/IcingaDbState.php index 68ac45d..0eb0927 100644 --- a/library/Businessprocess/State/IcingaDbState.php +++ b/library/Businessprocess/State/IcingaDbState.php @@ -122,7 +122,7 @@ class IcingaDbState } if ($row->state->last_state_change !== null) { - $node->setLastStateChange($row->state->last_state_change/1000); + $node->setLastStateChange($row->state->last_state_change->getTimestamp()); } if ($row->state->in_downtime) { $node->setDowntime(true); From 8449d56c075c0f397f696bd7a7b683f2f355eb15 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 6 Jun 2023 16:01:09 +0200 Subject: [PATCH 003/105] module.info: Require icingadb module version `>=1.1.0` --- module.info | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.info b/module.info index 81092a0..2e988fa 100644 --- a/module.info +++ b/module.info @@ -2,7 +2,7 @@ Name: Businessprocess Version: 2.4.0 Requires: Libraries: icinga-php-library (>=0.8.0), icinga-php-thirdparty (>=0.11.0) - Modules: monitoring (>=2.9.0), icingadb (>=1.0.0) + Modules: monitoring (>=2.9.0), icingadb (>=1.1.0) Description: A Business Process viewer and modeler Provides a web-based process modeler for Icinga. It integrates as a module into Icinga Web 2 and provides a plugin check command for Icinga. Tile and tree From ecdd51b6a0e24edf78727ac4ef1cdbb300506262 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 11 Jul 2023 16:06:23 +0200 Subject: [PATCH 004/105] LegacyConfigParser: Ignore empty lines in `parseHeaderLine()` - Otherwise the index 0 of the empty line in elseif cannot be checked, which leads to an error --- library/Businessprocess/Storage/LegacyConfigParser.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/Businessprocess/Storage/LegacyConfigParser.php b/library/Businessprocess/Storage/LegacyConfigParser.php index d78b45f..834e56d 100644 --- a/library/Businessprocess/Storage/LegacyConfigParser.php +++ b/library/Businessprocess/Storage/LegacyConfigParser.php @@ -196,6 +196,10 @@ class LegacyConfigParser */ protected static function parseHeaderLine($line, Metadata $metadata) { + if (empty($line)) { + return; + } + if (preg_match('/^\s*#\s+(.+?)\s*:\s*(.+)$/', trim($line), $m)) { if ($metadata->hasKey($m[1])) { static::$prevKey = $m[1]; From 77075d5c64ac34f0155c9ee5485dc917a9a9d420 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Fri, 9 Jun 2023 13:16:00 +0200 Subject: [PATCH 005/105] Don't show `process id` if display name exists --- library/Businessprocess/Web/Component/Dashboard.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/Businessprocess/Web/Component/Dashboard.php b/library/Businessprocess/Web/Component/Dashboard.php index 58506df..3423b2f 100644 --- a/library/Businessprocess/Web/Component/Dashboard.php +++ b/library/Businessprocess/Web/Component/Dashboard.php @@ -87,9 +87,8 @@ class Dashboard extends BaseHtmlElement foreach ($processes as $name) { $meta = $storage->loadMetadata($name); $title = $meta->get('Title'); - if ($title) { - $title = sprintf('%s (%s)', $title, $name); - } else { + + if ($title === null) { $title = $name; } From be2473864b623b7ccb20611e2d83808dd496327b Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 11 Jul 2023 11:22:30 +0200 Subject: [PATCH 006/105] Introduce new `XOR (^)` operator --- application/forms/AddNodeForm.php | 17 ++---------- application/forms/EditNodeForm.php | 16 +---------- application/forms/ProcessForm.php | 17 ++---------- doc/09-Operators.md | 10 +++++++ .../09_operators/0906_xor-operator.png | Bin 0 -> 30888 bytes .../09_operators/0907_xor-operator-not-ok.png | Bin 0 -> 30767 bytes library/Businessprocess/BpNode.php | 19 +++++++++++++ library/Businessprocess/Node.php | 25 ++++++++++++++++++ .../Storage/LegacyConfigParser.php | 4 +-- .../Storage/LegacyConfigRenderer.php | 2 +- 10 files changed, 62 insertions(+), 48 deletions(-) create mode 100644 doc/screenshot/09_operators/0906_xor-operator.png create mode 100644 doc/screenshot/09_operators/0907_xor-operator-not-ok.png diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php index 43afa4c..5ef11c7 100644 --- a/application/forms/AddNodeForm.php +++ b/application/forms/AddNodeForm.php @@ -7,6 +7,7 @@ use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Common\EnumList; use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\Modification\ProcessChanges; +use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Storage\Storage; use Icinga\Module\Businessprocess\Web\Form\QuickForm; use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator; @@ -113,21 +114,7 @@ class AddNodeForm extends QuickForm $this->addElement('select', 'operator', array( 'label' => $this->translate('Operator'), 'required' => true, - 'multiOptions' => array( - '&' => $this->translate('AND'), - '|' => $this->translate('OR'), - '!' => $this->translate('NOT'), - '%' => $this->translate('DEGRADED'), - '1' => $this->translate('MIN 1'), - '2' => $this->translate('MIN 2'), - '3' => $this->translate('MIN 3'), - '4' => $this->translate('MIN 4'), - '5' => $this->translate('MIN 5'), - '6' => $this->translate('MIN 6'), - '7' => $this->translate('MIN 7'), - '8' => $this->translate('MIN 8'), - '9' => $this->translate('MIN 9'), - ) + 'multiOptions' => Node::getOperators() )); $display = 1; diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php index eceb065..f26dd04 100644 --- a/application/forms/EditNodeForm.php +++ b/application/forms/EditNodeForm.php @@ -111,21 +111,7 @@ class EditNodeForm extends QuickForm $this->addElement('select', 'operator', array( 'label' => $this->translate('Operator'), 'required' => true, - 'multiOptions' => array( - '&' => $this->translate('AND'), - '|' => $this->translate('OR'), - '!' => $this->translate('NOT'), - '%' => $this->translate('DEGRADED'), - '1' => $this->translate('MIN 1'), - '2' => $this->translate('MIN 2'), - '3' => $this->translate('MIN 3'), - '4' => $this->translate('MIN 4'), - '5' => $this->translate('MIN 5'), - '6' => $this->translate('MIN 6'), - '7' => $this->translate('MIN 7'), - '8' => $this->translate('MIN 8'), - '9' => $this->translate('MIN 9'), - ) + 'multiOptions' => Node::getOperators() )); $display = $this->getNode()->getDisplay() ?: 1; diff --git a/application/forms/ProcessForm.php b/application/forms/ProcessForm.php index be1abbf..604b774 100644 --- a/application/forms/ProcessForm.php +++ b/application/forms/ProcessForm.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Modification\ProcessChanges; +use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Form\QuickForm; use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Web\Notification; @@ -58,21 +59,7 @@ class ProcessForm extends QuickForm $this->addElement('select', 'operator', array( 'label' => $this->translate('Operator'), 'required' => true, - 'multiOptions' => array( - '&' => $this->translate('AND'), - '|' => $this->translate('OR'), - '!' => $this->translate('NOT'), - '%' => $this->translate('DEGRADED'), - '1' => $this->translate('MIN 1'), - '2' => $this->translate('MIN 2'), - '3' => $this->translate('MIN 3'), - '4' => $this->translate('MIN 4'), - '5' => $this->translate('MIN 5'), - '6' => $this->translate('MIN 6'), - '7' => $this->translate('MIN 7'), - '8' => $this->translate('MIN 8'), - '9' => $this->translate('MIN 9'), - ) + 'multiOptions' => Node::getOperators() )); if ($this->node !== null) { diff --git a/doc/09-Operators.md b/doc/09-Operators.md index 58db97c..ba2f51d 100644 --- a/doc/09-Operators.md +++ b/doc/09-Operators.md @@ -17,6 +17,16 @@ The `OR` operator selects the **BEST** state of its child nodes: ![Or Operator #2](screenshot/09_operators/0903_or-operator-without-ok.png) +## XOR + +The `XOR` operator shows OK if only one of n children is OK at the same time. In all other cases the parent node is CRITICAL. +Useful for a service on n servers, only one of which may be running. If both were running, +race conditions and duplication of data could occur. + +![Xor Operator](screenshot/09_operators/0906_xor-operator.png) + +![Xor Operator #2](screenshot/09_operators/0907_xor-operator-not-ok.png) + ## DEGRADED The `DEGRADED` operator behaves like an `AND`, but if the resulting diff --git a/doc/screenshot/09_operators/0906_xor-operator.png b/doc/screenshot/09_operators/0906_xor-operator.png new file mode 100644 index 0000000000000000000000000000000000000000..fd05ec39a5a5e16e51dd0be016eef4be17467724 GIT binary patch literal 30888 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 WG;E+9 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 hs^N*$1iEM)b$=$J$f1T{{UCxUvB^a literal 0 HcmV?d00001 diff --git a/doc/screenshot/09_operators/0907_xor-operator-not-ok.png b/doc/screenshot/09_operators/0907_xor-operator-not-ok.png new file mode 100644 index 0000000000000000000000000000000000000000..8ec41b3036b1c13912a0b95e2fec860818ffea66 GIT binary patch literal 30767 zcmd?RgUhMl$4+#-Q6vXph$P8(m8ZD(o#|a(jp=f(jC%`)X+nB*U<9~KIeUp z51hZ?_iD1pq*VJ;I5hJc4~u`e43+{V=kW zkWiAAkRVrb1e#gem;wOwaW1jVvTaJ(UCqB`B$-^X9h6YR0*7TR1@Wr2^3(+0PpY`Y zaTgU0lf`gT+F=eVP$Ib5$5*-=orQVopDa;OUs!P7)VUMPC|@C~5F%^&1Ec7>`1EiUDI zy4Sj3T!~t5dAggd4;%gLa1?KT?4*1+hCBQuE`dYl#LDkI_+r~WS2bS6xSg+Er19Ho zSZ4Um6l?Qv$LdJ&Ee}HGd|JsD&>K2>x;V+tu8Q$rvtGV_gvxBZn#mV8m`3p3XfiZ_ z1W)O`G>M5LflN0pol-zF(s{T9ib}{ukso;Ybdn#tXjGG}xcU@DYqVt}ZhL^oGF^RP zE6_6J%t*dqx4kg;H$U^wfGn^Q#4Ir*6 zAuSF2RyB4sHMMiH06KSwRGGoJ39?kva@LZU6EFtavc5F|zB6TYx3#|;0uXW+fIZrp zI=>}%x3#fz5^xu${L@1K_I&r6jgtIN7iVi>N-cRMatWZLDLF4IJ1aY-2pTy#xsaoY znShGq>;D-J`z1_i;p}WLz{ck0=EmyA#R_yZXXAMB;sqN!CmSax3#f^2s! zY#glYZ2z4bHdN^Dt$>oHyQz(~q@^v4Jg_xHxH#E`{`7y)^1mzoHB#$;M{=-pa{oQ_ zucrG$)tyWoC4jcDHJwHNmo@)0`0vL587Rbdhx%Wn_=nDa-ogkif+ocFU#5wm^}LXR z@mvfbEh(<%4!1Lh?60Rj^=QFuYtRNP5B!3yf>LloC>~3Tg2osThKH{5g^He$oCHZt ztydA}OPK$NWC1Gbd&D;{Q8pWscSl{Pp+4qogM&7%eD(1IdxI;&sp%=YgTj!M)jeS_ z1BlmgXNBL9zDR#6RwB<-nL!K=P01e~FAIP~|IeeaM9Vx^M61fb-~Q=PDu_e?m`tzh zPy2hopQd36L;}DDg&|_3`27j-Cez^`19lYj*W@2GZBW3PPGZ>tJN_4d|G=`N0QU&s zn$LRt^}n$Fr|AS6*5uiZ-}>$$l&<+=$&UcNeZBUR*`Ygw$31BcOue$odMiC?$BW_j z`-?%)oaq4vy|P1#dxAju#Pe_|vi9SlYnIas5T8MeU-N<7meVmGE?soja*U8aPFpCS zVaJekfN``4UP;pt_PqNtM+0P@%YCcIi`@?Fvmx;S$4MGEbEz|frgt=7NgcjTb!?w5 zEggL2oB(EODbVJQ0&vb>n(fs(<65Agc8J;F~7O`dT${*{z9lKEbEh32B1x zTwj79#`D*~_Am6$M}CJcvia4bCL4HiiKN%ZD*T5q|3xq02cp0j!otmSvYdv7{)z=Z z%dNPtMJI6a=0lqYQJvFXO6eG*gP9EMb;2> zk=ftwvF^)etgq=!z~u=PI@=)G0GB{8Lj@07P~8tonuA?i_j|{x6=_(T&TTFrMEx1Z z&k2cg4=#e-Psghd`wZtpb?s`2dDDuRBHN9X|0QU6Sz@H9&g_7LfET9-ShHlIWUeUB zSPUW*MbcxaFa`0DNh+GP`EG7fYSw!DIP7M%^c*iLYi^3K>@PtIodx-y6W+}js0Wi7 zoNzH~9Uv7qZgJuYy(!uWw`?CSoQx{8QiKv)^m14(wX1pT)j|~A z*XJy2w%s6U28g(wF|tM55quy6FJxZee6+Yqc2yuiV->vXx)_ADwiG9ou^W-|C0bco zIpX_wl2FM6Jbam$_qs}28yyl@a}jY~`-#(`!2j8@e{p~J>4p+OjLXNbQ;L6g3^$L* z(;pEqpB!=R%*DJ=4;De-G8^RVs_eY>JNZq#(cCP2N<8nou3xU;x6uH%HonMS;?O=| zt$CwW?aRelv#?%3-eMdxXQ^{rc_iwzrl;pJUUY!`QeU0e>9c9ygi&vT&!Q`x+>am- z-+A5@G;`tj!XBiLWjuAnGr`!T@_>-jEW?L@mi`pl zIOpq;C6stpk}fV7ytea{ZAh4}Gw0=(cS~xIREVL8#t!Mu(3sA5=R4)anX?K(fb~qj zbX540ZICSEe0VQ(T+_{G)o}M2s~)rIR7j++Bj)GmuO%I-3+-DxLSNz=hQDixG|E(oKxU^ zhZeZ2#lx=sPDS5q{aMH3r|ws~`SvZhSJ`!6i~D@s#qMchylyhMneLzQ^;OUt)@hi= zE{%M#Q{!c7$^d^0fNwpBW~z4&$AshG>Xu-4-I+%Tr5fp5;yPCIXJvhaC3Rm9dC;~1 z#4>!cg-Gr%lO-k#PeKYmtU{~z`u-@`CLMZa1jsV?6J;j(&k^xodCOA0)B1R?&0anj zw=s36*?0Cs^Ku`kZ|4XA0wDcYx7rJ$dL{&p8`v&|^9!?rR|c(vgI}FyLs}YeoCN`t!f|Oyj{8 zl_xF!@&JpKP#6{$hr&n957DqigTX_KrTK6Nz}ABEzdk4Rc=ixMUfA(!5g*F*@KC;> zfHBY4J4OioA@kB;gs$jmOME!rHMS9eT(n6l1L+~f=Ijn4j+N>WhC@Z$+?Q%hXt;*@rg^QJhyRN>0j&5NN?c7<*H_osc172P zv5&|qh%uVTw|uf$rDo=kf7qgAIqyAA81yuCBa66Lukqic__(~@vZVSSsrticeX2Xy zT(9;Alc3H|3W>*Ed~4=Nwz^|8wPMB;{-II0KQeC!q*&?(6yWqrfeKs zTrFyI(nQ@7cRfH%FC(THdc=Z~wXRm4 zht`%+i#u4fU3UAcmg>O*DexZncMA|k_6+gcc<@SiQWL(KyNn{Z>?bJ&+0AkJ8GB6p zO`|&#FE&xk;1NKL@?8l0cC_T8ZY6A;M)Wf=2@OL5x14+XEI?S19Ebq8RJSsn zqKSu}Uh%s~AZ$}cOk(adfYzW_X>n&NM6Ey2KlRe&B?thkuZoZCYh8U*S}dfIw(>I~ zKFy?EGUjxwnrTv-#uKK9->3FKT9o2qoIzLO&sI=Dp#_^%^!inR&wtl+u zMu9Jad&xh4zhfmcGgu@!!{&C=OaGB}b-Bq*4dErwjc(>U+k(e+^w`@5ta-$l%fx~q z5|8DZzLN6!YO1cqs(U2x3>2$I0xV(TFJb0$gn2~bFcc*~>htsFg-C}J`8BFG;>rwA z{Fb{8NE}ocBSTaNIr<0{t`$Z(QJ-wM9tM6D6Sp#*PTL6k8HP0_Xe-?Xenf+U4K;c8 zsOjJ;djE4%sMw#Z?(r2AlJ8Kn#PDl+!Qp@x2mz#-!4Xo!h=L0-u$uqU?ZiXCWu zoI1vdyHi^2yYs1DtZIPud=V>T;S&$WjiE2OOG9+i3o*w1SGs&l;o@!fCU1W-geScQ zZ*%JB&+IsUqiVZ9#ukraT*t>=KXPy&{h>g%ui$q@*T3jcnEC(UH0 z0@DFii~1wRp$w|lm^#ILp&?_vJ2ZRbsc+)N4`Cv!lG~sk`)OLuE(pE*=L|cGCdr=l zBmfxA|ob~#t(nkV;#ZQLd3b_Y|L?jn;tJ7}Ud_uDpe;HEF1535%H0EIh z`YwSkbGz@#Z(T)c=hV^+RYpnop&WxFm@IlHF);pOcyI>KD6yceHQ4+iL7#QnK67CIR4ier7vflPo zGlT$^5JG8=Ruu1Pv2^C)U}1pGH_S(-wAS(`HvOT-S7xLDa6;~v2@8ouW4Bb99KUOdu&0Ueq->v$%~JKOO6sr7I7u-=dw6`cL`!=+X5dy!pZ>|{2Co_|CAmbi#8_2rQtO7N(`tCH%Bt%JR7 zZx{ZTI#;@~bqduzyp~8cVvI*TqP5R?l6$Bg(^#lDf_cJs2)C4umVypQPSw?**Fy(n z_K$lrpj_CGKlM6Ikpabil;VwR&PCR7`F_aJ2JR_+$VmZa?d|j_7qwDL=cQIxRaGat zmFq=(`A9~}KBo4|y4i^#Vyyw;$~-*#QI$OkQsFZSYOu%YID|rH3X5i_4^klA)O_Ss z92?P0GOl?`TDh)=v`;s>cs&Fjuqr`hLz`e0ALwZ2S>M;bE+{zPmWkh=ra@58F*NNrWWJ2(V*||6uM|=xO6NYJOXhaH^ ztj;qTsS)#j9e4wN-9Iga&iTm~g3PD9Rkdw}P7u$XQ@-Rt4C6CLB(jD8lk0vcpshT6 zHbaz|)DFjassY}$P&Ji4J1A-cx>@$M1M1^38wokjH#;&Bg7pomQZpTiPGb}MbtQ&j z=bxm*VkYr1%ngx1NtIs%qnA|1W^X8e(fKJZ$Y6^sSj1<_>x|l3C#7omfMe_=y-SqC zNZcP2VggfxS_SNH4#6*NmKMXXh$2JC^pK?_FvwZ9Y*%e}ts8muuILbb9dVa9@n6}T zYn4wHw~2g|*1e(XN@qCc-3e-u1_$Lfp?#aDG}U`Y+O=_YSTeBhWCJbuR=ed!+ma`a zlAfEj_z6hP+M4O!EPg=d&5S1M3+jEgXn=q%vZ@zfvdIyv)5dpCp9^Sa$y!CanD>5h z_j&Z|#j-kghVR=PYv&`OieKaI)4}$Qw|tVcBms4!Y+~BxANYVB(z;NWM>jSfbF(!< zn7GM>#2M3`w3L=y|1!yas$Rt1DIDxyGVi>JiSgWYqJx$UF0TFT>|6KYcS#{hSL3t`In!lEY5XBDT$r^kyDl7BONg&-Pii zYG09leA(`wbfmB{aWZ-_txE54Og2K5%klJmSsunzOkQFu;n7=kq_^NwM&;Kj)FU#4 z)a=smh^aC(8&Cai7>*5&`J}z*-$c-aihshoFP%nwXwK4rtn*bmImr1X(e21l!J9&t z^8~W2l{IvEYpXt@-OCaEf@@tVP_M7|B*Ex7SXe^$5)RT2!V!Sza1}P|cOIshjs)(; z^9_Qa(IcQt?mpM^MMo;uc!cS9;V)2^RvXJxvEFJjLUm}n-Ul6K^`DjK-xOg7t7{Z} z713(Mh?Wl3jubetT9b|ywn+n}X?V{~Rk@`1P>C3YJ-^I)da@;JC*{53K8l`mqzUHR zHs;JQ3__kxG}JxjdBIC}#zXc|bf--2>m*lCk{;QY+Z+&o<#)C0|h&JTR@ zCg55m$?$66L|(^-Y`a-A=fmkZXF?uj9Jp#Atc$vP%q#0c&ne@vacQ7f(OUb{d&1>f zB9{CZj$OZuDy3)-Nr3k}2CQVp?>YD3s&D+T z={9tk$yhPGg8q+ zvhP}XR1*5hY3D5Pk zvOwEil@xLZo`}o_klYt!OZDo_opahLqj;GL$mW%5Xn3DVfB^NEgWoeoGgYW(L*}^_ zmxTqV6KNm$GLlg7OzA`9IyKMR=gi7lYBc(1x@V>}4VNcery0r6y3cRSr%A#_jFf(4 zVZXwHYQPf_$-n3Y-r(qQvIQuR6U=&vCR{HMIqvnz+qYe<6Dd1)(QJmUd)+&A^eKmF zgaJANxck3ejC|e}`<9oO-teRRj&kY5tklQPC%=@X#8ugH$6r4kOpDXebA+sZt6#$k z*9N;3^rMvMkElwEY-6Kj-BzxG)o$H*`GVvE*R>Cy3%QwT*cI;iVfdyTHg5zFDLH^lX${j0ns3eB(jdPX zRB=)d$<(eFb&jXphLZ;hFDT#=Q^~;Z%cOw8>tB!M*vZ*1?A=Wbf=^bGwIO|`Wn#N5 z*enH-yEN6(d>n;yUI+k5DJc2UJ{gCFhM9$8LHUcTzS$osgGE;FK=rLhx1 zc8S4gCjw^1{E!iN5DwW1D)&}RIl}n2r5`YeUm8U$ zs7>TGlXym`6u?82SLpPNL1lu-g-;fVDW$jM#V8`c%Fe4(=Y1Jb6H|PlX|f+#?m8V-l8!DHS z&+t7_K)T9eOfJJ*#CaqpL+N7wi)v3dEgci|xp@m#Is?q_Hn-wr`&+73O2p9R6YKX) zcHu0uZIg)W54*sspcw}?GHR~Ahi1w~^{YHhI?r#|H0vX++cTQ&MQKnz> zCn2i)ts8m)pRoWNREIC4j=WEWWWC1>|F7uK95c){7UO;vRFsBpLt@aEow#!JB&L!c zXrO&Dlvd&h$$TT!bQRM|_3zM$2gThmc06(Ax8l{va1}=-tM)Gh)viBZ{Nnzmtjf!8 z-rE=Gn(6N|-@hlwA0ziKKCLA9ms8~xeLu}D`+;q$BJMI-Uvg9=jKfWky~=P@_Y>qF z5&ikKf{pIcESWMJO_aRQXvU;G#1)#i9Acd^QnW;(fhs&tyli0FkY=M{FfRK(1` zfxYYLsFihU8RcP-9=)qh zEra`{&k}nEi`ke2bn4${s6Tw|U6`)e$C#Pz-`fyIAaZnA%%)6ine`zQdbqGi52%SF zDfzxzPahi$1717J0skQs#i;yFMJ+6ee0$Ehdnf4F!sq-g`okl%wT(ZrF{>~NmDq1g z-9;IyEnZC{t!V`xn>n{~ zc%a;0xtlJafdJk}=k|D0cWO~@$-cxeAjePm!*E>wPH7VQL!t=c!WI%UaJ>R9rj3$| zd5^t+HerwRfIwNc0oN#i3ZH1bfA9M{-b^mv<*t_fkWe0Eyu1R%LTTZMIo+|Z1IVj@ z;HIDf|J$3z;|m2z6_H3rCp8@9YWZ?tMEP~=2h$WSEW6NXJcdh zMg-SgnZfSOt);d)K{?QClHvjD`uDlz%|Z4haQ<_cpo!D^qU*(8U;jSa4@;PIfmd?x z%@6e^mwrEsdA`So7}nuxouVVej{mo-o`sAGOJ~`))|%%wrUfi`UU0aZH(K@*vmNBzew4!+)}pm(8+TNB{uQYB`;qyT0fiJ zSt3k9IAsq3$tls>hBn&qf{riUf>i!1{joIQf?Z#$) zV9Rxcs3>~B6OH2((Z6N0lZ(-r1&I)=M_qM_yrlv?kK95h_)6ycb_ z-hQWHP8!je?|Fe)H}DP!o6!YV=dBa zW&PYg+g=nRRl{4{L!ZgAF?2pV9U53EyLi6(!hXVzD@~H=>X+NaoV~t_z|IJjv}%vB zo6Np{jmHq#-%4mw6-j^_xh1rGjUb;2OOU^9`&%29IQ5eby3E03F@F-#^IL6xBWQSm zZ3xC3`g-P-{;cmY+rcvWV8@2?)hCx}r-cYvzrdR_lCzv#~_#`7u59yV`NXCM(0T%3I}L zW8pPl5j-Gx-{gg)WQczC16t{kbXG(pw_R4nt_$7CmJA+XW0}+muT+t1GH6kbNre8=;16?dhZ5fB7W|@~eQLKnO!dvA(NjQ* zD$S+lc>R8ZKsgf8(3;Vx;V=gaY%bfk_!VXy7B^lNRoUKHtDUTCXS{}qmpeM;LZ@CP zHzHFxabunsX5Sk37mVe73!Wa)(n`P)hDL>8A`OF+7bb58wieDMa0oej8)Du71K#Z4 zt~IWi`jV{@BjnPifXgk!v$d0NB|_Ub_Otv(aFk*ex(`ug?E}L9J}+t+hqFlmw_L-kmEEJ1>|pYn>xqo^2YRk#Jc7g>GgeX`5lMoa*JF9QP>sXJ{8Fh`?WBcGxm3gJ^Q4j& zOk2sk8gAOaeV^}(A#OR&lBnTG@*0OgwHnipGAO zi;__aJ}!g!iF2{b@2<@;J?sh7g?q`q(9_Z)-RMp>nDgiKrCN;M;%L|?{^F)?O|G4K z12?fH_-p6y_yxzh{(Xgm16;UG<%L^_3@*XQE|KVU34xcK7`yw#kkWYz+k!M^3d)`^ z>22n$Nr(wK-ph^d68L$_8t@gqUeBWB8u`Dx`2gZ4cUkA5?Kw*_qyBGkpST@_MA8Kn z8TVEDHx<%E$~#6yF4~RrD6wXpXZDqJbt7|fC`WM@&X=P*gJOgNf;kh6emrIv=6-wK zw5A@4yTj#(s8M7P>3ie3yb4-*?Subudz?<`d{LJ+^b;cB#|r?OIn5e?y^pn#q`2Bp za`Cep?u>`20YLjvfs(5kqt}reN`G3w@R+Ld+3-Mt26#~DwXVlzjTcj*FvMRi#&n|= z5w>}vd0C+0y?*bGYL_-kw9@tt2opIbrX#FqblCy>ONu{Yw3|bs1(1sQpaCDNp_WI( z8sJaf_^H?Nn0$%QGC@`aO#RaAwT5k+Pn=IXIP-&~pZX~IuIH&t$*E!9;9^S1(S|YA zA1_HlJPQuS4O~hpc1VMN#emxeC#*9Ln}U?DL568r;l9O}9YH92^`a3X>BVGj4C8Nx zrB$^UE5}1K5_*{os2e%IysBTjHq5$?(^cs!_Zf|I`X+j+H~F16SI<|p@)t0KTJK8g zoR;kEV68qlXs1A!eT%i}X|bE(%R^*fh4x7cM?RHWJWA7M2(KZA%)Iyfj;h-hmeEWN z+A7xVYmqLTI4JG5$void*OZyhB^KoJX=#t&{^?P@%H?&Yssv!9`saLoQon?}bfcJc;9&-<$?B!2HR_hjejzx6C z-g;s1?(arRYVOt^yNSeUGaf&iuSsToBhS7b``XeP6JR~^LOtTMAFTQfr;ctTTg7KdKCZ{~-#LZVhq_`T6-8RQK4Cn$B0PJ#K zWVFbu26r4$nK4 z-8vdoF8mzw6a9p-NcMs8&wQDt;6=7smK?lh z$QV^wZUSt93*zG`=i}sB(S{zQELLW%T5R7G!T0}G`pm8j68lZzM48R)#~T6Kza0_>E|6%WB-?+GH_!qP5X<|=Qczt((Ejh1y= z>JIx_ivtKqEz7%XQ9e+xv5FIs%jF z@ZLY##ejsUvxw*n@GQF|G#tOIM-zCeotpT{A-g(WZ?QikP| z3gV0hmUzp{c!*e^#2;=S-b!F6{M;#6DGc?Qd423)zCG|d+e{ynC(AFCq2@YwM*Aer zVZS&Di%r6TTs%*0tK~&|9)56c6K!Q-)6YI!Ldv!$%_X}Rr0SI(rZBVH35Sb?m{?TP=>D+8gpao^ z2Ny*XNBk?@mPLmG+csIj8E3c1usS0IhtsE`JnQT}Yf?oSee3A>#_xrm9c-=}#D>G; z@{I{FWIcl89v=r~%P?M>``+Lkd$j&~^{t?&Eje1?ahH$B_Y+Pnqon=bm@H>pESbV= z=@BI2krBe0g=7?N!?QNS-BKIP=)$YcFNw2N4lKPHSE`JKSrw$nrg|QooGBKp?)@Ou znVn)j3`1xfxB0Ucnj&zN`8Bn1zh9BsWX=c@xF3~#IhP1l3P3)$iN4YUAdyi?iO9o9 z5A#U#MBCveE1*xcn;PNKrL!)K2Ly}!D!Ohp?5nvoJ({d<>7@+Nh2_ z`5AJE!K8e4a>Mc?(cnx_8@!|-Y?3Y8*%sP-#KKjZ!!oZng#{suB`9H?TP&C6O`)P> zZdB_xKKb}u68UkEM09?EFgQrxw^?S@t?BIhm6F@i6f7(jZlXZq_p=8AY7qJQDI5IM{KR<8UtUDAg>D(-*P2*vin59CV#LA4tzK04B% zpO@PcKuLA=QL3|4^MhOD^2Nl7k?rC-Jk=NhVzBVGoQEH(g5c`=v9C_+G>jK%e88Zg z^|mK4?$hF~SYA5Mn-}bs`7C>`awN>Tq+DoHmVBE>12x~4SWeA}B7C{3-_8q7OPX_f zVWZ(s-iH8^r2*3ggw)7UYu+4-QZdd&Y)3<@KCm^3)8?fCd~Rz~sCVD*cb9GB5OJZ7 zgKklkQ%-EEX)XpUWL=h1@blDfLA{Gh^j^1Y_Htg&9a6Be4t0~?lz&sp`l0a~6YmY3 z6}t33Jc*#48Blbu-*sRAI2W8{K)W@Xa%uZE<(gvzC7oY6-uyN+EJ~1`gQ;FfnVi}9 zc)R$ru^#{)i_f_T5E?nA6xgKa3ThAu7Bdeox!5c+G@zP#R$Z3xk zhYhGZp45aB-|%pOUh2|>^|XJ!1i!o#y`W*Q=NFAL8t(ziCUos_a~*e?oZU`*)L(xR zYh-MZfGOHbi9#;^Ezleqwg4%X+}#v?IoAW03Tmh}<)ARLHeGT2J1XHEDyAU}sK^>M z_YPB4xQviPQAy zA7`@o8elR}8bHN)K`hhT&vBx?j`JL!WKN2ab%N7Uc}%L}RV63YQ*!x3@wS078zvxa zyz6bLx@{npcCEtBlThnb{IB?8g5?$teZD#eTkd z&h!lR4O21gx)=2IqSXE;h@dWzcRF2^`T+6y^sr8ux~;8kV#;>biJNBjEix$QEQ!wa z7sB(@1^X5ezh^Sg+j$p@pf~N|$ZrkPNidMJdWQ?=rNb{w2xvh(@sL%{Nh=Y3^F3hHe z$o$t0V_L2}-tkN5=@1r{K)Htblr3#o_IqU&t!$ruXS-xs;w%Qsyn^V#K^fL5S&N_= zjCI@Q2bsPBn>4XHU+4Dn>b+#8hboJVt11*P%dB?e*cXS#DD#CbvQF|s`^~xPF9-bk zEKb>)PU(s?rd3iZj$V5KCS5qInVXz^SnKr}&#NqII%ZFmU0hT66*z$oKC^Y2n@ zScjKBKdQSKoTyG%FJ>KG@9Po@E;7qqw}>~u7L?^EAlR0SS4jCWOdC(?sxh*kUDQQl zb}Ve7%Xv6o6MqIZ+HENj*`1&%-AgkaJc1s&z{r zOD0wBBIs{Y>NCf>VENnh)(SF0cNs!c5L&D@6$at36S@lX){y8AQaMHg(1A9o2;{Xt zgfFVAqKeF{RZrDIxF=Vq_EP$CO0S%!sw#GKwB6?HiikJ+`pD|3a(|_KlccK}o*M5f z5$#h;bq<%;T`1pqU3|6Qi;FS+-8r=(=!w>b(Fp6NZC-j2&>Cz5vRs}2U3!dmJ9t#x z*MRPt!v3>-bnl$Bj3rm0*Bsr2x`qPx!c_SJbo8pvi-O+Ch~G?B5eM~U$4XqXtH))K zmwaD9t<6yQ)!#*dSxiWE704}n0zcDF0h9V&n>6$dL_ou>G7_$!+(XF1QE+T(OUNCQH~!L zBPtm|P}u>cS2k`EgS^KZO>?mv<@b992;q0f0Q}|rtLVPG_K?i7ZTl{~sOAyVo zMr*hS-UA0<-+yUHSAJ5lV`D+g4c}Cv?;p6y2C4YFLp*>_lIPqeKDppZQCXQC2#z z{e>62mKgqyaQ;)b=PC`0t?Mr>58j7GEMOMf{wqEgDM;~%>JYlZSkCUl)pS2{eHTpc zLga)8@Ot!n3$cnmfhuN1cpKd-8M*_JJRb?x&6Ac8@&9aXM&w5p^YzITBKn)de{un0 zk#}{O-M@k#f_VJ|7Oih?Qp~uQYJ;tp^$Hf_*D+aq`EWj87=vRC!E{3*4~R9K1B>yq zl-W}}2#Le;N3i@v$$q@~!;1+P$}Lk%BO1>z8;q@(tZP2OrftcfC|#U}xbpv|0iDjh zeUASpbUupsdalVdRCTR!8IxKMMwXobc$PU)S9}C7fOE1?%)@B=#!DC)b=Ya44@v5r z41;x!W@z~#SL>8uTxD%v%f2rt{_t}&u(XI<&vDH|YO>x{=%WAhpnpg*HyFu=^^b&D zAJ8QW9hMH*cxgi#@sODMFvk5qiPqqrfc^3ErO2dzH*Kc29{X2(A!DXA;IE-OqMq>w zSUj$|YV_ph?tB|xE(&RR`Qh6RNAjNV-qivstX@`Fid+X*vaNpGzebNN-8JDeH#~2s z0mDC*au!d(UVY?;4xE@?q?yEx_t@vo=u6q(81e_+Dk1@#Q;J%C>s-{{6`hLBqn;DN zm7tgQ`0Q+Lp?ochMe5-;RpNgNut4cl-dP+dHf_^{Z9FK_$UeFRlhyBQbQ^f*&ip_+9KZTn^q0A+zCH3{^W31 z3dQVOd2O!x^tc#P$Q=*D~!{VN{>7 z$&y!mAv^`j1jXuI!aG%yA52Y*`Q*5K#n>-?)#m*CNo<42gitf$Q}d{R+*xDWUoeuw zXwV>*3;~4ky~ZiB-Ws%G9Z5NbwkLmVaMuMZRWKSgt}^|B32$-)TSDU7X5eJQ5iq?1 zc7+I|#h z&Of-+(vV|F@hYx;86Ffdz$1A<5FG*kp6`4it?C(v;pk~x{G0U&&HfRXzJk?>=T%yf zBUbA`mtx=+{nFEa%xTG_0d`IC==(EP^_U%sVu?@)rhj zr1YKSl$6(otQNri$($d_8{NK6sTC+XDp}8e>RSjC1YkB1ztI~?awC?)_?u_8(QmK< zzNQ&llNkPCPMKH*s|{_mLdo^^MNMd89wT((;>FcdQ-yOnNZRy<3F*^Gn_rgJWPff2 zO^zbgaRY{N^wK9I?xImG8O+1erm>n`Fk3NjT>%b_AYg*^eUUzY&p$U(UT4W70FbWK zS{gN_-(mV!u(hzwm8a%siOkcmOhxM3V=)AHDRt5MOZNo=@1Qx+3c&61WdE9pOR70) z>QOHAbRm~#@dGF5(YsHTb(SduW^Mi|$Y*3bzsOyoL#0c|Fogp_s?cr5ym3Bb>HkzG zP*L{U?0kq=WxD1o=_UQ9n&YG#1RD4|u?&c8mZ@Oc@}~^&NHI%x9dMwqhklcfzy4hc z|4RrwqR7+-cXs&ET|-*9v7tp53Uiq<(*u z&!-Qy^UH@b?~R9}J#l-N>wE~k%D?@P4Ihf-w7A~I&Yp^3$PxJl4$XwZh|MAQWCh1; z=o0!v@*uLE`uCv`-uMu6hzLoGa&bI>w?)+2cxzt8jsA87+nw&DXX)E)@SW)0qB&av zTHbLFIaZ2n6gn@X`8Lg6%Np7=#)Rf@UdRHXWkj}mITvC3KQ*qfX{D2% zn46-EozzrF_)RYVRNG98}+fAoe8@9hi=9LmlyF}YPe2i@Jj=(Y^-*lu&bI5r9$d@JvQ zh&8mf@{Q!>awiPlLDX~DF?H}YT7Nqby_%|`LSTI`5$R5ZVTIgvLI5KtK@(y>hpo>x zc7isR#s)=CFWvFKBn~#ZrBp_g{LzpqMizMpKBjAaOo?8*oHj094uy?qX;lv0H4{OQ zk5UNicQ${wF&spx7At|{Mq^|#Taa4Ymd#41c&6r(E<|&;l;t1$M*=BzkFp+3jCGL4 zaE=Ixs&`>WH7sI(FS7Tz%lyMW=%-#I>u3L?l9-R^wYc*PH%iXuS;dSLF?S|cmM&t& zFTXBnQv&+#Rl;7PW*P8Qq9Au8`v0^0v|D&; z2u$;L5p)9(UP(RXgoJ09&0Wbx6NU61p9PuQux-r3t%4`J8rI6uhobH{EQM5OiU~-Q zw3lt><;?wY_OAMQUmkjTA}N<{p{&`>zRP0!hXt`tg=^UMP$C~fyu_P1TzI}(N_Y#| zOxLa@qisaw_ObnppTD;)Z<}oX_@8@Xf+!pDUp%2EDqBs%<0aUeL0>=ntfX#KWTF) z+1rlm0W5zl^E)pM#Cv(^S`h4gM=A15q>(*z{U_K5JD?f0GnY37r0`G}+6)(XR3TI;1s`$r-k%N=6gp-LTsx!|J8cMw*OA@@kD6&`* z(yHBEhkJ&l2^-9+Jae6mhxPn-V=NcU2wdsc>OZsop6d@l0Xr}=wR=9=>md}5 zuVKdW=Zo)JO7|9mA$5*ChA4D=(^E&iL<}e|#;N zmGT*O^N!rSiSb#&LqavefS;OixL@smw}(++7;_muMgPY>`g_`L0~qi-yESwVp)kL5 zSW-$Nkp503{llF9_t~|ZgZK>q;C^xUzX0wF(EpEFmtqaOUAXj{06TJBr$_sKJzYKX z!t5&Xr`8N6^3x4>Nyf1^YTs;Gqv)ol*C`SYYSg;rKkD1?PF1JZSM37^sy;4Xh=Sq4 zJ5dJ;Tah`^H*d?`9Ij;>J5Q?w;}K%KQ0WQhO03HFC>tj0&Oq(}<&42qq+`iHFv61O4Ug-LBx ztCK~3$aPDf-58!!4N`y|%qI1en>5u4EQfG=g?U{I! zPIskhPR&>PBFFCB5%SG9fJ0c4$KSVE2r>Gl+YFz*W9vkgcpF_BwqAw)Swx%m=BtYy zDqL|uyy`kMER^z_hbITQANQ|F>qU}r^yr+xs=n!zj^SqYIQs9mm53aMlb@?^TNyqBCc zR-N#pWVKtVv$ExL4${y3bp&?Fv)5I}o!aUz7x}-6lp?ugOJX~B(jmTqK%z>Udx3AJ00`UED)4-p&BjFy+^8&pihn`BIeEM^T<|I zGVT(>gl0uj?mh@hO(;97NcNb_FE_^;7nqL^e81=WZZd1eJb`)sQa&WLngpW=Es}5Z zcBUJfim37T!r0z_&u1o-?_*W z16i<))_Sq+M6&VGW_O!I-Vi+VEpV2K2ic8Mwe~il8&*ESPH_L0)b)v4zpfNT2oGj? zv%nu2`s6xW$`}MKMa4-%zVhxNR33rZtx2|^m7JBC&xAEb!@9qFBCgwrUufql@mH}0 z0p^amh1V6r;?xw-rl!^98*5>e4}mJ9;T$zCQs(){aa3=)_gi+DwfTd*I~ADRv+St zsKoBO66gr@cw9EOQmB!=hy`T(Wc$fg-u~#4m$23rLAcLo_2?qJX0u+R#s%`_vo7T& zJH}O5;QAaC=-GZkEx=*9KN~jIOJy~pF;S)vV_TKDTS-u4$F|Kpq*1-u?qsC#$E-OK z-B=Oz=y@}7^da~tyK=QmW?i4tiH!#=1DXsgk1_R6Wjh>-~EcRqU_OPk#GBIjuwC2lW5M(Emr*4g^}Gb zHNIZQEc*}4Y>CAxWj^-d%*iNLdcVYjjq|L%f9kUOm&w!(AV0HxWueY8D({ky*e0{m-LK_ zcdQb4ZP3^F11;{m(UA}nb|Q-7Lb+|2bfoqn^$XYimlhphLRCVnjxUvs@Q3zlw+3(4 z93O)lHLS+kGu&#{l4KmeL-9eF95$A`OaF{7)-je5c<@PAG5Ka~*sdYZ6-P zfxu&tvRC~ynJ=e?lxMjc$VrnHk%zhu5E#m7b@R?Oc&hBz^kBx9bEW^S`3o;~0Mqvs zPwKhh7{bMl7RTg^A(u->GTt#6d95TrOB0IAreJPNm6^R4g^?*DVZcJ#C*ojp9sz zoAk4X!z9~#r9B-BKc|6!s@_CzaQ?%RZIO;|Zk!5tAGnic*bZpbd%#Z}{9w zrnIyN9GKPm-o7oa?Hal2)sn|PoA1zh?4+MWHqxiEzpT?tXq6{Af&J3R@+l#Rw}rM9 zX(+6$T{vqVBJ<*Oo}Ctw;;GIuZMYWqQK(X7FSB}TR%&|nQj6bGY^g~-dNYlwuS0yF zEfPXz#JcQoL6i;Y$zJ7g6eWFMs7N71#k8X($dd^;7RVnvq46}K2D8c<4r$DoI^*-USn>@9I2lD zHp5qg`rs@DNFoVwx{&wAfOYp5p7iC7{OEDg4%a*X{Otnr1aY*k5ZS!P{r7ruwvh@@ z?K1_-#vqBGixt=)eE7!-Nx{mhpA*YxDw*LcWZadPH27eXBT^m!l7y`CF<${5pQ2+c zdeOI+yVgub#{$X>U5*;=riK0J)fwgkqNYMHr-vH}QYd+TY~|ECHWUDv=p*xoKe^ew zE%jP8Gtke_Pt`Hx&TDQ!w#wAbNlU}iqr|`U5MUFhM4AVO1u`@$Uqt<+MKQVs_|!bZ zU@MVX#ciP-gBaL$Lb|M-ZJMu(E~~B`Vx=Ed_UkYl^mrr3o%)s!{syCW`M>1W;34Vy zv2b?`>LOCAOf^DoF4dT>v~ksWlz=F__BBtYR<03;1M;+RNv~3XGsK`7pSw@Qqi2XX8`|Ar<2v zz^dFR>z#dFF{A-zqGNyIV&bX<*vEVab5iiQpKQ_hJPSq#8g}Aje&0VA2Oli&CS-m$ zI!Nz(s0$)93&!lGum!5VdF224_IuN#es7F@l&NR(M&jg&g!#3I5big*>{Iz&IOeF~ z+ZkN6NInkV{J8xb&yQL81fI@X!}emthk{ojFQzDCMO0AmnT>7xWXJw`XVDvm#As|o z#A?<7+Aa(;901Jf4K=5Y)4Fl9Tr>*o>^gPWDp?Z#@#|%lhN4clq_yo}(QHx8R>HxR zOY_929?&at<`E}BBp_3nOp1s%rK#h0-GXw`psv2a5kOQ;zF>bIpIg>SB?c!a)HTuG z$k2hU)I?2hT!%V5(8#R6MI4a&aW@QBqQq~{d`AW;f4_pss`idx3Z6WyjC(0byJ3QlD?B|skUVOmQcxOk=qb=3Gwzf$hI3eNWy9 zm>^$m_)L=lA{h5BnWzh@u-!<7IvK4eJ5yF@8j4ny_7`JJrn?$c1>f1M%<P>>g zF#F8xS9N!;-CUS;(Gv*u0-_tUCL_Pzs&Nth8oySWTw4|2s@5)I zKx^+V?B$r-=SmD?ngoKz$1y%>=dL?tp%42Dr^~vVhsLcBiV_^q7ERUn&VIfs#faxr z6G1s>{3qc-McG0;`_{EixTehUgSmtNQ^|+8L^Q6L>j$(ejOwybjdGd^7)v)r`4F|N zE)f6vHhVfkhV5`xEiCzxMd!iS29h;fz3Yk-|ElJz&Y`=roPMI0cR(%Xhp%V(^azqf zk*?Gw)mm7H0z@7%J7O4L{GUT+I>2+Op+z)jm^rJG@dlc(~(48G`@pYEaM>nQ9NY=BK zx;g)(h%0eE4=0eur3x&$}aD1|(`?t>^i#ObW`8&!Dzu}Ohty34KsS#Y+5_hfoRr)-nR z2zA+*7|(_&M<^-ZB+8xjIlQ*cpl*Lt(h84vke+bO{8>po!_#39Wr;FH(fIbc62jDN zwu4*7U%RJ&{@V_+oiDn@XQJp@{+0GqXWl^+?P&+{*SLZXViW4rC2ZAo;!C zH`&pwLF=j-33JJ+TTtmTqV7IPl0f9b=JnZ@&0+_g`Nhl~*@o-OemSu~R|gJriO;_R z$F0@gGRc_=$lhFrbkE7D9{)nFq|QnN2egrhGw!6-Y*PMpv)YsX)`(Zv#ZM#Xw$%vI z;B<)-`yrbG8qv1t=RrKuiJIVgV3g|ZjPg-yENE#gRJL(9Y5%+#fC^pr`QGWOk{+Zf zb*pX{C0g{dpI_y2fzg!RLo_yYO=Sa+r{Ry)16k)Zi;o3pjHX(QJ40Pq#pW>hrPplu z#3eFLNG9@jSVZU;;n!W&)~`RjcxM%ynvZ`)K;n+YR5&A2KJKOJtZv>Rcsph zX!>gZ{c|T%6BDO51f90XBN2fxThhu?8s`)+AN3DyQ-J`_7$WuMy;$$Ly`T{y56DiM zUrG6WW46owxs265Kzmbvhb-AMt{==d`I`7`OM`UFO@4QvuQ3{-X++5Dtyd1B=_{W? z;uadI`waEzvr1?eo9YfD(l`Zm{DqQZ8n0tslV`Z8j7vHW;XfpV>`En**PEn4PJ5o} z=|DI+$V#^!OpN_FKXZ2iA8n?_cuyuO{v>X(RJqwOd*x=;&dA5>6E_Il>7VmP9-OAy z$359GDI0hi1nZ?p-^xkxgCD~qfDGD?aYMS6(Q?%8mLDN{V{d-7H@s^22NQt$vhR*(oqJPNqmdz*e8G zcAUM%%CQ>vjt_i@YjhFSuj@VbT4eUH)sZt2RJ4Mvm^Kp4nlXK2{SK@Oy;Lnf1^4QI z<3oYt8Oe7XRg$RJHngVyY)*o1^u?9Pjn|m^2U=WSPj9`bvr?yQ(qRoznsX$2gw!U`Dm&8 z@=wwTAK_szzsXG9QfBDXJ4>(b1p;IV#KsWkzl-?4_^Lmmpj&*BYEiYo(2;=mtpt_< z{B14Q%;whj9XA|R|wKI zqQ>2_Zuz7Hs5oUVFXiRY(QGmrTlsr$mj00P3$y?-JDE72Zv@Q}3EPYcx6n2~P9L?g zzX;zCAGp*(^%f-?iK-h9=D%MMl#*Y~O{z58?X=~VbD&euQ58&L#j}$OwYywb7UuDE zZ$6c)xaei`?KxGd+S{`qcZk=|(dswfR`?Db&k!guDRk51og0bm3voT1m1;5a2dXS- zbr}OpX!`;Uz0;|#pl*?weDVc7BaR>iC&z{21oWpQ9v7y2&Owg;V=t*H`=1h;X;jur zi9FHO*j=dDD{ye?D3HIzFo>AE;`e8&?>DjjN_SWYLmvQhjbifGT%I|ONZrl0+s z%XX^6O*?39@yym*#?FYfS%W$DK9KtJ|RPMQ?!{7G4m5_!W!*V?EV5io+0*nn5k zt*H;p9FTkvp><8_c;9UAgXG5;ST~r=vm!*}^Sgr}=Zpp^x0$oTROpCU`$+x5??kb- z1{ISF+rYMCGQ+xOkZ>wmSXKYKz%55Mdb3sR=FmWN z){rgPjKhjh+NKI!S(eO7-Io>g(+9)iXV;irmbTYb-Hp>z&F>+;zpjMe{L1%iC+xxo zkA*vVEOS>zhrQL5>iEns51%+tv5x*E6`tjh!ISYgNKFG;m_WA>Gp6_ClIH9ht%{S)n96aXJ6 z?rSCXoiCeL9v8RYO|QmA1@v`!A^VjrycE_IGDW5|bOd7Ui~&0@^0A(Fgb#JJ{V}e- zy=OvHHYQYty(__wX%hNslfTo*L>wz?^R7-gvFUKMx7%1bC&O=Xxu(40uvl$OQoa9k zM!)X>WA`=(GdxQ-sB@EXtKM)>oh#=#FIAH5=Aov%;47xg>Nz#m%$dO! z73#RXtj*lHrcVZ+68d6N>a?eASN*fRo3+#_HfDF%*Fw#%9o`wVdTu=RexBnAo2(bH z+hsaQ(@JW4CC<$^2@5d1Og3FF9GlZ{L2lDktb7zkf985vWy>-8u>2u><6D}_#fJ+^ zffxky=OPU@pxwX)VG*?V_)}hPT@o{jeVSeOijS`l{4L^lU@yPOpfiK_y$|iwSuPiN z3tmx{vGuaJo$}C1s$oC8IQlV>l(is-phn|GIGgbN9UgVenQVX=5pbhkH8srbI5n$Q zCll|n?2Z|IuS({*7WO1v`E+C1?;==_x%pmQrBL6)H&QA6YKLMer<0G`2|PX8JBXI2 z{IAONrS-0%zJ{3&Cyh13;EFmYd3lrTlb`_I%wxJQNg5oMX0roMic=?=Z^?{5!Vl++ zbBp@nxoi1Jbw`N<$Lp1KK$~SgzM!9#)8hwd+|G?>d`QV%t%OR|zWb?U-ZqMCyc>+1 zol0n2rEE(*$DCRiurKHNX|^0s&W&5g*CQ!+DV>7iz>35ntx{?&R zeyX**_DeZ0OnjDbD2S>Bvyz?dyhU1vs}6-mMfKuydK^RBN=lsCOraV>h`KH9o=^^_ z9ntBvMOE$${#Zk)Ymh)UyWxwYW44kugzSgqg_*LF2}P8&6QxQ2Ny9ej#=Q?RO5Y=p z3VCf6CZ(avdus>EHP6*T zy~)0i$V-28cNA{szP~d;aw5nt-0gy4lcZ4v=r9Fk|Jc`g*8tJ1OW=Zh&35dFXYHOW_ld|GkHm*zl-0l z_=$V_V7{Xn!A%AxQ-O=97)QppxYY9G%GOWpku5xgyyD4%Wk7m*?IUs7RKpivoE2v(BMQ8ZwCg zY6+htfAtLACG-p!1NYoYd0kYYu?!O!kDxfQM1Ey480#7^45oi!i#+cD9^`I=dD@}T zHt*Z2gkHSFBIv2tO|qM!%5QfS_R1GDAMaFjj@nJs7&#RHbLGh5e}*#nDIkEEkB8Ng zZ~V{(py?9&8x0!fj4L_RP1%BjJ@E&#i;rkj(oGx^M-NSmwyZG?D(VK+L>@65k(ROz zL)$a`cVr!5$G>X^72`#Mnwc*m73o#NvHUI{&MdV{Faik=j*XlsS4Q~vWcp&PmHS3D z3%9l$;tgKvDvtUcCo8i%ni?&AZ|Q}DAYUDpVl*um`Xu{aMcaM*D>VrZ!F+Z~PxEaZ zkYgUbxn7sZZIn5tjNYJvG1$7>-``VVmbpbTYBKVwPI4EbI}CRY#8Ds<5X@Asjo2CGph1ZrtB8FEw2aINW6C zXGr{oMI2Pz5GZT&=l`j`XOeSBgkKg>np$;In(C2rw{>~{iEFlqf>hqrLS8%mZ3v>> z?2t*4MUkGYaH7n|RPY^b|5ZidFy<+JeQ$~8uDC>W|)yaJ+BXAW zhJt99%uxMv`&zBlv8`UJdEiih^EaoIn1$1Md*Cc8OerT7l%U9CQ1+ zweGKz;iHH2nau1XH29s3&%I~@G!^-ljea9h$6eLtZR{v)1ug?3ZKsFNct|V4Nj<%= zBF3N4{QLwyPo7uSGiJdHOuaIheVqWdhnhIzt&??Phwo=&fNf<|+HYoc?>Z7i(aR+~l5ljbQSuDqPAuoTD#l27o%uJ7>3g zLj?zQ$5g3^2k=Scueb=5bYdHQAVS_|_V^)ZzlD3#e=oJ>6n1$tPQ=DiZR$O{>FkjI zEV7W7ppZuIra1vM0aI}TUg*V}cTMfAthv72&z>mU3*yVCdG}6-=S~Hs-c-{kO>$L1 z2THDbv$^lsDv#5F+=I-43_vg9u+jE1The~7egd6lpHq)*2VAZF2nxpL4SK>ci)d19 zPt;t{%W9_9y}0$hyA^{^sHbJoCr2FX2X}_Djoc6NHf&tk0u%zRf$*=)L93=`&A&lh zB$x^8pzLcRQW1{3)Jk!aI4$%#7$+^(DC+flbgJE_9Cu#6nBuJdZ0*DYcd(3LmvvT5 z5A07iny1_J1 zv?L4|`Pj$T#OEcjaQ@fQkoVfGAFn^b>&=?HzJD2Czw5rsST>-v)Y$|ErqMn?9^?e651)u zw|c}UE>8E?b6;8G(zD!hm(6=Uw4M3AdN)730}ql9L+HDj_GkD|sl|j^ScLdRIyf*8 zO=YpEboLC7r3G_##I`(G>tmx8eQ<_|CJA`^m5hJ@kMHZuv7j>SF|AqsARL(c4gk_J z7=Ym7t^hxQqQGl?9O_nJ_}`G>zoZGPxc@| zB3x?^ppwT`73XvoVrzN1%aR?IgEA*SU34{iYBq@jm#+@7xdPA#2T0(=PIa6UMtl$6 z6%H{+9GxFdUsPV14cZP5NtmQ*z2~q}BWCoOy0CqvR&(&Idab%KzKZn5TAyI3X-!c) zOMKk!x_97X15NI&@zNh8dbyOoy2S2eiByox4fFHE#qLw--RxMruNr6bp_)RiSD9fM z4%bC;l(gf1L(uzs*h!KGALfhYl3h>JWRQUdWS(JhS9x4+s+j`jp6BL=@Z*}XH@D7?zI-m=u_gVMzc z2OsI;6g%)~S_$t^Y^*L4%rEWDA+I*6gq(ca5_dMVK+l0`QCX6GO0*3js)6ikNZT_lB$G&RvCpd-{O+C57_Ql!~xU{L<2@@l5BC z-`xvmj~k4it_OM-D5oZ4*uZQ*PWPO-PQC20J7{;6)s0_Vc{_J-60whes?{F1&~0Zb z>NJAjo20B;z^} z8P+x$IcU!gF4kvBwKW>HD-vS2#~NbyqR60IEV??rNm;E^fOTtf$D5Cu}?qA zO$@#^cdNGs9~d@@zIGoAeSd$bn;0`_IB0tgOR61OweMF06^w(g9*Xo_2C3bB8AyYr zWN{@Vswu-1oB?uR*b(b2HQI~vT?!>gNHAhhiyk~s%8F%*o;(B{ETDIH>9Bd<3BpYV zkFkyLy7p-*l+DqnAcZ^-SG6YDt`0dSA@%VIh3?dIT zcD0YJ%Gf=h&DgR$`=tB9P9Hlgo7FmpK6qh7@CD=?JU)l1Zibob9!~A;CE|sOtFml< z(NykHpE$A4mcE~Aehusm@Q7HnLt0J;itIJ51svQ(6m6sHsg{@$5P*iGH@J#lABmQ3 zWvTBE6eq3SPrv2^-yeHKt)Svjv}P*>HIa47)#d%UbHVv_?KeI%gJO?{I=nij&#Ha8 zTtl{B(C4wX&S@PcIL|Inj*|B(w@7+=^;R(ol!*$o$@$gD#Z6zCK;nl|9eQF$!U5u= z7Y}PA6i&&%e~&veKim6lZEN^lLieq>EXNn6(9G}3TKvH#Rqn$%(2H69(|vDU0=Ecw`MnPu zG9^uFzeIxpsKgp_u*-<~K+Jf}(0M8{Ozw;aQQGzGcdby&#?0(bj(#IRG1tkjrU1P{ zVO3CXgc;^^gObAx{>XqJGTip26o1vk;>?oF@=fc!w)w#zAY_DtZzAJoGl^Ye_jZXc zVBW(N?7g#TZ;U!!c!VliYHdXb`Fu^K!%9V`5&_v-MXF+aYA?L3gxO{wS584pYP5}k z!h9>|ms9o~<2jd$O+Me&f1J8pFA%OE<`vG{4#lx!T%)M#g9xjQjK1{lZ)M3`XtcXh zddJzbLg_Jkv|F%?(tOz5)mho0`{7xd*-f+h2wImLp^PA?Pyl&%UU~dsr7wmDWP#gU z=Nx-xE)U5t%|FZIOGhBAj}A5rDFs{inBhT+lY)D1(#g>(japn~skd${OTy`eSKywj z?mn;QxOX#pc>&2io~uiynUc5`IkNb~@g504ZI0O%oMy>;ZHZ!}gEX3gkb+$K&SE#)Sr7y<0q3eAnB+-; z>HQ-u(XAm#$zIrmRms+@>oP=}q~2dPV)0;3O7iPzd)2#n}g!>$emHZ$Bi+c75# zL&?^)R@2#3700P_u6e$4ZAWIa(MPfAB>eT0HSHuICI6Uq((o$f4=*MMyECfY!X$k6 zZs+wpHLR7qsg6mHgVh!3AAVPB(Q=$}^4oq4G&_wI%$Xz&F}>dQwZrc9GUCC?z#`F? z)HLq!lgmYQZbl=ktWNea-RjWP~@;--_IH?H1VchD5@fuhy>* zczKeUY2!1Ko}05XN5-rXszaJ$!b^W?hQ(Lm^y`bYw%@f@^4W28RO}3V~%i_93RMZg9 zCJnBSPqP==4DSdM@88u4dIvGBcz-q+R8$u>zV_}-HQQJ;wV@uPWR*N;{eh+42a-=f zo}H4Hi$URR`wTnPv6ltljk?B5)S(dX7BWDX7Y%H-WO}@l5h%I2T|5%5EGT2qSHAsN zvUjGEt`#JD;4Ar-9MM4e?)T$OF{bDi;YJ5E1ANJXz=_6{zQ(T9#J9Ht=B-IY?N~gP zMAwn$#}7J-pGcV;^NBka@9ighz+}8#nYz>zPK%Z78`$l&l8~RJue-Y$3oh$sqTr-4s@V={$P+GL)*-Cm#j9@mvY^26%I=pe0&c_Im24}b+(e~!X zCm4HZ3damU9G$!f!cY-}sTe82lEt~`U%lX$DAhuqQnYtUb#wbk=yUbnog zm^RK+kcuT=2P1v)`SST|m14>1uQgCNV~qyOU#9EvCrPH~l6?d_j{A^;Y= z;s3h&Kd$<(tN(jf|MMyPZvgp!Hh>H;%K0yzFx*uATQIx(3M_vo#2cYB__v!_6vqXQ zDU@vgdCdQDutSCuel-!pHO2f96H9NB;^`Hn-2EFDfN?<|Rg)e#F-gj@BRkZ ziVONXX|dUV;{r#Vd5oLm>7Rg8)Hp6^e2r`A`2$jq3daRXJgk2L4p-uWeyi=H|K;3& zvfu}tSyb)j-vGUFTref@K=N;2e~!BdJF(n`Pk6YG>a*uhD-|r?{13UON9X_m literal 0 HcmV?d00001 diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index a61c984..10e3655 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -10,6 +10,7 @@ class BpNode extends Node { const OP_AND = '&'; const OP_OR = '|'; + const OP_XOR = '^'; const OP_NOT = '!'; const OP_DEGRADED = '%'; @@ -303,6 +304,7 @@ class BpNode extends Node switch ($operator) { case self::OP_AND: case self::OP_OR: + case self::OP_XOR: case self::OP_NOT: case self::OP_DEGRADED: return; @@ -476,6 +478,21 @@ class BpNode extends Node case self::OP_OR: $sort_state = min($sort_states); break; + case self::OP_XOR: + $actualGood = 0; + foreach ($sort_states as $s) { + if ($this->sortStateTostate($s) === self::ICINGA_OK) { + $actualGood++; + } + } + + if ($actualGood === 1) { + $this->state = self::ICINGA_OK; + } else { + $this->state = self::ICINGA_CRITICAL; + } + + return $this; case self::OP_DEGRADED: $maxState = max($sort_states); $flags = $maxState & 0xf; @@ -645,6 +662,8 @@ class BpNode extends Node break; case self::OP_OR: return 'OR'; + case self::OP_XOR: + return 'XOR'; break; case self::OP_NOT: return 'NOT'; diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index a9eb44c..73236ce 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -483,6 +483,31 @@ abstract class Node return $this->name; } + /** + * Get the Node operators + * + * @return array + */ + public static function getOperators(): array + { + return [ + '&' => t('AND'), + '|' => t('OR'), + '^' => t('XOR'), + '!' => t('NOT'), + '%' => t('DEGRADED'), + '1' => t('MIN 1'), + '2' => t('MIN 2'), + '3' => t('MIN 3'), + '4' => t('MIN 4'), + '5' => t('MIN 5'), + '6' => t('MIN 6'), + '7' => t('MIN 7'), + '8' => t('MIN 8'), + '9' => t('MIN 9'), + ]; + } + public function getIdentifier() { return '@' . $this->getBpConfig()->getName() . ':' . $this->getName(); diff --git a/library/Businessprocess/Storage/LegacyConfigParser.php b/library/Businessprocess/Storage/LegacyConfigParser.php index 834e56d..437e369 100644 --- a/library/Businessprocess/Storage/LegacyConfigParser.php +++ b/library/Businessprocess/Storage/LegacyConfigParser.php @@ -349,7 +349,7 @@ class LegacyConfigParser } $op = '&'; - if (preg_match_all('~(?hasNode($val)) { $node->addChild($bp->getNode($val)); diff --git a/library/Businessprocess/Storage/LegacyConfigRenderer.php b/library/Businessprocess/Storage/LegacyConfigRenderer.php index 5b099fb..430a7a5 100644 --- a/library/Businessprocess/Storage/LegacyConfigRenderer.php +++ b/library/Businessprocess/Storage/LegacyConfigRenderer.php @@ -197,7 +197,7 @@ class LegacyConfigRenderer $op = static::renderOperator($node); $children = $node->getChildNames(); $str = implode(' ' . $op . ' ', array_map(function ($val) { - return preg_replace('~([\|\+&\!\%])~', '\\\\$1', $val); + return preg_replace('~([\|\+&\!\%\^])~', '\\\\$1', $val); }, $children)); if ((count($children) < 2) && $op !== '&') { From 137b494ea4d367834e4c99d53f737fb4fc09f940 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Thu, 13 Jul 2023 09:48:20 +0200 Subject: [PATCH 007/105] Update operator screenshots --- .../09_operators/0901_and-operator.png | Bin 81888 -> 31172 bytes .../09_operators/0902_or-operator.png | Bin 64085 -> 30888 bytes .../0903_or-operator-without-ok.png | Bin 81769 -> 31421 bytes .../09_operators/0904_min-operator.png | Bin 94447 -> 30888 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/screenshot/09_operators/0901_and-operator.png b/doc/screenshot/09_operators/0901_and-operator.png index a93984371b4ead1aeeea1fe998a37bd00abd6fb0..c6e7775028af00dc033fffa8c0428e91f1aa2276 100644 GIT binary patch literal 31172 zcmeFZWmJ^y8ZbHxAf<$qNP~h>gCHOc($a`@Hxh$%4~UdVOQ%YRbT>nHcZbr=&@eFH z;QQ{qjqlf4>#TKt9M)p-%-nU=ef2}Il7iG7?EBaN0N{>{w73cYfQEcT5y8BL{6pu3 zD~@v$Qq^03Jm;ML=a+l<+&CLodXco$=o&VFkS%d|}B?RH>1v z%J*(k#VPV>e*PeJ_)|Jt+5 zB9f+VoVSdkR1hC%HtKw9RG2X#&G?8hQassNF*+;#x#TS@7UPvPp2+^B zd*2Ku1AQrpl-|iun%Lia(Miatf^FZd9}Ft)-vG4LG#l}j!mE#E}nK{W3Ua>6!3=1LU{6|)^uivGaZ3dW$gugEoK~Y zPf76*Npdw)4H+|ec>ojg854jKX!#F6ke}`&e*pm0r~m*4^6y>buXsA}Kci@XbkzSm zqlh5K0HQC&WMq(kUmDw+n%X*8fF0X}D$J1FoUl~YaMX~O<1+@^uo;?wjZE2GZR~EA z00dn5kdHQ|j)pX@HrBQde6E6YKWFeEpKrbf(b4>z;%FsEry;LIBL=oNrQv2{XJe-m z!lt325wJHg<5Llr{C7F>lOUaiqoW-k2;}18!sf!s2DUc`J>li$1+jC0I5=35Gguwm zY#j|Rs4Gy*$03ewTt9Q5Cxf8aEAwfx^nwhsTI zg+vf^GXi?T#t!=L-pHi_H{bFpS-P59Yl>UiAjyL~Lx_`uUEt^ZzefId;x8*T{WZ>Ghv7r<>I!3jZ@hM9D{h|oaYV%PbzguA+6NyMG)wGt{Y+^o zB~=l=7lint@98AaGT#rsq^TW%G#3P1+l&ol9}!JY41M zFj?4(DGsIJe;i=@kvlJELo(A;`LPHJwvrE!C>?_f0ClfBSR7U@Gu7 zpe&p1RQ}IJMC)|OA;(CZCZoUCO~3R(@i`e?Y52b!CXO6pv!~U#{Rb38=^`H3?0~`4 znpvLzK=xlC(?c+kLlSIgA)|1_aJA1MtYl z?TCdZuqYgkKDi!-3jauPNo|*+uJ>8HcBVd=aiPBW8~qdM#;K@$^?W@)%a?duNz2R2 zi;Jj?Ew+_k^cNZ?OPrX)Qn`tl)e020RSqp+=bpi)E|1$jB&3NjUk@OTWqJ{w3=J3C#`N!C&t;TppyNuKZO>w0M zEjR;=)h3J@*1QoWwy`KgfU` z2+pSlH=GN3ALnA&&Df|no0U45M7py431ugZFUc){(35QMMPH1?{TAG&VN>S)6?Gi; z<07#)gQ6JmPMl`_?M~|Y!B;2bAw30kR4(&}00sUP6Hku|8LWyFQ`55{MM#)LNJIPa zgpT1`jNll`{Z)171sQ|fJwL|Os(L+q5oQFQup=iDWQu;l(^1?_(Xwr_~U5CrF}8H_CV@^ zW(?}Sh*OLu8Z2yU(46m>)%fD9gMyTTGq(c26CW<`vdGJ@U_yom-3|*^kX8(8?++f{ zi1ZDKBE;F%-7UWFea90E{x&ntMn0-v^J#ouox9ZPo-Ieaxx%_g`9D7jHYOq^P0zEQ zpd~nWquPkHBNs@efS(Uk8ZQSm1>2kj{CaJFLK{&a5&{I&j3kr_wd5=aDQkVXlmQrI zsVA<~QQGJi>SjxK6FiFwWQLqD!_L6(ROQ$zjW;UH$e(a~FMQ{Vv`Cr}N=6R^AMMgC&a= z#ntz;GV!X5;-zKU!$P&;V8l}|7BS${Ij;rk{c}?NrLY;>cGS~3-<=tkMPY>31RAINm`ZR@)9*mjx5kT zwVG7;9J=?TLc6f}a!)w$F~$cmH;Gq)m-{}yh}%EBfELZ`%^MFZ*qbp9GeY&syLO?Q$<*AUBah2AsdFzUNddwf5-R(zfi0j z1sa18QDT}W)@!{#qm98jvT0Yq*aKguod7@HOQ(0~HN-x&UrZGs9tsY0=|yq-xXVZ* zN_%zrH8zU$YQ<%)5YF=CH#7&AfUK|ECt@LBoAj5=2&RlC3|6VoiSXCp^p>INOP?4n zA)?+S|F^v0veQph2wOG-_aMhZ2ZMv({1D$T0t;n;NbQx2Sr3FM_*EF}n^x5v>t<&} zO%mIs-azgIxgz~u?rDuRnPw3iP2&=+?jl_g=C5p8rvkEK102U*Vs{t4`*0iBNr7>t z=S7q%!CA{B*z=dj&56^{0|BpX-U14Gx3G#zpEK}zo{O4*5Oqm#nd10gcfJwHL1J_c z20(gMQ^XOP9be7oL#mjZvbw#p%fWe-7@5PrKP4w^$ zq%_OXPo@lFllCh+JxTfp7u|+MvU?NxgtipxHa-8|`ZPcDB-g z&iBX`X-5YfaY%kvKBx3!Z84L^lcM`NU4|~ESA}!ZJzReXiZ%bsOU%F9*$MD@@vct^ z;L(nb@_Y%i&T7JFJ>;};H`j7ZVomZ-)Qe8BOsoMSpiH$`U5>};^4D=PkMF&2tn?(i zh4?`=`8iUKk1G}DH=#gcUluJQi2)duOS`>jzjL196A3p`RlMZ>yqnyb8MI8CU>aH1 z+*)GcT%bw9wi%-_KAH3_8YF(6>B3#XlyB;5fZ2q8$iAQHG29KEkz1n45`YLZTz$7b zs)3sve%W&(Gnw0svgzSlSM*?eUTySr+idu}&I)AXK?5-){`HJg#8n#XbB( z1FT~MQ%C?oygEU=$?Y_W(SdfN!FAxYSocF$5p}pmz62iWiO6~_0%LD9`flyl1n&k- zHHYuKU8Z**40;ylnWWPcbF9dloN2V)3YFFzhE;lF0b3iA{jLk)pH|4TZE1<&^m|Z} z`qjSnKL0ii4twDncoPa{bn$7{sKaS4kIhw1r`h&ww0UUEuNi~A)>tlxD!NmG2Uy*r zOP5R4z%x-l*g?P3)3<7Y`p@RsFk1bq(# z2d&vOfeS%Cb(#nwRk|UL?!~oY@b+&W}|J^O1;~Z-ghIysy#KD~m`=rBG zn@&CM0Z&}qDU5kp?>oyKfeO#e>O(>I423px9Ls`Uq&obS z&jr06quk4V+V7v%d^nn7cB!-{`n7slJ?NOsLXD>qY~|rK_6hwQQcc+ZUZvFNx`;Dw@}YTBy{g_Jz^F}d(OZToq7aU?K7|*fF73_S z#g39x_H0eyT6+=-$1GO9{Gt+oSH>_ldTa6gO#aAqubKqhFr@9DGd#VZI_#8~T`t4i zsHqZJc-EEwwdy&Q;Um##I7UIpUO^W2d7%*QUgW~_a}brp&PQXVGuRiO1#_kWf4qfv zU$X%#6SLvpMi6+_4)b%F_o_=5M8~StKkN9(L}5EFOi$0xHjr;WRA)N>pHcd6vT1Y{mGD%l0vyQef7jETMb-9YfGPZe!Blu1oRI#q^wvZ5Dj3Y zz{AvEd!N>F%n5o;^t>Z2bh2?N=nh%vK2HNqW!d#~hKh#6@aZSF+SlDF=K+tkc4#~3 zT=(Dj41{dQ;K-SBxvujpjhRN-n>Rd!W(JBBdKZDthzgvT7xl`~Dvo=W>!cC|R^wDv zaQ5I>_9T6xL!5W-eVz3EdK57kP2}M0njN+p!o2o1f8o_aHCpi#LIUyz(ChyCTLnAh za_E$9=wGW&U%gWhQe1=)B-)ovrO9iJ*lelCt9k8(gC(u^ABp1$+~NvkTr()b)$wZ9 z3{rSTQT)kR`OuGi@oNqsL!!RgOM6DEkZS@#(2zF!HojMafRcNhrDCfnye1?6dg(`h zgd6#Z?_S2?;#W4*?n+s*xTKCJ?ub2})jeMK#;2+}haQBB!!+;um6aTNT?nEV74rrF zqg0+O0{Wg7J0zc|uJ9ARKTQ>GJc-a~;rYWpO{=Agy$*S0-kITAf6>CbC6A_9`(U1{ zW>=uBnONZXZq@uXb2DM~=gqPZHz?kZwyo3d)l2BqL7GPShnBJ`8v>D-l>p-h~^1}NL;M!sY3$wC$1bC z5XLLUJe?yTj#Y^b7sydYU24OBa#g^L{zE)ZDRQ1)x#&gB6Itq)u;W0azPtb zd6>Tzf!Gz!kdkC4cvq5ndn!EZW7B<@AYak4PLv{u^2u)*3hk5rVNslk)*}ES^IHRny9Z-Dg5zg7(z#9+7kCknt%q4$;wmW)>XIW<2K&k(tX7DLB1#*a4%JNmU3+O*iYd0O&bb)Fa$gm|SS^7$p!+7y5~}~#-~Y#WS?K%Xk^v2BOaiwm zYs@z$*Uh(tTjm+upB+_VAFz~K=XzY zcI^yJkj5MSW;-%d9`nQW?D_(SWU<#2Jg%SevM;^@%iaJqCObSY4C!KfpN%V zsi7U=0NK@tgIH)+^zF0=>hSLBLXM`;WGS%Zu5Mf=RqEbvUOfu7V~|MT5x`3BGd)htSQ0InI_c7CcC{B4Ws{lG2l-Sb+#lnn-Ay-qF{- zmS2ImIB<48aGlB}rMuj{h?yzDSa_b_dzN{x%kEx1m;ItGvOdC`WLd)u6CD|Nyu{Im(MkkJxJf5?=PrIp|Wm1e*hod-t3@2cuK z2Rd>VeVX#h-W74z8-7P6iyK_D(5i6$M@C6x24_+-EF~kf-ZHc4 z>V2_yh@+FO1UBi3_*lM5(>Ga(i4;R1fY_zZfc5#3{6bvUm{ujCRpEY}WluN6PdEEY znOdJT<{Ty2$+(%^_8!~ro!ZK~&RCckNz-|-v|W@Ly0kDzxO50a?WDltaO_1$wQ5l2 z@Pfs#A%H_BU2U6Oe)>H~kRAsM zYA#eZR9K*N4*v2or!vV_^SsdI7JM-FCfS|IaQbWf=G#kbk&#n!r7*r5O)`C}s~BS- z4qTM$PK{jC(S-MheRxz9hm&#Jx}O3|?V58<3nur6kyc8#LE~TpG|suhOrj;+r9O*eYj{XW7)%GrL3|p`bkxZ@}xi4(@GKTj--W~y~FIi*}|%a*+Zx6F(otU#2Cg5kZ-+Jifk{vTr@`S7g;EW$q!aYVDG?@%zJ{_dC&ANY3?B@~^n zkPJ%xrFi{MB8&L$G9XhxF11E1e}qLy=}ITQkq}^L(jTfD8MN0VA@eeGJMW9@{@zjT zrg(w<)b_7h1kt+fO%bJ%xgGXL;E3E&ixvq7^I#R$@2K5?QHzD#aIWB9&+j6C1C@n8 z5{`V49}ItkvCFWyZHsQ3SN9~F{8hH@ht8%Bl-<1c630DLu2)4idLemah4khJI+M*! zyIw*pf`6XtSS2Ef29R4p1c9BNrBW3w!=m{XtGLlHZu^~n4CyNtI5c-^eBy@rn`|IK z>U`k);U3UH>zZ@p+qOO1lPaEk$z5og$YRh&ZQcs-&*|xnyJ#GAfQZPsYw~LQ`)EO- z)6hsRoj*dn8&vgZIDvq^H2R6ZiFe|Tatm;BA&dh2lU0rLG=raI02p^De6-T2`CWEr z+p>^lnSFOF0?b=>=Zc`FZC-~bRwv22us5P>*s3Y+SagKAibTx^8xW=aewvgjY1P#56Z*yMh;UgrZ|>OyuxvX~7&=64&R) zN@95w|4GQt$D&NPXLQ}SI^tJh)|F0|K=BCy36M&(p;vw1OxjF&t4&q!au}*^c>aFO zb=Mza)VfdmsPOAL2MS?CG2yi5T(;UlW)a3A`ab6K za;+sL%FLn|6Y^`#%DUsr+zEBhQR(J$A$a0+MTPO<>t|w0tfGl^m)^Dv5bMoZE8I&4 zI+$ZnGen?9HWt>i7qAv;9#QUoz_xXt4N1qvBzF!Y+scnykpY3Pj~veLL=BkDnCdS1 zO|ED?+fJdAl=HxWGr@R}#9Kn0F{p?l94kaLsrq)?;Gc zQa&2pS>=Q%|B}x&023i~GN`Ftb&i^Gy~i2zFO+qIyhHY%Uq9GGQ^D**z6D&+|f20ZT*Cgv55~ zJk4!hd`|%eWbqT-DR!f|25pP8W!RyWpBO4Xyx7Y18Z$D1P~pXDSS6d<%)D%z24_LX zQ=PGtwj_q~Nn3VL={CEh+WHhfpNxhqUH=G`PxWRg#4rBt%AReQ6<_8mH8*vK)TL{n z*jsGTd&97*BCk+gC<$6Izm_FrVxxi5QP>|?Y9H8j_wmM^y_nNxr#{Of+3*MQ=ZXug z^{7Uxf`3qg*kXtRkk)@b`;79Kd`4|ujZSuemr@#FpD#HWVZAy-N zq`GHbvu<0U0|=>p(9oBYCtGD}jj!SmXg^LUlR7=xGKJfD&AoUI&L@qtmZq6O@}9PR zNz&fR-Dcc5qolN25yK@Q(*QQvKE@s+^qiT@?a#H)nDbkkC`T_)wIftxdY3;PO0zA z=bPpT8r*O87reh*E?V0&LE#Scyel^}uE&hN?CGfcbpkL-;Y>%TA{v%mV}r{}H9d`6 zKYy$;velx}bP_&GJ+!UkfZI^~vbV_JJ!x+#aI$E~&if=4S$8eiE+4b&^}-u!IzT9# z*qz=rd40~?nrw>}uorm$$q0$FsFl)(tU@ur5B8MrKj@C8jM%;UUTSsqt#u*t_|zoi z9pM&N{HK$7zi_Tg*}MoIWio7h3cmY%L?Q@1xG^4k?$r-G34_5$he9m%=*@zciKjK7 z!_!A=>*QQR@Dzy>0W;lA5ar!35WjN5?B{}T`VRUBP3XT>!W`9oNsa+ukI#!7&tJ&R zLWExqh0C03DJq0*zz`ee`p<>=QxrZ>3f}E`n8uJozBtVc!G;R^m@=ywE(aOL7a^GY{43KwZ}NgW zxr@`)#4##{;nFTPcYsww9;8hp5bRM^T7>V`;&cN6*Oq!`{6^n+mL>E8R7DkbStt>! zYQiPqfU^W$XE4$Cx^Mky^^)|godU3MKJfzm%&S$PdS5odp8A})gxeyVkeq3t;Wj}I z=5(BQ@L<`?#W=M&pyk5}L!t(HWM)bf%SdIY6s!~ab@@&D-I#@FTAVKoO%?V+Z#z

)VKv_K_h~u>)QjbWTB2F@m&wF}DQ6 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 diff --git a/doc/screenshot/09_operators/0902_or-operator.png b/doc/screenshot/09_operators/0902_or-operator.png index ff6dafabd3acec8a552679885a55c1a6b8de3fb6..fd05ec39a5a5e16e51dd0be016eef4be17467724 100644 GIT binary patch literal 30888 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 WG;E+9 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 hs^N*$1iEM)b$=$J$f1T{{UCxUvB^a literal 64085 zcmc$`bzGBg`#+3=kq+T=XyD}Yn<1a$9cs2c%KVVQIfrK`SxWZBBCqM=g-uLh%O}% z5uJT_=>qtMEuDfGyq$M_3e~s-F274=@4-Edo3xIbx}$}g=L;8eB1;EHdvkVIQx|h{ z2Ujacx3zOk;zUGuiJ;FUHN29RCq2Ck2=UwNz6G6OW*u;QT{wG(W^Lz{I|`3mo_x7L zE7#66N_6iH{8~F)v3zYc(OkfeA7w`Md_xU>P3H!@2z!3;F@LKD)u>C9uWF5Xc$R9i z$CQK&k5+tCYjsvs%Z@9|Kw&T0H6@;hXJK|CfFALJIv8~F&-GIL(;V#2-RXzmi?5mf z`New@Ns52ox4cOs`RBdK)4ucnynlSp>g+%6Uw*pAd*&baPZUn4@b7h(>Ad3KJ0hZM z6#rNAAp{LdUs3w1s;Z8)ovRvR4_<#aQ8h8iSoZMUeH_YZ7CMrHgal*MXbWaMGfG-t(V(XU@- zx{oO1yA>uwAlELnuk93OXG_0&@`N%}IzK;uCJnmSLq&ZooQm--6d;yj3ceSw;9NpR z)bpfmO$XGk-&D^vh5j=I#+R@>>;qF%^yKkbIXRsc71z13Z%6H7yDijhY;1O`+vY+% zb*b-$goMDe!p+-A;)$q*6qq`=Gz`YGa^(u=U|0TB75wqjYbJPfQqm&|syeD;-BT+kVKbTkAtSwf>!Skf)eY!9YgyZohZkw# zUsCZ5jM(u*zm`y?j~kW>q%gi95~L*`wc{58-V8#7jfeDeMl>5V?V#1;3?5ijB z@=ql$Cr_)A@E13JezMo|=Kp%+z7=;nctlN2%?z~UfikC-`QJx=Kv0IYc~9mLE9)Hp z5cQV$@Z+NRy|#T+|3la1!psONoCclqi_fwx0B*S1ll!tU*yxpoiS0YSEBNXrM!8){NGh0`dQi6Z}$HA^XDpHuZ@k5qlbqn z*IfE~!4un9Q@7r*GO&z)+ju$nR2Fd$!omU#evwyIrOAYVl8}&q`8#^(77)noS$|tJ zK&kOEdm2f^z0)ZL6T9NkwYJlSqTS+o*PQ+g zrP!O4TDnKm@t zvgY@m&?VXQ&BS;!%x2eRUhz@-HTXaJvUCgdrN@rH3+pC#<9}+dpd;}K(0wJttTP9@ z@sFaa&YHf|pLHI&2q%Lb4DmK#To#?4Dr6*%sEM;ZKW;R&aL3TE z@l<7p8hx!oO%@iG)9v}lEkGjAdVmj4-bqD0HEA0=pM_l&s?*c_NVCb$Nmqbw9`C9u z$p|1~JLgmoCKC4@^>;gxT|ciFOcU9bxv*d{y5b>38v(RU0HtsfSW#?sWamxl;7s@j z?qnY)>`nGAsK|w>H^j=k(;44h<9IN-k0^v{c0oI;+2ktq$;>p?Ry2Wh@X~Y-E_1 zc)4Ofzr43pTl+_>^CI`kZf6EZWGQQVG`OMhDbZ&cen5o4YZ{ zC&Z{97h#mv!7}G-xAW`!+l0iKAuu}(OB?^t0FS93OCr>?LreUMpB>!MV}u4y=w~*S zd@81ueGS2`Az^vP`&-VP%23)Z;RAWFh0nfvIW{(C#-AAT@#D2M__t&G&Fe>l%g#@GTG`k$2w6DJxzWA^$Dy_S1Qg3&8Az)hKuZ)KAJ}`0XNtDG`{@UxF`4|GR zFSZ{T?R6NAol|r!vNJxF28WtcOG_WgJT?EOcQ@2Dt?+(q;8>`dbnw_OdJ!% zbzh3iF@+Nz|Uebt$GOS|@GXRCiOq|M*Fo zg^_;T;%W+_i<<6lhp5j6`}h5d17dH|?ZM}D2+vyU?&;UgjfjD0R(rV}hw5+5ejW3Q z6-=Wge`m*^n2?w_Pw<(8ML_Z&4(8LogQ-nRA~te7Ry?ZStTpKlAM8(-P}14k#6e(D z0{diabo=1B8_OPlO{v&Tb72Ble;B>(b`|!tbFHQ#%C@O@B3FhQ5(5Vx*lmEnvUa+q zcohHb=Sv;|yC9~im+9lfEB%uU%W=~m?JN-VO-=~`f`J(U-p3k~H4lxLpzMt=OZ-h` z>$~Vw$lpnUoquYZ502J3WZ~cD9LZ7RmAQ?KIHbzwtcQavg&kR9gks@Yhfrjr>ki_U zf7l2O%V~dC_)pE#CJ%fLrbGoqdtg4`q1g>vDumV3Nk!y4MI^)3zg^?11sm$8+fdbk z+vFXQEko%Bh_%~m&0c@!SX%y2N->mfhgO9l?6K@yYzGoMsaCaj&bh?PI9`ECC|Rj) z(gFO-&dO>xDQl_9VcX!|8i#4ZU(Y$^FpNFFX^cSX{AR?agO6#G@3H6o(|(e_%Ey z+`<*B@y`;q6C>&febwB>;p_fD=_n;iOFT?Svt^D{4Uo$qgC5}Y2|uQ6jta7#PQ845 zmmq5zyM?x%b8C(+OORlarU}uaffwkD?tdQFJjj8{1^W$GF4%{nce! z`$BuQew?CSR9t$XzCoI`b%&3e?Az6&-(OgoBLB$GlfXM3|Im4_sT^{18L{YFu3Mvz zYZ~je&GO7THWLYP@|HG}1@~b`dLcG??^<=@Uk!-a!4nc#D}(~B*v2mAbUE;MP;hOv z_6z$vDmg^*ossg%onVCOCGg3u9KWm{=Erttx?c}s0yo3j7dVrQJ|URi72AGVz%brI zE(ZB;cp4m3xn;?a*NwYbDOVj^Dp#$>BML9}hECmTw&2IMdV1oqVtg?A>FK_LchzyW zgk#e&uNA-fTuAGo;nq9E3ks=TPPV=eo>y_dtqtnely}@ja>rp8m3p^9+hu9(o!h6LC~@~)cTvRv!d=U!+#xZ(7&SGWE9<#U_A@CarKqMf zp^#SgXfMW{u%ht;svyGHL}uVS4F7=s4i)<{4{tww_@dg8a|J>%zC5-nJKYWgj2 z8l-KrAx%`pHJG3srN39VUw4m_o44OFb?!oBd`8S(Jo2z~d}xYY$2o@}J6EY&Y4M#F z_HmMjIu^JZhtbdc&2fU0DCZ{nF~h0(J^twqd0{|S98ZK8^Dfn9xHjatL65gy$mHNpj+cOQW*<{ybe`KnpY!j|A_djM&FVxvFu0yM!ZI9=N2%24He9ytqL;mCg2236+ZPonCGO;8_Dj z^BfKwyD*&+uB+E_yE8~Df+jhJHHT!ESvN<^Wa`HJxuL=mB8rQVS4#qGCKvNjZ;}oV<_ZSpwzzP(xHXOjjeCe#JB0% zNPDfp0>VCy&X>t6_G6D3A8w zG;&;tNV`O!N;%_tJ~msZ7ILN~Vq!bj6L(^^b`KJEw`6_nEZ@?LIuzQZ` zl=KO*Hmz;l5p0G)A=DE}1eBA$2n}E4XWI<9%8Tz!#Zi4X=Z3ITBQhimxHG#vfL`J> zdaS?6oebP!Y_+>D@50WVnBOBl;l3`J4!ZgUbH#>0{ckPAxWG-h=yG346S3`FRM=j$DS0=}hJwP|o8Q7ZnC7Df-3i>R&`1M8 zcG@DZnu%;UMfdd@2CMW<{g3cGG!^B;@06+6p@qn|3goqg`}Sr^o);%#fNzH*?5=<2 zWz)oX_~pEwblZL>+p>GbT1qpB!{0p7fR2tcV5+#V^~csPCrs$Y4_#ZKvp?U{D1T9r zu8@sfD;iQ37lS}M-I=WR-t@z&n_l2_=H1);{&f zMT%AzblK8K$Q2rL_Rop1X`*LULpjrWBkHPL6hl}Of=aQzt}dvFHVtQIEv|64<#Xz`I{vyOdh5zB*9lxZKCwHX+=YG#jB8w(Vh78@QlR_b*bvBXYuMX!9uuYF*0D{gpT z1&=jGmnZQi9~@d7EoBDnyF=d^ig9lo*Z+yYzx?L?^~aCf5k_k2C^Ct;eC0h#CH6)x zWf%LbepwgaSqDB4a)EF|%-Q*c*MuwrQ(9=m)*rYtFlka-u2&2~$jj%?I$ue2TNU1D z?MKr0HjQ4Vt;?D_yH#uE>*dy#XnuXzbJ=t(52A=2%AO%SVAdFResz)?N_w-{`J2R} zcEnB59or0pO82ox*F^-L5A0YhzHw}#Yzu8n-$dOVOb2j`c82-yrq;hV89act={Kl~P&cSk(vI_WI-oy2)8AbO zMz3?Z_Td2JPC+t-6x zOi`j#!dm6%A^@^gx+Z2v-5v*zs=6-#`IpEZr%s(+tgQG+9}En3Zt++_FhsHh&| z|6ZR;h`A!Xv)7Gux2UE^IVBV^Ab3s0`Y(%twP{W`-!I}B$x!I?hi(* zLKDWWU-GWd@5@S8$H05&h@Yk-YLLaH*6UWjvQ$wjxzQi{yds~4>PpkmQQl|ibn6`L zKl7`?H0qonRTx7y#P(O|_qsV*mgpCws#K{Fr%{malwfX(K>{DtqAIl^O97gJO~sXXM47k1y&<>lw|L!lY^B9Iov#d+H1(JNAuDiD_M!vwzG zmE9soiGEso7W8Dw{;;7fDfaki+0GQ*LDX3khL|qpDV9ihnbmNmcuWPI1~+W9O!waz zMq9$n8$@5VKWK@lN+}v0wPr|<5(|DkhrB0&#tR?3@FvE(aode^!Im z%5G4o*M8WDBQak9_!9W3k$j&>UR-SWp*BhxOZVz^O{c+3 z)5^5BUBpe%Quxrq)%L@7uTxg`PV7;T^q;)0VF=XFhaZOI?&2;BraT6zr1)?O8 zTdS*l5a=FTgYpLXos^+1yTwlOA|{yI}P@ga-$wT2%mJ&zI#o@*0vBJsBk!Ze=3imxc%w{#jKyZ zN&1#yac<>7-@GS<-zQ0kD}s)XoeQ2~_rxMQOd(K5_pkxyu}8?eBE_5ce%WlMxWF7D zC1&TWx2KwJkS9vp5DGf(cprQP7!zgzI^S)0)K%U7Kx1D&pe9Y$9slKmB66+iVEtku z+U#yCsJ%7!4~o(bYnYnQP{HXHi{i`=vheerezH?x3HaaF%}t*lo) z#Jz=EtHbdbJ?8^xaw@mmMo;|EbmDr4M?<4a1osVl8v?Q0NlvrR{BIHvvKBT@Qk57F z5=bkJ6*^f~L@3jbJXce0gg(g?z?ED%*uuj<@Dw~4YiIZ)C3mNS{rY}sxY6T*Apm-X zwvgsFz@Uc4#tK?mS|ryj?h^++jr)~@|1MSKQ~E9YJ1Gi{v0^R=?>Y>EMb zL!G>%=NnZyCEmiEImeySC4PQc_<*o5Ns`r0{v?CSHx|RYtB>?@5g%3Jf~;VdF6b{E z9?L?jj!k8|)97~Iql&wB6N<97&aBwLV}=N>H|)3ijn^-b@%bLPj69klr|!=JZ{t@| z5Xn*jq7uqX#1iU@O|_cl*IVmHGTuA`V(529N~;3eqjV6NRl1)wCDEI_Grf1<%tY8( z05C&LlobNvzp?`JSy!=dap!kE@lYiparY!aI~9yW)gtD82$%ht5hAJ4F9!Lch~_}w zh)zdQ?Rl_ER*ZCSuDQ%|OaTCaP59eA_Z4w_k^Zb5HasKL6k(T;h+Qr_hDUHPznioN zdS!6TMLW{peYlRT`)ex?>0MeIyYPL3M2R$0x>s@aJV3iJ%--UTx=DWdZJ7Kr4K+@A za%cJocxQHzzVJHB zU7k;~G~7{0566#L9W0~geCk&Z)&dT_Mn=}_l2THNLK@CT#x7ov;ttM=w0%9Uqrfck zw${g+z2?XJV774 zWvOJqTS3XwC|+2rL)CCI{_@e(^8xco8Q-^N5FK>D!P|{V=k#O$4hU2YIHtvIL2JF) z6f&}6%4ZBX!?L#%9}sh1u=I4J-(8#Kj*-Qd{7%*Ha% zjz;mRG|t_|?>*a}sYNPL#6_e^q_yE2PppzTE(}tjf>J3EuT9PFcPLfk9dj+A@F|W$ zb!k_pq_}C7T9KZj{)qSEB|p0Q2#B`!@hCqzEdTvQLMAhW80G8dYtj4Uo$i1HXJ;g~ zs))5+8hWCx#|}lBYE=g~ubPFgT@oGr!NlIHh(T#nv7jBIn2nb% z-nr@~w1B5OUu^~u@BiTfoO%0wPK}W1O<^u@5v6a&JWd#_Al>>lU$GU*z%cZ+6)_#x z1LHof&1Ir}zq`YT*lHLR>Qt&`LtFHZnyPOd&R4h{@ACTl{GeOs(-(Fh90|yPmKq7k z#wpXX>&wz1)F}v{vS`dY%-h&jw+ZZLyeu9suo)tpR&_B>ssF0@M5)v& zKa8Lkl4V>I(laN(k;tWYvi7wFlP|NsK39+nO zdo-O2mDtmu`zVxjXqNPi?BpRb>**<4P+4iFs4PFMi|r70?(zl!zhvC8d*bbe0ROq< z$%*blk879_}O5$aio}@a6ohqed7JXI{c^Do}H$HV{s7tr5oxC$)0&2 zXu+DV{_xlLpelgLNXM=8RvufWjOu4P_O=fT>E@r}0Wb;gFxSE?A$!hZHjvW!O*pM*gL_=Pmm6QRk+^d%Ia|ptiY6(HdW}OVC^<6 ziHG03-Q;5){lP)_ug?kQe2E~*TEe!;vo&GPLuie0{k6;=k=Y%{{rohz=85~!H%Fy3 zC^V-QWBiz{-(r!2@wTfXjZnvb~&&pBtESWBxFa1|S zn2MYh!}+1htq9GgeD_)js_F38pp@{*TlW3IsoNkKrHzufTZ1W$w7u<)3HI09|3;bo z{+d^T)wb14MdH?qyYH4qynLHp!_1DWzCGgD6|Z{h7(00H@$p}CFG$DKymZu=)HM%> zWas8ym6P;ezZ0w{;{Iu=$oFMh2R^d4=S4+cm>5`iZncwVYUfw9-I2-HVi!H-fE%Dk@n()*^Y=sin*tp1T)2s-nwL=Eh|2$1Z z6l6O>tmt&(9wN#<@0|i9zqT4GP|Citq4Utr1!?LA1cT-!GkQ{Orx$4MiX-0m{vNgHuKZrP&UNbe5osP0LSmCJy z>yH5h71j3mv4f$$95aRSrMrK5TQ9G<){{P2{#V;#X7`EPmVW3rK!GytwUPk;^Encj zp8kU*#?=BS3`8bU?Pg|oNWh+&9b;nm&DZI28F1@OG5|0&&1Utfo;?k(OJ;w(X8reo ziHKgllI%01zH7!^9-j3PYKdpX0a}3}0Jn=-+lLBXD`Ye3oN^lKqo2_^*I+-R6hRuP z!7Wb8QJhoee^D4BpBJahF8f!1MQ`cD$BuS>H7O<{8OpgH^L36tCWlDs4ImcW z6@JR};Lg2&@Y}vPN%fh%zYqFzo%?TLA~IRPX}J5}g{48^d;e9~5){7n--TsC;nR`+ zN6lg9L1Ci*D*Rls57Kiw|8ErjP8QJv5=n&Me|0X5_q^il8!%Ft_P=f>5!a3DydmfQ zyJFDgkJq_rMlZ$xqhguzPeDwF20y#hbKhw%n9 zN%$rHPpL1@`2?D;ul?n)aJ|{0;e|eb{t;4DS=opF1sEUcv9XlUuV0`b{)d3pUxC)C zJ67XG?oBcN>4x#85Ed(wGM$^3&JO{0T`6YV6hfv10L%@a1{*s&4FDhb`uf(gk;$a= zB->2o*?jmH-)zA`&`lk1{JQ>B^yQifw~3Xy33c#kkb3@*X574f?)qPE}w3&MSnt&Lc`j zCZQC3-s}2FDKYt ze>w|3eEI$4|62~_|IZZ8|EJ9Z?eb-D6#2pDs5ix?7?6ctcTZ3Vx4ku& znTcPc6jLhI9!m()QMK`dqfQnOE?_;d3su?c9RFw*(B}Hgu7M$~QOB7+2TC=S89d~J z{V)n>0880YReIX04F5qS6Er`sc%ffC8%@%MZX% zKB6hH#+n)Pn~8OosR!1zl!rF&92$(6^GoaA&F^MV@vrGMv;-hc{B`k)FN^V<##WZF ziUK`RxoSOLa}9Vo-L_ZUALN*5>qA-xm+SYIexL2oifFrV+Ay!}FV6mZ-O2DQ07sm9 z`$MFMAT4Y&8mf<`=Za3Y!vxzd*s9r>v{YTZt>?ZP={1xdX*ueZQ6e) zA5h^8&B;VOyF0>f12h2-$RCn&T#sD3bmx3m?w6Sv6mYaFkva&N+YJE%l_GsimM!y@ z-n*?K{EnwzfYdtum=^#0TUXfq-vYM>xMpMPS!gPi#3sw!Pk=<|nrdP$)wbrL*|F6w z4A^$LP0J#bo32kh88iiK7E&cnNr1j@K*YAW&IH?RCHFr{o_y?ID)agX;6Q7q3E);# z61~j6=fu9%?<#g*Yum`h@|1~(fV6j-nN8UUU>Mh>37Ae1ajKV)`?Ee$&r<0WwMq?( zVJHtMyab73?M{_AiN0EH(S6&0d(;x1HQyD7uixwunfJf@FhA}i^nJ4hO>4V8ZB_m|I0vrn4yoAeqCde^9c)@hFhRH zefADz@^JN+Cu4f!S@Weg3mJo_vn;oV^E&VtQllg^exyJL__-7SUyp&*IS2t0QO3u+ zNlZ3Mug?kXbY)ulEzl#hY0}qRfbm=cVPkH?kv&fZVdU-Le%bwhZ>^V0`}G5rPBY(} z`pmjw*>h=m*Z2HbSy-YVfNpT>)-5QUNhyii(6o%Km*^bVz`WqHkE5n)>7)Y$3;ZB4 zDyfn4yY(CA$zVIJ5ghjrF@U+@>reuS9(muX`T$XGt2B|k5c&N9^fcC>pU}zyv1v=8 zonKFJ0G}y&-{)%25e3psT83)v2XI~GK^S|*W6Bw5=_- zIs=ZFxH$ao`rK_ErtRyj+1c4Pwzdd}VyZX{@S5S3Uh5|8hV{F=UB`#qCbhwiZjU}# zujDV+tT9r*Xyg&m2K9fh-0pm>0D~u%U?PSIwpR)-bGwhW^gk|Lvp2YTjk9T7Gauvv zXAXAQJ23!YS}R|O&>cl0@2W30e3pJU@wMtS>KV7RxH=x8Cg?7aBp^wgUv{(_{DXFd z`lFr?9&Yj+={Xkw=orX+u0r5pc{?BhAanKkpF<6I8~4c)J}EG<>wJE)R=*hmvBnP< zBew?RO~t>&vg?1Vp?aj_bel1w0`Tzw9W`{{4+O6p3)>M@-3_ZaCyJ;@89{#32TBUe0=(KKA%`^x!D!l-QGc|s4?SS~gAnvH`TTNV;{K|E1 zk`9j%Ld*BJ$lZAps2U*U0#qMaaMzWqv*p_FY^Z4^z%=T+mIh0Z7GMzT9Dn@T7Rgje z3MeZp>%dr*?X64aEA7Ym*^L?vEGp`HS8m_F?Y7i+52~i8m%yZ);%9+=dh&byOx;*R zr}LJb)b#4rrAS}fp`YvW@BmG43xrDhum0qiAiX2!~*8jSdoWl#*{dH${r?=K-cP1X`$7tfs1}+Tz|Tx*4{; zGR_Q6IWQb8$(HNPiZrHuox?~3xIE0M0#P>z<8N;^GED2{x5*mo+!g!E3iuO_clUp% zlC>5;hcf{l$l!Nkr0J1i)$UpN>lX;e684xO9=jXtX57H8oT6Nf2gioqKHk$8o2gEa zFvnP8k>biJ4?ysbl5#1f7f)w1VvB-^)w+FHjZYkRe_UH5lNiBQfc&1xANT|y zh^H!Qg9MB8x2WDwyOHTIy|fM(WN4q`FU~Q;HA{f)mq}41>z`hKLljE6#I^c06HHh+NCUxUuCfwBTR2e$)BHbsG35g6jp%=->CP3fBIse8}h zTmQrHH2@d^MryosYq(#SZk3vuhlLMnln|W{R1GUyd`q^|>s&A}Z@-W1-Zk{vGvz>n zgP7dyr_L0vD4ZGx9}CCufn}|_M)wplXz!{-&h%=*fP;2LMAZd}!qB#C+<`0e)>u>_ zConL$kV(xk72Q$*sf-<+F^7!tiZrJKI@lJU|eB$)GEJ_;|#0MUEHj zpaYQ-!g(hnV}vI5%g4W+cRf0^DXjs2j(%J>Uqm<{D5b&9B5pcydZl2X7{C1-{-LQ} z#g!-d6kWOMz=p{&4QF+<(at~@jnXJhYJAEDDbYq*WBwK@uC0+Cxg%@G@a>@*z^PF& zl*?%3Wl{I+?LgO>p;ni-7Nha8n?7NCe`3vCriGKiM&qw%SEd^D)tvm4j3g+MFjT%yVzKRR>TNq#K>IXGYo zH}bH_^2myq;XK~9f+37WQGgs^2M43TEeq^Kkt(;R{vEE@bc!jDidT0qJk)@^8-TJy z0!358Z}jBdggt;mc{w_AemqMorzP26%T}L-SxkV$=~9E{CNB%0Dn)XLUYUh&#!LtzzwkNXrPEp(@olPT5-{D89Gib4@w zb};y>^lMK{tH5xF72oRauaslUJr2ss+>z7E1bj1229O9F+Pos*NQ;;uK0E+l0nc#H zWn}hbeBw@1KcAiX>TwY5tL(uWfqoTw4VRNEEK-dcU#2Gx$Kv7}_+Z0Bl|BTyHcP?| z6;*Jcl*v3PHPZjcP^=79(B`ViP7i>`Ev)Pi8H- z;!(Uezo-80S$h^3mpP}srXs#0O|4KO4d5`RLC2{M*w&Qh?#TMdx&ITp0ox(oYLB=) zNjMfK7B05l*(FG728rj{^tBdTI69t9Ihh>&MZm+gtFdzltsIeYKm|?L(4q%HHT#`) z1^BHyaM6}P&VRcM)Z`}Q2?{Bqy4Kd#1*N5!M*o9TrJc*O@tu~1ddjKJ0G^evp3BO} z$heR}*4&3f7rOuaat8YKW1G-oQf8THTc;g=VL^f19ez6%Z|^!_9Y9#%MnG%J!(}4r z=}LHR-U!i1gn*Mid;$Xa_NWKfF`Am1`Ct>kdCfcfF5MS(S~Z*G=MlkePJc?tUd|Pd z9>-%QU0n!Y>iXMmO@cfC&+%ah*n&2ik~t}1PS+QIjjb2htS^OUx?5@l)=%hsy0zNs zJVmNsS%y^I`H`H)(3?uV*g3oAm=l5SL0U9;?b#{HUAgcHoP)9M{vagwjj6`%a^e<9 zv}VQZ(fF)y=$d-~M6e?~W5x zRFqc(8(@bOM<`9D)ADvjt&V*L9;}wX|5z(Yn!8{Q6nm>-;LWSmdj><0ngzBoJO1vAM(S-0HwFx1rj1|Dy$&c$MrQb)55m(4xfazbUQrgY}bKpvIUgCD&Rwn ze^x$aIV`dmET60f`_Fvr2-`9{8vN#$jEE^PE0hMQZy#i(UgUC~3K&4+ZBSB(tP^rzT>e7{c5I5N_wUF{qadqN3aB-kRuCZURo=x7%8tsgwSOFzE`jUn9&PpcrIV0wNz*o5D4 zs;IM5&bz^I)DG5`K`VTdR*c88ht_`|o9j|%a0;UVA1Tf~{fV4as?^u5%Jv7rPm}mV zfvZzFh#pwftAMg9cv>m@+oswwS}$0&eZG=#7byYbelR-+FqSRc2O+&tcDs$@s_gyd z6q^QZ)oJsiAyuePsd_u)*N1vCx}#R1b7}`FRJi4jbD#0ag&&Y^&`;3`d5j>x2@>MT zC$m~r7s-x1w6nqFt9f-_6&Fprp!|8WJv6R&08sO07JEA6&{x!3aVHg?i!=6U%ds}c zj@X?^=jD;IxskGpHr-bc#e32IG}Rnm6!fRgSQw7Q4_I5~40<4cRJz4_#46=xtEV-q z?W;Xa?<2~7g1GSXcKOF{rP-E{IIqyT$qgoXpOcS_UDdG<+G0%(4(d3JRI{dq7MW#b zg)l-p-YJSrqIp47K3jg8q2kj++2KMZYme7R>m)cF``q`iK6^Pa;`$f;t(9YN#U-p) zB^t{$0{NMKR6pc1ths4nGr4(y9udjotoPNcVNc35EB*Y1hdEJ{YJ817zAzPrvePIG z-Gi1Poh5S|#sZ!>Cfi~t+U~fY40xyP$*DzSb`Ixmh3mz~=Ox#a(x9hIyOSWr@rWY# z@onJC>!Mwt7ZsP4a&1r-WyCN;B6)+!{%7LwHIYLeOSEp9F&(w%$Nisq`}fd~8fE5| z=n4zJiH^!ET+A)3n%3mY8n?hW;>X-9qso4c9xS57*e7GN7_E9?co~2Cg;ssH(FwC| z`LO=!HL=3#SNHtquUfWhHr0OeXZaX7p}j)#^>BK=ZojRI^0tqW`pRN%f_r&0fd*wR zxsdns$AniXWiF$Yts#*;l72o%lhzwgrXy2(XEz(ab_QoP{ z+6+q?ACLZ=aDKy-7v8{I;w+@fKygHZCwyN@e(g9QFy4cE&Cr`L}^X5a5ad*idA{yKt1~M|i+}zwx zeXgp1f6_+WyVlh=qB4BP?|BR1iqMd0#l=HsBlSC#7a2ru&Jx$gTi~5WAYa+;&V2L> zR`8f=v@mEls}{k`U8a5{ue>$>VNPmOjWEVuxb+S-j4Q>2X^dEZCdb9h*gVAaC^NXf zm|*AcEaD_7{-pbFEI(IHQI0{ki2rst5w1~1FEZB zkFRk5k^Sqz=3tv9()pkzBT9>V-o8P+ZFfVW4JQ`KP-l|f+ZzNqT1hzD9q##-EJecK zP^)xUg$l*Fw>cET4C8g5P)?UoNKf5wgW?DXKFh7PVf#G=`&MGS_ zMGn{}uT~J(%{`U5PC-u(O*3vg( z3~}z^q2K)CVqto^BpQv@tFno)OlqF_T{%^!Q4s&72|?F@+$5M5SP2B2*}QX5AVx)U z6!JK63(F|9pIS(%9GcdxF_I9MV>DfloAWdjpbWcO-k^(FsC(~|8A&?laH?rq z5BRN>lD<1izbf{&4v=~xf*Uu#qh#Zk(c=01%SuniBYzJJ3v}R4mHqyZiMB|=!jvSP zwL9#5BZmac`V6Zh5ZAuhO0VSQrNKLASRuEVP^^u+6b@WmWjT0BkNjY7iEcp$u6<+WT;urOp6mEG zA*4^he%|85irIikM%9awli|0g!(^b_WZ1p@PC`%6QsYy>K)#!@+Zlgj}@+n_dCpk2`Bh)F#e zsRzgU6GT5h(hfxB%8Bu#_>VWz#Onmd(HW+O1--cYQ}t_8MoE-wo=M;B)Rdn7oId#w z_N=Lt&W?uUDMThQsM-x08lu(qvoCLtuAWQH-&84yaY^_x0w#$Fo|3G(O2#rN%VnXyj`I&x^7VV~I-@w(~wBSd{;NA;sGi*`dzag#d!AtjP1o8ZE;>`KZib|3vM z>M+}p)e+|vnOu!ripL93h7wGP&H3)S(0#NbTTl;s(%6MyxAf^-3%b#_8Mq*I+&ml8 zFkfesKB@ygbPgNefktd$^#$#WWoCz))Jz6rB@eo z_8Ja$zVomP5287t``C4vNf&fpNmNBNP@4P zOp>JDqk!%w?i57dV#rkHAUC*T%D+F0^GjaA4Muj|8M5?TV!jo=50%a|>1MJ|h%2~5 z%1!8>eZ;<1HqEzl#fRQqo z1j*sF`ooy=YxEtICofV%4sGk2Z@_s4zF3ZQ`$||7^gOtCvVHI`j~5zP-LKRv>}`w@ zpPAlywp?dx|HVf9Yo&L?j`131dRZLb~yk2DVI;r z?)}TV9WH?t(usIjIXS7!&(CKT#MTzZKQF;Cr@Pcl#J_*_>P+t(SXXPHm&-@(fOk4{ zxVOm|eqM26CaR_7nest0u;#@&WhO(luV24bl}va(Za7#_**2|O5E=S8$m8AOY#hYj zDP30R1f_5NxPOkLb1XTtt1q>J+^WC#IBjdhD!whuoh*{iGhr7Rj-|YIC)JUxoGTgU9w9nV`#K65KX+^&qr_}igYuRMLavPZn&VU;=j);f&(TIv_kixa!{x$6bfy}Z24qNo^t8dLQ2C{@+e$ipv_l8TuEm^^KGSW8n|+xGj1Tj2Oa zL17`n&AO`Fxk4x@b9IZnWi?u_;Vk1T!FkrY$kBN>%T&F6yRlC^`{X`>_Yl(g>-*dD zq=YXK2pkPL$@$BPf=L5+-0jCcCEwus&4oC%{ezfCF_YM#sRf4yu*%az)z~NUHA!$o zQCCUd1mxDSEXMlSX`}^ZqpE*0v=TRkruLYw(@J!CTAKB{ zxBF*uVNsk@sSQrrP0z#V<6Rx!uS~-0#Sw@)&MU%6dLM5V0wW?TA*fgCgHJo&@?_rH zP-Nq@X+U&{cwH}2RGt24su!$~6}4l{^YMJu4Xb}c^Tuk5O9iDO&(w5v^T)>Yz%LWA zJa{0LtDLF@+zN;`^>;h+fHv;9>4sCqW!!Gq?( z`?4;?iog)%fv=%z{{9UYF2b_6flIs8;u7@AOr#g4{kw%22XG&xLa^{XMqF@1b27W;O_3QxI4?TxI6DG z_mjW8U(SbfKAr2?i)3cnW~RET`d2mG)u-`K01QVsRi)hn9R~*VS;Y+#Ki%+?nJ8z~ zm?$obLVj@5CLOoxA_H_E@?F{70pGmbq-W(s-H2m!v0x!6DL&<0!Sh~{T@hg5MA6t9 z^;}3R{tBR*_&xW=x#_&Z2Pp5_ zYMWnChCG6GBhyGuDxk^!k}nBRomdVjll_MDxuuTZv^?$$-Ca)6L}ja{cr2KeS>M{O z3Aa5R)ZDe=Q|sH}bD022M4X+~;jlyr_nPa)M+2X5)9J-YRaIP?P!^)i(TOj$J zro6pJ4;rn1lN=V6plD*j7bsP6zCCEW>ylNca1W}`^!Rjhi*1~znU;R`qhsDXDA)CbIEDLZ4fFqMr{T*4*doh^9GJ%OODn*LY%cP$^$*{At zW3l-4o-Igr)_Fj=noB%vtb=V*+@$fn_^%2kF5wb$8+<#Kb!>N23*wkGn9u-FbSvgP zhSA+{INpTX%M&qsnBbsC8PLZ?&hE`p_GdvZcc%M*XK*k)x!JvTk9sJaRO9%FXxC&1 zkL9d;1NrLE%4t)J4HITLxh@`V0XogqEHTGrIfF(Fx?Jg%lR{xItSv&i<9pX6i=p#c zIstb8vjDGf)vs{u1)rbW-yq-U&`;g06X7bhxt+{LbJAuNn^$YO-G=rRX6a$+itv=w9Z8>L>OJmoma}v7cD8@{h z0;x&_3tAoL2)KwdVAH#z!4zLKWAcaiaI|xt%jM2VUiVI-@r z{xO28g|_VNA4(RUW!T}U!3J5^dmPhnc`h#UX=PDr(Rw>-XS})*COW;!PsyDN!96kpg{~m*|ywfgg-8jtINe%-@E z+4C8zY+s4~>L*w7`lY@bw3?HPC@gT=sOS(WUSgstG6Hoi@5{KQwuG!?bG%V1UWkMHw+ES8y}if{%2fa-LKrCv zE33)<-7U_0t0--)X7^h`$?dX!x(HGr`bgtZA5GcZE>AZ;w~Ks9^Icss=u8D}RnEiW z;^M@_#Un@+5|e?i;%Y8mB{X>4fpg7D2MXd_ZFAy5!Ixdv6C86J zyfw^kEt5^Bo^ncUYw_exg!IF1gH5;b$D59e_p>)NZIf^rMuRxei~wo@%f!UKr!CBt}aYcJB^)YZPZMu9FQp zY$nW?YX;ri5582bJKgsi4$3$C*W3}hMQ=5T2>gpV;8LZ7ciipSTzDp6qD4hVYmR3E zAC&FZd)_9o+X@*DCr{{xaA(u1RZ#+l9T2c=cXyY=?cxs#J_l*<#OfwL;Z^9cJ^Z5@ z+|3F^h#>`r`F1(~PBmaO4<_KwKRU8GJ*(S0aZnO?Y)}9mciOE11=;u&tY54Z1Px`a zp843GMDZqu$$^{k^W`KWRjM%!s9DHWCl+p93e&&RC)cKy6sx5Qql`<;I`FE*7YUzD zZ6(@&Nm;NLgX5h;L0g4byc|;TNY!g|fY5UH))#;+rH<9ZtHtUu&T(h2Te_HUs?@z4 zdgmY=6J)&<8ZW=R?qFU_eJvTe_f15QKB-ICG6 zGfnOaE~PAE#4?l_g++r24}A8VCAJ#sryxD|It$HEb`$&*&G3vAB~}=G$h=msFLqk- zY-+IhF=7 znrhR&#Te%Fd}oCMP?Dg)Xk3m$Bc)(9@-x6bJQ8%-yTgPm6(e!t*KmD7j-A&r=n z72`S9xAaNIqiKj06}9D*;|5YV1lMG;xYv!7aR-Y*pd}NZL`ZVfttiFuo{8!Di)ci(@2f{g;jHU}_ zr~<&eT*%H9u>NLoh}3zuK-G< zESR9~1we#xX1YHRC`Kw64ILd697J01KyY1?b&1XLl>K{7F*P^pkDc0y|iNu>2fT zYKj6Y%rL5nCSM>y0uDj!4M(?rkG+yxJ-I3>u!F$5#{mboA$7uOV2J&^a%h@ii3-O` z?GT{lr|?bf`p-!6cXq~JDbTvl5omDoYBbllU)De*!!_%yefFHo`I?I@CSC&m^+UEk zP;mw&nH2p(4I?oIV;dFu_Uavd;?8MjtR&!O$GEy~G(08rgXuYn?K3-UxjW)^)?X)XhRX%Fr z(WxnB8ihbr5k|$^{yFZfnX9gALzZQ$?cEj6IMUnhO+g*RcoFb$u|_s6J%N0?)$fKP zdP1DjtFn`4jZSM~x6pklZ+#%(>p#B%Oe{D8w1-VX$MfVe?s%}_4(k2J^L*gzrymNw ztcFI?KY;*N*VdvUA~N**qm3u>6#|0K?pXr@0^orv?ds@KFJ8s#>FZMw5w*$mCZufrP0<=tX()ZpY4YeFk;kuI(EZo0_0gKfK_dasr*2n`~iWeCEK`Uj?qjlrRw~K!Tji^ugL64 zV*dV<>ElisQ3=`CF@s~P%u84XB|TE3hpzNvZ$c(vQRP^0^fuH=l+`U{3Q{b)8wNYq z6?}%Jdp#n{JLGT})(3!Tgl3_Qf_%-0rCelhrnCR2IxbGZ6!pXmz!P#)Ofrg=rDUO+ zw=`J^h2z+gQn^8p7w{TUZw*Jc*+uILD8+%o-1(Kg5|ykpqBM+X_JxBkqcGq*X#{vg zjU)&ISAWux4Fg86G&prnU^!mwi=t3*o^O7!#6h!|UdAqZ)pKJ9GO-Q@gKo6YEes+~ zylBa;)>rXvGaJ6v<8X{?4=dmAR7NsPlhhQ24BW`T~(g=qI^?4Qswtw*wj5BAP zhar>Ky_}EJQVZXTM{YM@=bgg5ZQR|Zc9FZ>Ts~lhe$SAgmIxlx=(Ifr=nGIzR@JNm z$Mq%u-6D-hz(hfHAsBEnt8{hvRv8Q7nsy( zbn}uKAJ$p+a@}4Y&CAfb|K-7!bq4kY#Mct+V<8SweJ%sxXm0bR=H;Bs%WJ{w9Y*C6 zx^xc6?1|geAiBk8y7(~M}gSYH8vFE&Tfo^mj7b|EW1Ht6s zsl;%eJE7Vor1uttaVf>sce!Ryn4V>qxYzSea&IZ)kbJ1D0~kfm9!**NmQ}~n zFJGmFLwuT+{X)u4`O7$&Z`oezC@#)GGX#+kf;(d)&u8 z!QH7s6T@5)Bc}_-sr2p=&#_`6ziVaE$h+z9)5YRd3?XLpnj|sFsZ$r}w(ZKACOv)B zVmHRN{%z=fPcde&*xRW53}n_AokbCdvt}h$-Q*%rGEpTO?(W=fv!D`*;Sc?5`!Zz2 zl5oQ*|KS~Al7NiOe~>E8H5WBseOcnQks?&zk^!uTDy8b}cqJ5PK62c0IXl3MAC}1Y z_i3136xjmj47)cAv(Ev)Y6(R!+qPSZB;fq57`8UuB!&9mDpK~XmmuQ(t%C6UVK%x1 zCm?Yblbv<-dc_1KMu3Zmjz#q)DKJACv#3{W5^fbofX!3}{=Hfz_Tz&ylEGYqiC1H4 zKsw}v`EQ%CECXT5e=i=6+5cC}YX0YNA4P;~&f7Jl)cv+J`dev<3hDQLQ6 z=6E8w9tlMJ_w;(GKTvt0nzZ}01$)N%17kk$1@E>ULh20q&uR9tKnP#&Q3Yq?I`b90 z-gnTr5A#4l`)*)x{q#9=4s!^e7nc0*MKzBe5dllY4Wu<21@zDG7>`h*_dlulkGG3OjTnQH?x7msKjp96hda4uUWFwiwQW@a@N|7b zJQ5QZADZ_c6&Q$~NfH|wg8Y)XMl+L6ck`jxzfSBJo&)M;JHNpWcr!l-_J5c6G!FUi zfZ(q`3A_AdnTKMr1pgiKy9M>XLwp0&{`dMppvLR}jv)Ss|No&nXmcfgsa3Izx7`=1gO+AC=LQ;6yCG9(RNq^*2p-cs;V2fu=WG4=$` zdY;(*N>&}WiPzHSh}Jn{?0f5tJ?-zQMfy+k`^c>XG0TENcY0JC! zxOj(-^SgE&UWzO$vGA4aOmU7Evs1R@5yt8*9a_uYf8ejlP?_HNW&|!q62aO;=p<26 zT@TAA2lUdO33t7a{%2Lm3c5LK0tq)f8m+bvBAMQ5vB9dE^{jCc83ZBt5R`aSR(P{*B=KJ6@Os-9ui~8i!~wT2q}1_1Z|CSiIvCI|kwRhz z4S?xX(w-eqyFN2kS3Zh8$P*v&&*yLtvP969h%|6~6r0!JMY8x9?L1_`B4!L4xnMzf z+EB95Fa>{&fp@xIM7kb8Fc$~~HMJOEJ^@p1lb8KV0)U|EK)z?5;KQ1xSb@8r9~Ozw z>lgMAV`>Opc_A850UYBjbThaS-eSkdin@vt>6_DYr ztu5<*4!mHQ2}y)lAor1+-vf^^_;ghbSo?_r0a_`HR&S>{f34!n5}5%v@r*Mu>*-h^ z=;qY>4g|_BRqn#aa-|o34)694T>o&OTni`Os>Wc)id7&|Y~U^8J67uwEcm^t=37I* z5TXC>WTf`oC9q_S17dA+hjcf=yGh&R8FIY(_2iO|E&*`a5_m8dax+!~X?RMpNNWo` zh}iwz5;21~yr@h5%^6m=MrJ6mk-$H30V<~vm2WNQDp!&|00kJ5Ks%EB?YR%@$t1!{ z6@=Xsm=7(IbjxRm+2J$ZwP#Cb%#uU>7c9=bC4oEaZIjEhz?mZZ#e*Kz4si05nCI1{ zd5FQ!Fl0~;M4k&VDOuy0bnue|$~}^xwat9^?lvIMnjim9?0!DO@)>4k=5_XBhtGH! z!L?*>9~dqB{XcDnUviZ0YRq(S!s+;^rKXe!-Eloc?7L1g}zxR>X(rN;{rl>|U`Fa8ZS~Q25UV1F?L%uAQz+&Y}-& zg#g48B6L)z^*4dv<;(kjF-XLG(-VqB1i0YvF`X&TDz$j8nE@BtCjV0;^jvhWv~i8< z5YFq~20Mo*(`#^Xc_jCb9%B%^N!oG%rvC|i1`<)@wY$N1y6|WIpM2C8k;m{gyW}ss zCxOEkz5i)9*74p+Yxv>ix|Tk%{F8a{4*}bLp)UhvTh^DSae(8m*Z()G}Mh9}N*L$@e`H)O< ziDKNYxKuK8CR(2o_PH706;CQw7JTJ-&cD3$XZ-v z!v$dAvx@j_vw;dVnV%(mrE_effyxM}>ZSjW;EJ^|FkpN!C1@b4t}P{h#KSsWfv9O0(8 zI24Me`-DDamEu=;ohY@ceQ7zIX-P$Y$YG5Eap7#Z8=R7m2EuIuD)t9pF4>LUrUG@0 zKNHWT0;Hn_X*JE)*5nf%z4nF&6~Z%%@?M^7`8VdL55t%78YDa?jNY50R3SB|j;d-T zRj_kL?uq=l@FgyaI&TK%?*yIY%%nNi@SvR`;jR+be7O#P@|{qZ@`@`LDlyqR>bzCN zysQP&FI6yQu263~QF~2kQZd0dB0inP%?3?G_)ZF|H>^M6D_g>L!@WP-zEgW`Lm?d`xv_5e}!9KUEYlsdRB z))rE+Iu+>=2>-|qZhRxchO9&++7nrQxFTfS&No%#eF=X0CJjX`bUlTK*T+ONBhW8YF)*HR@T8qdH#WDbZSSb;CQ_PVj6=FudNSi}3OWf)zv@@g%7lsf%0Gys$NG1GUtK{De#XN z!2SX_4l(YocB4lBY5;7{11ui@9_TC45C`&;;DSkf9OKXGkHp`00hrYjN?IV{Vx_x` zL?XmbzWC9dkK6*dv2=`2lP3JO9HP^tMU6aGS!fwV=$10@>|V93i3C0^_`LB{Y*gmn zVO6YBR@P6w`l^IjaprKk>Xhoptaj0i0i zth-+1I2;*<)NgWG2O3FVUZcSLnGE%i_YL4J9BdawCeNeaMJ&-?XPQUpEK&kDL^Y@) z0jIH%y2e(UE)Yc#A|49?Wf|lo?g2;t>D~l-B{I(IsWUv}S$CJ}{5CubAome*x=zfA zs>Vf?VL^oZU475O3>-6g%bgd1^YRbOhc(IYL8AY#GP#k#GfC3Q>Kn~w9Yjx} z0!lL6cF;wky$&p|7PY4rI~C4+TmnIl7V)VTVSnB_6;`Rq(K!R}M2Y#=c}8eOt2-Oi z2xk^%l`h3M*xahT96-dE$vci+u5!tc#A125KjA-0v+AffzHh?UDoap|f;T6^$$I`Q zmV-kGq89Pcfw}h4<>0EE%#@gymi`e{>eRKr9&FRG072?$Qo-lg2Ap)e*V%Rk5`aj% zNQ+=BMFj6f?0lU>um0K>dtnCeVq=w2Qf}io)+`7$1&_vzHMH+n5Q?ggKrm*b_4oS4 zSKy=U##>r$Rs5V1OpIsBh7GJA@0g-y>L$jQiZ`1aCQhqz^KS#U`Cx5uhE;dLj1=uZ z&MK6cl2-lW?N6!}aWZ|}spF6Y)Bv z@GRu;7h_A{7#bROOt=&PnWm}c9*1tTCe%~8TlC>dXtY4f{mK=?; z|4)V3pllr&p7_Bw*;)mx5i`TEkt|QRJ^`2cz1uS7CxfR^3P7u#;;Olb=%OZ3XDogU zP2#g4x|2cWY#k}MVt%hrY#5r5c~ytnRV`krkY-69P!1P<1_PWIlH@I;>8f5667y!0 zn3a-)aB$}t*Ey-z5bv+XKNcwg{}>c&yJzsJQ5-$_imCH zcoq#8Zvzr>*{yy7A2%Vmwa8%R@Jw>xxPqCkLJ%ziLS<+IAG;q7e2jLZqUq2_f=Ktu z1J|C|6#2?XEICP4Mq&>@L1c{42wa@~<6DgAr0+bj%Igs6DTSHZGz$SQ{@aQIuZE+l;!Bzjo#xCD_qsSM9uHGct8s zmhq}`U^%TWs4da3Z=^MWnJOtr*P9VF!$UeQ%L2;;@0T(QC8%f=`uf5)4aCT@e(a}z ztkt#z+t^aLm%cs+I2xS42tRTBb2mA)vADpg^jz#g)~ot zQ|gAd5y$2T-cPY8zM0VmQz6tE(&jZvb+q3w!kCFRoDJ+8xBV1tWyd0}8)aN?JqN&uRqToKiEc6gDW`nlmNPFk5W#<)m2mWQNk8u$wCZIh@&edz^lK{H#>nQc0k7O%Ws&Ax zbMuh{&DT&eksA>U*T=ueEc-xfNlHatDnEr4wSDDpVfshd3ta>5q>2qTE0Xp5S=|tp zIllq!j+S;)!*87h+>QVQ3CvL0Ryv4g3y*C0s@kNpI=5|^a8U;2cxHN@@@9t^VL+Br zVaVPRELZXdvQDgU2@_DSup7hg;v)g4RaK{q;@_{<$l)4XM8%o+T6_&yJ?%mE9+<62aX{ z1;pDkuF%eTy^X*)OIF9b3a}3zdGl|+prYoR3#N$x|ARjyOviYPzMEe*Ryn>A)SKfj zvV?XP|1yJ{fCwQVOOc7H9<%EM2dKOr>q7&A?Y6Sr+Im$BCl%wEagxAYv|SR;zM=zc zOrr(HRrJt_AeyLB+_uu9)QKdjv{y3GGOWJAUwz}SKYl)(7{<~u1An(M@q&}_a#^qD zKmL*&>Hs6736+XYY=H9~jSrn3a75c^x{~ybs;W&vv2-B8>CGNf2@GqO8<4}yK^G(AIHV^< zrm3GXTSLTaH9>Y} zlHjVC%z%}ao}UF-FWH`HDhbz~OgrSsg{NmpI*PH;;&EqRnL`iTBQD|26i@M(3@MI- z+=@LSDt3c)XV)V6L+^1g9Tc1D6vcR9vIVxiM1k)lgcC~oJM!LBzRd0tWyjF<%Z^IW@S zk)Yf=P45k&j*WIDEnT6-})`-gYzs zJ{)GV7mTytVTui#P7+Yj_720s>k`~}_l?f-KOz9x>WOh<9Nnqp9$$fpe<|BnH$Lz& z^U<>ndJ$sL?Wm#aR}TX@LO$m=!El1!ZTg4(7$uUil}AY#Od)S~VO5lKN*x9VnGUj* z4-UbazFXN!!GOag>_h=pe_8$=$9!=Pi^aR|s?%i4VD&FWIFqz$&99#~+ zp+WYL81%4DWEd_r}LPvZ511MFYd@Bgo@Fn#~={`}4N z1RU#s&*4XHg#WGnmmdF1y1$eFc3}Nqw)snpe~Zk){Y?GwXZGTw#rqUnDFyrUk6-<4txTTGbLgi}><^NXI&Q30XAJXXA+hB9SMS z+3Tv-YjXOsqE6L9jdFWOg(O>dkHqcdxMTujQgK$H;p?VNB-6UO`~sS@v7F{pEKM=Ni-JkX32X%rG^*3}V#`>aln6o&B8_D-wHQoU1Ijdj| zYm#hP>O|e5UlQ-JM-c=eC^oP^Lu{7wBex|3r3gg9$Z$c$i{SDO z6{RJSwsqs~u20_zV6MYUi}?IbeRE3!`*`s4$we@AXX9@t?z%_!c0O!4Kk!mG)#G(x z*mV8vYzRnpW+PeeBi{d-c*{8?^jN)+2-Hj$bKL%}VKPH}OqlF#(Hs@G`R z7Z02Qo_%h*;a)?{0hVEIFWLV6{rXc6Tj-`v;9&-+DP{fcpp%`djaP>&gf4w@m!HJ1 zKIuX2enx9ca%V9W^?;NpALOghHZQe~xbl2CbK0^<4-rtAG%`l+)bJyK(FT8FVaw1p z!og>-vwpcW#$wZ%@n=z{vV0`vS{#$s+__~$dipxsgLn$bi`@Xrv)vUYTBN_VzNEXD zlH_IVEOGT_Uw{4OQ-ML#ZDnq?2hw6PZ!a=Cz8<`!Jl3*#TvRPGY3YVPaa#YY;wz#5 zHAQzIW5wbco-)L`Y0FK+$Xh%RB}t(|(dcyGRgx27U95chOs=kJ1iLN9+@a|F)QPRn@g48OSBFKYn2`qM7G&pj zld?3&@6p+1W6-Y=c+W6Lbwi)p?7uH9-pwncqp%MyJ98>Yp<2><5Dq-neXh9Ez;*Li zqGkr7w!-W@PfYuCyL$9$Df;nG=Y8(YL7(Euxa3U(!WaWc!K5-5OpMH4i^GB6Y2AwR za!{5W*ykhkgQu~>iM=B@g}INX9o{&mk%)ErL3m6W=sDs)=jUbEf_1Is8`$f*iM>A? zh>QpzSO+3KT?fqxTD8=V75QEZj^_1Yb7mJK zV4QB=`P~Pk&=H0%)aFF4a@@s^h504L%oqk@@(ktZ|5X_{9lJAbyXC$YcT$`voagvL zROv}(OYkQ{2k+8Tc(WwTy(Q@i&~?cc7qlz@zlfT!5hxONo(z#+1yy zH^0w^XD!^9f`eT@s~yJ^^(m#X zIS!v(EgoaKV3C`%ii~L7$}67AsZ>TUPBlfjjY-d(cG6(iG>bXn$@!wPIwNr=cvnFr zjO-ULiY$4yl_3eVs}#45mao5|J;=L|6N~fd8uwl=dHwG_PZfeX-Pel!<1x*CwUDO3 zVw-woF#(O^Uv--@aULj%4pbIX($miEhSSZqo_l3!fzAfrl3jsF@i(qss24x}=#?mJ zErP46lsE$OWl)n3DVrS#skeGVZd;c8fx$8ju1xvx1Q%T!jxXj{z=;jI5_f#XP{|b z$Nc>g0XC)K8`%IBRVr*Ko%cm02>^{dJ_kix=ChA+Wtw3upKi6mrqg@aNdD+nQxW*J z6^wRQ&kdn-d}p?)8Z<{xFf@J4YQfpXHv6sfp3PzNI)ZlD%{nI0WUuje`+T3 zeDr3WrI+Vj0Kc0%uZzCxxVIErMhX_nt`)pftOHFZ1=mb}e|sq{+g)YW?ybr_&Z{b^ zSl}0sTbs;dfIC4aKT@Z0=!gtF5cgy|4+TeH37(oI%aqaFe!-}7NwTZ23C0n`En462 zJtOvn|N>+a6 z0VtTo?>V*t46IBB+G;0LF~mZu-f~qusiMpWIuE&O6ocfZ@rXHvu&CX=t@_zoJ2M=L zic3MHhdt2g6W@9* zNasXG?s|<2~n;O-XYt^7?EPr^ZvjY=P(p9GYe&tG+X%4aYFn31T zo^ZYzjx8TeAe~hy@=W_N_dZvQdCbC>nfK|RI#2Xk6G(9C*ws5((0Gu1&gb5mC`>uE zgANyE66K28?tQ(c3U%9Lifb}}y=dJ^RGU3VJ*gI}^SC^8R~oE$Cg)b;X^Op8*(<@y z`&PP`vk!WLoYLeujBE0%1?^Gux5P7rnaJjT;Hh$!POSbyExbqXldeaaWH<8 z41%21G5H=96I6MXULR5Fe}ST|{vp`^NauJlu*&$mTCh5x>t~~Eu1E$+PymU%*@%H# zkG=_n&*v6E?qz?5xw;`4j*G^+AHcDn`MPm1px?5_lxygdsU78Arm7I*cGmW^?wCBZ zJg}8+x&qo=`)8jybiE+r(0;9wM^8{ z!VBB8u&Z#~%eHMaYm8QviIl{9{oe6ZZ;>MXc#D9qYl7`;-ubnfX#+t+tj*d8Be>GS zS|xaxHnr^(%TylC$13pjv#E6)ZsX!3{daxdQ<)J6_`r_kwIzg0+CTf#2@FKTUWUbTvgUk^tY#&u7@fWan`TOv`iNNPaT4v4a|D< zsd2iMY%w7=jQc%_B=kSgg@6)N#*(7Kq_gNS23Ujj%al_cGb!_3!H=Ct_O|iq{*;cCt4+sGzD^8cxUS3XIndgjDrpBEkvXzo| zvp#GzRnCGt?lfb{_jJ7q;RVKHn+)9Um!f7O#Dd@D5j^m=Pd}~9e~IQa$;*iMfw5ON zv7_ZC8c~;KOOz6zfF}eHMo9rMA`p?YHM^{6b7{KRYpX_`H|ODiO*kKx9z=)3{Z8W} zxW5HFoSCH+|yH zD*ZJ{S6v?KWNeFHvoYxCOYMfrohQI@Ds$DLwfISq>5;8J%(-ql8gI^@P93zT;bbRz ze^JOJGb4tBcL9Fr)o;y5gdQXd@NSo&znhXJ-+kwA>?|# zaMb~&pT3=J2F#KDaMO?SlSTRmHB$`NuS$%dXNL@4miJ6M1U{2#1kxG^S%K@=m9+&_ zNwzPNa!OLm{`h5@zK{uD^*xhas`#;z;660MQmymC9HHB34DAW~XFuJJ&GAAqt%m5K z7@inxijq{uoaw3L#&Lq$kXFKbPY~}MpW!>X)=(p_$6VAOh0tZ3SGEz;-oF2SkC9@q zzK2uZhk;gPy(m}7a(2_dbaaqUqik;ilf8V>M_~k3n>Q-3=lh&%V4E*^(RFFnt)0$- zVNRKVkY#UMbdk6G8-*dRe7sP4^Hgb z6-8e*6u&=VA(YVce$ltD=^ef$YKi=w;z{JM+F=$O=8iC?!IDcJ1NH{>c`-kt3FhX^ zEvgS$DJapoxZ}1HLd4*s%wzdAh7gxIBxBFckDXbN%zrMPB01bgCckNyF4|kYpL*4U z|N8Fy&HGxAG(y(JNgn4Y9349e9eT4&e{{^uxuZFrqQklOTq&47B}{2I^6_sU{MCej zHZI%0+$LRq@Uxs^a{lskr|Bpo(-}dBnSW(S4sh?_?`xj{JF{nPHpR4-s0UP{Wbo0( zt4Y(^2WCd=*m51FV~vy=u`n6Xr_1k=Q^#0UYUo|F$u2l>^Pg+<_bl^ph`)`RM#s`s z%2u^?eK|4i`$60oBTG)Rx8k|!RxEo==Cl&%yfKjL#QX)}1(~tMmdNWY0k(wSu3S9M zm}8L2Aq!A+vxQ{m|DJsGpddWYy*(v&RXS4@f&-x|YgD=*h=weT&)opnP2 z0%ma(v{ql(LQv-s;i*Wt+VjgbulbP{#Fp-7!_jAOb87t=@L8M!3)h1hG&Iem9+~45~YX`Vq1xR5QS457@ zR%Q4KmIr4*_KIGUzU^Zc%JM8nQA%j10u_mOP@S8*$JQytb}1)+>{evzOM=+U9MiA1 zE&3_^NK<Iyw>BgASYE|-M{D4AYnAojfyemieYuHA80pAAKJVnjT!dhsp zOlO;YM3y%u9BJ%j{!a4QN1l__YU|O$$yXoJTxW?VrPMlRH-^`c&u`HQYmeO>WRXf} zaK>hY;6`Qac(E90=OM6)TNKhhosh4vo!XTvC@sJ%uOz!<_)b3^@(f*$TKlgTXGOAO8 znNp8^}ykWeq#te3?ASSt=;w5Wz_ZDH96(+omFL}$D$JuX{ z%%mLu`>v?EY^#lhbk~AO5-okv9r)vr24ONSUCd>kYxVEZy9e3XiYdL5Q$%H1T@u3} ziA=Sy^*st~T^q`Pcv%`uma#%`Ml_fx9S2hz4xYJap5PpvPL&;xX?0mRq6$VzylW$0 zc^(+d-N$qmgDHEpw6EVASFX1APV(30$5hv$Cv_>dZ=p#_M+YhDf)n^xkmqna439Iw z_3-_y6(@8SFqQX)^e;YBR03{7!NCH)!6c#eW2Nen+Kh=<3vti~yE+C{mZ#LG<1)Ki zETx-^9`q#F_(}L2c0J|6D|NablKeQ188MUUqB94pZR+NQ^MJp5I~S?O$SZ!W@7Dq#X?1)Y&YKDMvNi8-WhpNZ2u5o|=?LTw16E{8K1@0|y@jv+f2CA|7Ze|%-X z1=yD}X@WKQ%xjZ~I%6&TsPr-4j=FX`?;{ zHOFjF=LML5fCb~=w#%{M`x+=Yanb1ZL7juQHtINIzxE(Q!*b(*M{5Dp%y~^{_@4cQ z$M7j<^SP$Od;+?3+OyNnX|Tz*ks1qDk{R{l$oseJ>IhA*Cq8=NV==CE#{4mIzgDBN z2d0~jNrKB`_p-2_cm)<--%o>Xw@zgOC@sii(}}<7X>2{J@X+HpyWzD&XUvnk-tfbA zapKh2$UAWaKAM=48WDTHpGbtVwd_ipc{#5gS1&ZaQV!)FV1<0s^y?JC;s}yApfx zf{x>tx8m@uk=^&18Ynf-^>0EOLyM6GjPK7KNI|kX&lCot?DDe9xsu}0O zT~Ss78<#T8(V*TGo)V^S zeuybgB88x17Z(L|D>rAbZC$&v@29SpZqQ?On|_WnQ=idK($L)^__%oy#q98|TFa5* zDfAT-w|cwL+sU82aY3iD+sW$79v4f!XRw0~(j$X!nyz@RljhwnUKCF-W_6~LenenO zPZKx8P#F1kW2uKllFKcjzvFB#)nXS}I<6jB(z26TjnJJB@el2Pm*>+}SR?#ol2aMOg+qm%ZL#zm|5#?FQ}e zaiHj6jg~=}&TWrpE`>e1de+#5Oe?^H5DUBQ87);2h}I3FZ8ZK(Z-m@Zm%oS3%=rfD z&$#K%fAlYh!cA(6WqsU_n~9SkwPB5~TqMK`8>OY)Ti+7aF->MnVQP*>tCIH4=VV4Lj>mr^uHCkocZy20F!7a764AGr#$ilaB z*IvBV7qAmN!?YaCcaog@2Q39tkUF4dAHv9%w#p?9`q~v0yhLb7tr+r?Iii}y>wqGLF zI~lB}^Te-hFvZq-PXpJDBs@XWHR^P;)o z4%5*0>}efyUOc%6GhyIa`;_jW>iMPc)Nku3%W~>^%`{s!E+*X_NfL_yP%+8bYi@f+ zX2E|@fD@M*62uh*RM>JnTTFTyv)r--taTU`|F|SBbc0Qsc|=y4bE`x#Se#ZUp&{Z3 zN_S_r^~RO@FbMZjmf7mO;e6lsq^Bi8)w9ieS#I2`^0_2i>;<&R@4upweE?wW?Q?5M}#`b8oX^XH1E(r_RX1ytbY0^w&`-Sj%xH z0zc_R3s3Ntt}Br_z~a>8?TZK*WEzB~Nxp0z%~7@m6WxKbr|Ebu2B7)BDb8xYTfAPi z;D3k6^`#Dxyis}l!MpvA4$OVRw3N+XqOtELeMmLYoS0d}b{;=YH$(Gtgg2?_hwWC| zkA)fIVc%2+`oLsG+9EOBSAqHB{(aU*gc0brcu8L=6^MG>%X}QyC6{r(QeKi+tkr6H zU$o97E~DP^?js(zA9W7~U>)>aGf{~Q5nOIfuGN#@fItoJ*y7xTrB?T!;z;qdfo}HaVOOM{O3a=ky)WQv>ZuR z+|;n~w%RH^pZ zMMfkhbbIHDA!^l++-`q9h*aB^v;J9B=qwz?+&d zXch9^iquO?4#vC3LA@u%4aOG!o2ISmzncYlB!VfuCYnHuE^wMgtAhVzCYTERbx{}b z`seHm74H1^*2z!#PA7mpmEq+`$A6KwXZW0kx8Q-t9FTT^VYO*5l7| z{|pj`Bnl9(Ipq*9=&D4Qf}AtQp7S?w6gG2|mc1){H)dZ_`^ph&CBiA@smJ*)M|O#j z`~mSkEZVDvna@!mO0yiwFWg@VAujSJ^$ni#*F;N9P4a4mJoV%j(dsMKFre!ax`ie} zYw&WHWvz<~RKfzYHNh8c>$EEwgS^FD)<{*-XMFvS`yGE;r`T)+<|*E)h9(Y*@zLh_ zsvvH=1wW6xmYd4?3uX9nOpH`(F*}J5?QU`kRVZ<0m1l4B)%6RwV?xM_-PLauD6Gs< z$I2zKo|++2TZ#DQPmNI%rQ+2!#&NM9#cN43M%MOk>SAZ*oM#`L2GW9%l2tp|;Y&PE zhF1Vl@qtdpQd=#A_tO?M=MiglgeAtCeWxkVeW;x}N!B{;#paaZ5w6!aMe*_BYXk1p z)zih!!1OqL*l4H!NWg=Un_+2BPgkwYWtT-21lOuJ@2|u4Qt_JA0SsAPU3!Ywhn4xM zn)O@|B|qaHJ?AF4EUydeYOKf^t!3fIJZIl_KEq0=&eb!>Ds5S$FL6NJ-+y!S1n7Ta z>UXa8Efs)rUF%Jh{1+i%Io8$ywKvW_eVDpw-p8RLd=h&4gwAR3$k!h~4VMuzvbjt~ zT#UsUG&}PSVsDmE&>+JfY%JTW*F8bm)1e#L>z$CFZidP{B~*ZzG50XvS1(x+pBl{m znA(OxxkJ8tYagN zu<1#2MAK+ORefsS-E1pT``0FnF;)4JZ1F2e9hthwGRu+NY}xr=OQYpsTKv=A+?$+- zcHP;URLvJg0b_^SxI;26)R$;T59`o(;*szVL7jXgziK)nTnukA{}ME>uF{_oZt-3% z)RfeyH*a5DH*4J_qRJ2Blv0_;pB3>ctc+e*LUo^`i^sY}Xtjp4IR&%%bjy zUs6g3jEaSN4MJ|!Hkt+lg0FhZnvl2eDc;$&S+VBJ?<6h_4=xIkf!u7T)6A_#)c5*) z_1trV%LVQ3viy(~V`9^cNjsi{_6)7yBM-+bfuwON`6ufla%Y>uO;6uURpV*taf44; z8CKfMOr*ZUrEj0b8a7M#4WI6W{1v8xwrccKH_@!ic>zxy z@rVQ*RUHdr|GcW4*i1yu zi{~%f1e0AQ7m-Aa#M@k)tZm29&%u1H-KTthrx|0VV~;kzMM^KOAm`+3-ytNYs${*; zhkW3L=7L$P{mbLBnd3iz-!Ba?maohQuPNK3chXX_01gd9DJybA0L1I_)Yz;s8tZ;~ ztF1(-?rKHkcSOv`M3zG%<()XPuh-Np@mFf4S4(}3OiOPT_`b<$t_0qr=y5kubd|gk zH%GX0Uy>@^5%T|kE;o6FJ!|k!0uax;d!|Fu^iYcq0E=Km?eW7Sqf4?o! z>)}<0naS1C@r8F9taagT_+`zD&MVgqDSfN*iF%Y&pRgNF;P7%bU~YYI$IS2k$k;2l z*kQK#qXZ=5A1eWN5)Wxvr*WbZ3U*-eur3irc<<|6{iCpyjGT|r!Sh}VEPe}Q@WBlF z_M}6%YeMt3m6W!dE8$wmfzPRki!0f%C=XHEr%!2N@iXua=^@ZH1 zPALH_S|+Qqtl^`jqNjPz{T{6*o{zH8C2)SPeWhGGYYZqWaJTCUH|}(s?qXP7q-dB4 zsN@l6<5wlKsJ?zlb~Cb=u85uRJf59A$#GW6oqwT5cp_f2T!+1tylGM&e0_X&uq3xp z>Q;+O)@*2pL=b$r52%sIYi$_f6}_vGfR!7WwYw7yy06c*uwwrakX(j8F3MbAW$=}$ z|6=Oc6RW>3SL|i<=D3n|1yk(1$r_WyL*U=7_yhYZu-q8Y=NXdX51N~g6!jC%Uc^L_ zeDMaRMl&*k88I zZ|JT}oxt6Ii{=g0mWtM?dFKhI*6FW$w+B!+bRv!dG^db81_(6gJr9-Q*UTD4(E8l4 zWZ&%3dI7^`CoF9>W3vQ@Ch!;L4L6~#jyp7lg&xSmRWK7mt~u!^uRCExwbfeMq3wDS zDyy0xi|){3F7L1b>vXtWfH}An&)62jJ(?L5ghjD_bc#o^U%%{jbCv9DcPqOpdDBp}Lq|jqULafuuW&uv=>^LGQJG#o_z(z{m!Rswm%ABSA>Uq=8X`oJfh_{caKdqwSZRTlba1xg2;CskwM1f~od6hO>MEFi!H-p5DP~ z_^;XVV#Y8(UUy#R-R(Gz|5!s^{L!)nY0OCAdI5~e89&^y_ps17VLq@ba$a1=_w@ot zuP@2`DI&ifdsDz0I<48O+-|*Sk=y-BhQxdIgplsRgtzYxBGv7RiLM$k(9jHGX#WC> zDyNc*s4hSQ@JF9KFyOr(VExc`eQ z?uuK1&75mCPgKu--WlXSM!s4wwMR~>#B&94lw`-|$7?Wm`uD&;ybZmIG`hL=S&3Gh z#f}K;@I9|{jT7f0uv85~SeSx8i<;d18NS*58>Q>t`fNNVQ;~(-7y|1W|S!@dJZ195S z|9LzY;_o5~C$su?j3vAFr*10t9<9Xy%0MBFAlLSt{H z0IG`QP1PNG;Tzj;l8M(*?TLv`EeDIN7IQ}N#ZR)=kwuq=npM!|MG|eQrzx9xXBUR* z`$jUk-%V>iDFPFc3v#FiqDzyh#8e_K3T_ci$T%0=tk;lWv41(3)b&^UbkP5zc6Q=2 z7oUd&h>`G%`SN<;(_Eb7E=S%~hj|Lj;ys50$LD!pa2N6UJ_Vd=7J}U9O9*qNcPE8I zGlp()kA3DZpQR-;MhlokVk^g9ze55Oj3Bp#I(xP8Kjhl8N3JY`O1;;Kx$IFxT`m`j z=PuO0%lIu#6hHYg6~a1s+WBqgjyh_0(C5vXQpSrvJ=?on6q>fKB6w)tK1kAjpH%oc zj%RnLDrp|??=ycP?2OA#tjC!i+9EnS(if($!^*c`dLCgyH8~;snv`1pIF@ZUI@+{_ z&U3e5k^@UI)rj|`_qhnOo-i`MEAqUnHL&VEVfqv?WO@fx%-!LS$ka;>Yh!pq|0-6wUEwWk~2XCSdh(gJu(mW~KDHPQudd(yBL6!$mn;e{>%;AFV|q ztvGT&l{~XQGAZz)`hu<>3c9V!ZNp6>6Fv|kt|*s%U3j|YmX@-BVYy;9v5=^9VqTkt*q4++r&EBId4RAL54 zHM6ZUvZc=D`UaM`$3W35zsrVr=Tp)HGO1GK|B4A6o2jyan#C`fuAW>SM#6P_rGDoR zMB7BTeO(s|+Q}a_QMjEs7RC@z1@SN)1U|bOpUCzFq-&bV-+)c~)H7F-p)X3vx0+vn zRKXzQKbhRmo6PBJ)SY`dgF;)_Hxwp^4YR^q0DRo7Y2`!B4Nhy_YNi6V+3OF*3^K|W zS8Gi?Yv23cAQ+Ml60(xI^x_EDe7wpL;_((2n|rgS=BnmvJ0`9)e1l#Hb@6-(iKibo8tXENi}JSu=7+z=oaqE$?Fr4T8B(MqAXgUpd7O zL!V94E#(;aO&&b5 z5FOJ)pg!)8$eeQBAIZzESiJL0i1M(Gip3g$qDT*SUblqP`QnAz?I8a6yXYMD?3tsh zL=rM}QtaIAJKP=9FTsw_C6UfcHdVBhbm*--HgB}U^0XAGwC>RF?~Krcp^4)0*Kmdu zl-5t%rj+q{WH({o)%C^1U$93ra*@h%{KVu9e|MV2U6iPqj<&84skA@e z;fg#3`gm6>hS$lto@^^#UO=2L`lV|<@d2%3RspciIWH$%b=n<`Be&DAc8>wB)c)j@ z^^FivMOinx*HL^iOR{F#srBcqAvB*Z(QNq3(5gi0TY2k$t^UP=xsd!XhuD?V7@{q^py&f~I9&5SA6v>L#7~3KMRCAX}&28fZ?7ICauo zd?%{G`?{}vc|vuU)*BQ&ZPvb{R;@;K|reU!eY0Tc{B=+|?!jaofOeoT##&I_z;H+H!i+l8Yy(uz~2< zz96cfDgLpNJE_NO^7PQ$s#i(#o-9@z&h3s*=Vo~LdX062BZmns!W5~YWf9t9aTZza zQ3*bvl0YH8Uv~Sdd;3*}v)b4DmD4lXB_tcDnGUdbQP@fUX6AZ!UFg5BM9N_)j z9ZA8VahdtUHuKysJz?G!=t2{*(x&){<-^S|B19yNi}s!E-e`<*x=GI%bFIDEF< zXHW%v_Vw}CJ@or#VDgxS*Rz#?2_ljhBiey6GX=C`JNjNLYpy`e6LL|3mFn?iWUBfn zWv94tk;4jO#K-h{agcCL{DMR7_n_hfySFim9CuAJRi5j_ubLRL8*VIeklh!B3U<`- zY-kV8EHR8JgLsuE>whzA6{!<;EIMXZi4tnOZu(?1%*VIasfn&Vz4KTW@?T}kdi)6;IU^si%UuJ6ux(D+=%v%_wer=SqRD4V zACauKIb_4ShLYH*SQJO!x#bGw`lRQaQir$?7rG%&%SbR3R|vq16DU@DGXp%9sj++d_MEu=}TC z?}m8)wVzRZMEh@Gp3FCtEJTFfq$exe4oPk{x9_ z9fstur7IO|&GiERZv2xZ<*NNr%!#_eR9wNiH6y5_Aeq%;t4{LN9z|)1VaoAdV2Zq+ zTNOS1>Pk*O^1ZBYpDDOarAoXf!%(Fl=y}%|tinap!g%kwk7dAHkC;bpf~A?*0)#Tv zkR|mX-#I4l-ymX1@%G<29Zx;2^axV=mTAE~x?bp$qZ-V$L`y1&WOU#en0~n;{758L)&lutB*u|WD6gAMjO85M}TRdOss)!arSOtf6>TG#zs-rP@8+YwI{NU z=~ZHRYspFl#l33^1cs6gI_K=>>VUK0zXyQkq%xpRBoQNlV5AQ0tMBz|gWG%*DZU%? zL9wFHOuTQq$E#Q9E%`31q-_}NA0|Qa-=ce|D`3w8*#1Ws|E-xXrmx&~;YoY|N_Y<~R}GD=4nShZr^M(Ve*>@o zjM3pMt#;ct#PPH$xY=1t^H_WsUC|BW(PJB?YCUvx`CaG-A8G4gp%hu|W*%_P%V z@Sv4TTo~*_iud`tkmeeV+EcV92;|?s!Ab!A54YmTujYd2)#^F}fmX`2f3u75#)?ml z2U-5>diX??`j~>uy*B||`^9-|w*Ta2wgn(ABh!05^?@FCun2=b_^I($!DpfOv4Mx| zF-T{LCf&x@qj}ifpTX(M)YPYDD?Ru3D$n9WvRq|Y;3DbLAbQ8|v7FPvgO_HQr27%^ z%m$ACwrTZq-lRPpW%ea0Ap+!;Rb_`e>TN3eD~(u3R6;C2#NTyTbo-jmQ&j3}%yHTO zlYxPxgCnpF8KZxh<1lPezbI;W;|?o$jqEH(!!oNgkHFvl!&e>_s7$DkJE@+h|V=Zp@G_OPq4)iZ&Z z8-0e+t>jDlGb;t4(>|_;gPGq;%lAl);z+F`W2-4R-`N3)ht_#={)Ux|Je-*Qj@`Mq ztb5Mqp5QpvZ+$zS!El6eB&2qbcbA?b)G}7(3DyEJ-*4yNH|Ew}u#ip`28CW*?6|}2iHxmfnN`zpc zTX}&R3%c?jdGfKb*}qx?7qe@J#g_0_{aHr$i?NTp`f+~kofXs+PB00eQC^KEZo8#+LNlLpzj^Cr&<*c{|B zR|tW6pOR8v&Hg@6`^{#z6&jCKicV@!2q!z4ZJD1C-L9_DHsLVm{%k1)kqoRP@zm2V z-s&~9@pTWk1>Mfn3NhAH?kgS6@EIufzbHC>;5L>d%|2-#2wBJs3Qn1i$Z!}sg{y)L z&-I=eA6tU25>mwOI_|4&#SQoch6f{?#n%oN-Lc_`ogmfqA*0)?(Y$0g+N=O-FZ8Sv z38y+oK73hjn?tHd0W#^hzs|6?+_dLC+fcJh+k;kO7O2N{)68D4UW~-Ii=Fl@?d&&^ zffl~ffRr(lJsDaVt=0%6N#9V_*sl1}@12fomks$}Sl-btM9RH%**octSgI_eI!1S~ zuYMUCXV)S4U3D6ljT6qIy=fP~FB0jX3uQXQ3+RWW+=U_n*d9p&pkRv=v2iMEX6iLn zpZ7F>4t(XolH#R)#;ob~!lKPAk?~a^T6E1IpFWySU!cXlR|*(wz4V7Lrpz1^Md>v5 zu_=e@X0z?ZLH)xP>SvG0lII*L@JMw*bfu2aQjQ(jy?c4KHr;VuR8ui5UYjdJ(AB%)OXae^2EYALY%|LRP59bay`OL;>ys%< z{t@#`j4|bUD@5KjbRYC2>&!EO@@=P@REJhR1>%YL-J*o*Te&*v^CxZ(7UV6l7=qyJ z#N&v#h|lUx% z{p2hJCsg27T=~VfdIQKO&yfIo{1hIS#CDkoU2F3R`aT}{=CHkuj6Fz8yQxq!XUrb# z?A!2Rq8pQrdmK1gY(uSnrFV9Y66@A~mdK(g{vxcX%VouMkY ze*K)kbD1xqK-Xm>TfOpw5_8ynaIo6vQn&dw@J^vF_R1;XPNH@>TXEmUH5KTfF72V! zS^CE+uh=YL7{H-!mtn+5RDW8uihBDJ=+Rs<> z+R@|t)v{U28&yfi3XWu%dQ$ark?7D$&}yIPaLF}{U!i|TQiYs_r9xyYAZs<%`_`sX zTG-+CxsQE@3nOAN^)yY*BiDsMeF=9uciA8eGAHn%Ygdd6*&w4JT{p?Ip>fx!h)*N# z7?Wexd2Jbazj>&#vbg0!LYBvdN0DgfTbMQo{46eJ*~)$^A%Aqk_e@GLSpdAFiBHi8 zI=0y8wbgG#vCED+Yfqfy2g9n{ETU7M{A{?e{g7o|J`y97JfgFhdZ*E&%E#Qqtem2( z&M?d2vN(=GJ*6>jm-SR+o?5(Y3%5d(`+@*Q@l#dK&)4$;wD?Vv?0PtMOyDyBs{{{?Z&}4_7vgnlRrYn>6#{=CUdje8 zzhG4Ad8+hs3oIgZCgcBnNt zIg+$zR?<&!`^o=#Dzo`j62RGV^7XT(YGt7W0l6)Hg(*01YN+bQu(9L%KO?Kuncqo+ z1DO%Yk{y+Dn%7zL$ivB)J=cl)c+-fhRUxPe=w<;XfFqMGgz~F12}KyCJA&UU15rg4 z=QhA?|L1<|qHg+^+nV;(HmR*G?QUW0iTB{{cRJOzO3q}K*10KyS6(C9I|*q2qdHaZ z1*Pi1ScF&SNwxHd@1AOknQd49dkrDBM*Qe~hdt!*TSJ!?HFUuh#C?bvY+O4{E$L^U zsHU@*swULq7;srt+-*~+DRmrz@98YFR^*@U!qDw!I%?U+#R=9A_Z3Gw1N8)t9-IA) zc82x@X(71tnw~PU`f-;a1jgJpHgif#j0A0#>5ra*g(~an!&>y!W@*U-!+WyOznAxb z+gIv6Ri!AMTerJ5=s)~v+EFs(P83a&Rhwj=>%X*U-KGx#uZ}utf|38m`-kWf5yq4t zHxV`zOjoze3{+R?*jouob7d6>^a3GWcV~Cd2LmG_@wOTUbsWF5bM>pcZR)+x$i*&E z`O|*M6==(j!$*~QJ2svdA~KE?arz5P9>_k*U_^UbPiob#>z$LQ3jERoq*JCTD%QPM zkKUTF+uB;ErMlTY-jFI^0sZP9AtlLbMBkc=U4t03!D$W>LwcTE5e}7}xW{$_Qs*lb z6Uhc#m+hvo&t?-R1+CQ!ZdNLPuZ(Vjri_-F_;G^{{Yvt`XhOiuaO|cOLfz?v&J8)H znUC~KcI*;+^iJ?Z798{mw|vMe#u-&5$X8}}#kJPcyGq+|_erGzTya5By{~! zV5Yw`%~Pu2C%QuGo;Gn3_s(ZmkIpw8(6q1j-0h18Wc^GA4wg19T0%G`b@kiYo=Sm% zu6PxeHd{^eG6*QpC*aI=!=+~eIv)(`ELq0 z^Tw{qu|k{ET_ssWNGzjKh>=0#{3-78_e^@7&{#7-bu4a5=|q-Yw!p{Kk)n<$nwK|- zC)s4G;lw0O=AoehncJ2IW;RmL+r%VTd!)zkGuzg`>lTcYh^Lv$>?Jh?9xVs#x3!6- z;tqGD@3(K!LS&0ukY)7kJmiKzTL!GS6PocEMO-sc9PM>=L!q8d{a@blT!H0d#VmtW>@F;I&RJhO1Bpmrn`i6|2PQ zKev1e%(5&|xP-9pTD~`?##xo=+q?I%p&AwBXE@D+WkF_C+Y*%FgMzdp3$Q!+)sOmr z^i{}<_AexX1Lh!;>EnaO4H%;r*sL_faF^lm%)>&N`R@=@6|tIx_&=BKa!WfdNm zHr~bVUN;a;HZi~=4LXk=+1?kbS@W+9!l_pRuG;6mB2ES8vWd*`Z>Q34;U@-B;Ot9- zEiSqXPRYyZ(3-~0#?={dNa$g#_f&d#esMC`ZM0tXE^X0uDdB2T@+LAr9g(~T7uEKE z`O#c~`7!^CvImjAJ6%7PY+HAeRnPW04Y@K$C4(+_>C|#kXEgTc#7|r3_tCs9t11h8 zKGAvYO?LmoT|8*50aV*r36k$s*=kCcb_OT74asLiG-42?8baRn4sWyPsED+*`hEtX z@2(Pz*g7I*)(3A?^?#X$fb+z4SR31ASJwUrE5J91YYKDsVj$Uy!YIWu{V47Z;A!nEEsY{*}+rN#kGqbb@N zx%`pem|^IRZTnYmb+|t3OStFl`cGN(1}Z$6!jPN9L|;R?0v{be!tC#M@19mgKo4z^ z$#K}Q#Qf>i&~$kS4r79p+(ONjKmleIbso7$adp9t`evsBHS%V&imwOyG=SQ_4(e{G zvPlzBa*k9H>XKfp6Iw5S&D0mVTjcH`0#Oj$8(;txSGgt!))?SY2xPW$+Y~vS_jvOgBGGRntNZbjNhnm?Mf0{rI&6?Ve8OvFlQO<5U!E$cK z>3&>86J^$5?Uj=Ao?BB;9>xR=J(oAB!zsjr7k_*0KepN98lQ!J_T;SbVcd|f5}G+T z1OEe2ARVpUzk9H`4G62xj@wF2K2Pj-sy4Q7+7LvY0G%iuH;yxdMQ(Y01rs#(c_EjJ zk%BbFFoPijiSxo7Ppp&~))obV-q@J%{=QldXJ0bc=O+WYPym4lK|xddYU9V>s>YNY z8=c>e4bKY9_Pu)z|3!i3g#lQtF&@yN*m8<9?*7L1L#vx|P#a>50rHyh0_L zfY3R+K&Qr&?i$0zJLrLuooLA+_u;+vJCB`h?t~ueoHS8Pt6l0)+Av zMJCXvsymaE8@)@RqK0Xr61_+64&a8G&;-|gHgVsR87?|Cgd?lXqZgta{4i5&&VgqT ztywu`!urX9M1)cdRnrmFaEx7VJ!5xRy?J*SGQD>mt==jID2PpC?I-rmXy$o9plo`! z3*t_5YT7XMzwRf-`7kcoBbvFVLEMMnTSK$R&d61$uZmRU@Nsxs)ZYvrt|hLQF_vGy z{38f|YiOTw1x9kN4Hr1?y<=EMK~JEibGlCoO=i! z235pRE);GyR3qm%_9l%4E7M~w;w>I$_cz03`#+gB$eW?dv>I6NaEzgs(7EPzCB!8Y z6f0e9iR`YVl5u<$Ug}k1fZv*SY}34-nni|hJ-@-F*tB%9lF6u>+Y50E7_I{kE_ZU= zqPm}1^?h>mXXyNJa2Ia3yb5PW`!{oj8?%9I)5qqg$KE7dEXYbJ%x`7}bc#ThUsHO= z*Am;9rpdW#*y*hqPTyO$gN}86T_Td+w2VX&LYl5PY0N!i;JH^@& z=N{Gw`DEoGx>?jI3Iy3SJv0*8l!B`JTcozsPgxs3m+z(jEV2nd!_Bp9REB3e9qO$4 zEfPlSQ7G|cfG}M?oUR{43v8yBs%$}8{MZ4{nzvoG3Jn1J)*XTNbJ#j}V3x_XR`53#v#0P$FxsKtARq*HMDvfv^JS z5IR^1K4NJ#f@j11+8cDPu7G}?7?Pccr^*x&H!TmwU>&?WzV)0*`FGz_`hb3(N@?cl zQq$lWuA$!Sz3QyWQZ^?hnd?+)Ts}ogDFVKWraUeXGO0!1=sH^SQXh_K=Z2`i$xVh0 zbOO_7K-Uk`+nmi9G7IzalT!t8GGM==fS^a3EjL{E1~|>({}*LFjTA(&r)E$}*6E}h zP3eG=KHRi)=8sl%_dlb?fQV)zqfu3M3TuL8HWP;v1qZ=qr+{NIz*!FBZg`V}Fq6;! z`$%T8b#EI%RrDpU%Cp`!A1%thFou6I8-c=%qbW{iE_)_FJ43Ay$^O+9k)#Z1LWca= zS+2oo)d2SIgZ5Via(v3_^#*@?V&3%_L!CRMF1nuM{|vQnTsLj^=3^xmF#UnvZuk)qNelfKv2$ILsAdR8m0uqf zP%R%Z8r0Pt(~wAkZuayyx<)W;B~3S1n9~fY;(T$DcZcm&4aYaap0mf(yH5=hF~)l> z=vkPi5M4>(oqW7e7i-t=Xb2IC-r$sgYlnt1(P;wVW>OpE*&DQ%JrkfEqQXad>3%6V4n>?SYuI9-{<&vgOOBWIc_$hAC6PYZ?i42g# zBiGCuBy@B1G#FJh7`(~hG2Bm6^ww|4zi3tQ)*QSiECa{l1GdTNe;sEzFB+f%XW6Y6 z`Gp!3RMe^_d6VB)8nf70Dj%nF3!MJTACs4+lI{(wpH0*@#hKp%O?-#g*gDiMOyY5I zguHLw7q#Y2_LGGeA7sP9cK^gD>KU%6a~F^IfD*{ba@AC$qPGu+D8h%WryUML+lsb^ zOqCrS(C--1jx~%|C(py@*Q-1*4xq*zp%RdEX+sJpB-r^Ye>Sb4`AJIaZW;%ri>L{s zw23|1YpfzF<&woapf?V=I3}JzKRqyg`&;AYEPv07qui{kqOz3RtF+13Y4I#ZO5drK zdlDLQ_jmFf;&^#Ktj7I=Urn~Ts7_zlW(h5L?ETotCP1es4^+A!`yR7F6lN>99V(CU zG!=8zRRJZ{<=9Wonv38z8-Z74kTrO2YKa0Qm|=XU=fGrPqKOH1Gem#bvaMqeFEq7H(B!bbnW{2kE-DzCO313V?@&CiJdg>=t9a$58<%u z*Iz>p`qf1>MszrQm$}sUBD%NQ(29+ll_R^`YmsS`GSU14vA?ry3!q@>GN@aKPbg%}cB%fyc< z8hh|EQq>G+so})nzwC^qX6EtlN1@$ihKD9q}ou-X>AiSBES|qLiQcAdDr5V`658 z#${Ww+!kO3{#=kZ5OU{{j(}%t0Eg_RCRYj3Pe(4b@vBMF$b3m}Sx;N25b|f9v!L}V zOZ=&6ji~simmzA+9cSQ6aLskvB7RxpU^xCq)+i(cZr~RDSJm6NLq8!@B~&_XKusiT zxRd10IH9{%=`J1qzu1A$(ME&A5PH6Bvb5f&>ui$U zN1ai&rY`Ehi`(tK1WG4F^Vxn7p4fXwT$e6r%Y6IdTsN6_AVp9GeN7KIzg+wky`F#Z zZ8*f$V9miGAsAt9{c{PAfFEo@HVl`_bI|g_Tm^r= zSSb*Mpeahn0!{HQCfLxY_9gX~xYlz`x3sD8lrep6iNH%P_1p2@)Z%0Iz(_{8lbkAYoGhqXRvLte`hP9mvA^x`F{2| zP#~?t0P=k)Ox@vp*|kJ@_ELd&doM@Z)@N_Ou9R!>^N_tYohfKrz?p$Zr?Bx(aHD$0u~XX&)RXutOl#F_VsMcn7+xe?Lud<9VZ@0Y%8R z+C3D>{+GBQnAfj(Fi@uJ-Wb6 z#)CogD)Gm7TDz0`lBp<>%ROL;AhNGSqX1tUa!QQy?o@R(ZoC!DhRb!}9xO3#@B?)! zqpknEU!T?75%$?Pgc)RTJh-Qz;DINrgl>6WuF7+d(yf`E0V!{On4SLfG^_L|so74X zmneS=LNL{-HDhH8^zGLm(#6dH=!N9JzkHH=Na1bcVC?Cm_TvYkVE&4fs#pr$7#TXM zU~1Rn4b#k}-)d15U#j#&Y-`SUUjY_iY93i;r@PI2f>Y8Am&EP6=mQ`^huSx9FW4g6 zHi!E9ud_$C)IyuKZxzg_S$b=z6)&p8?^YqSjZ1z{H%$P)cA%>&QF*~Jd#XD3;NCa8 zdsfzRT9$E+-Q;4YwT+vl_Yvt}H^-@BZ)5xrbiO?Hp zzI<fJWkRyEmM<=r@SA5&%GVfuF6jdJmsMZnieEYJXOgzz zeW!xf?y|E@wDd^hK1+zEVaLhum~+A*{G~WWf@!?OO$Z$vYYM?2yQl6iY*IR$iknT^ zF-(Y^C()Ul@4C@x&93ix-+Ar*5q?DeU@jU`nWgBp`K!_P^qUO=DGU+d=$+^7U#Zeg z&q1E$1&?no{#LS4@x1ck@NBBGeSvj(d6z7W0rfqvYW9xOrI8U3$-3|}KEQQl$7pv= zatyRoKxfbN(I?>epk0XifoM^Z_C%H#8FOFe&4X24Y_J+8y8}?16@Q1g8DP^ZRg|66%P{2y!k7`4ttH0Cdd^o;F>(u4 zvrIFf7>krhuUtjgZwg?y#l6o=Z$8lm!h@8X;4FK1?y@P=)Q~A?P%9;X=%-Zw*Rla=lpAOSvnri z5fl{#lqMoo=~99e!AlXOE09R&(n&z1gFvt$q6CD{tI|VAkSaZTK&pV05C|QFP^6at z0rEb0?m6e)_YZi#yk|Zn&+oUpvoo{1v-`}*%3#%z0^+5-}xFM_H)m zI+8@iWpbOd85pDjY-?Z3LL+9!qatzsMaK5IR?%2Rm(c;q&ZTu-R6MruOhTwZB+(_- zWvHjtXVaaxzkl-`%7Ma|e5oH}6Ih$V5DAx$k*zf0X}VJiBWyXzZDox2pqZJat;J@P z4=wW#w_j;lWqlmo)2F+=p2W8P002j%$>&%&hilG(w#pP z1}N0zQaveB>%ffhs@DKqJUND*?!VZisLHzyM;=;{w;CE3sGj{%xqD==6yR7MFDjJU zEORhM2?PN$SigKhA{%aAd&=cL&fn+9=g;=b!TGaM6kS#U($*P5j1rMwxU@cHx5Z|l zg!TAGet-PiwnQWp9nDK}!NF~eqnMw^%-0&5ELjn7+ACw(cB?QcxdTofT7Nj$*uOn? zu=I-}_OVli_;7A=XfQTINq%Ri8;6+{AQZCN1pF)8H(z||l!nh$BEzoeiNL%h9>g@Ykwf;33Dp`py~vRH@)#Y!7}}#^=A$KG+8Om(O!0MV`)xh>?Q6u>(SJC_RQcFY6qhZkpa>AKjpRYb|svySo6NbJ>EN z1TP)EBj0v09+a4avD0#nJ_xg>ml(N{jHl<4wKoZeyB{}|o$E&K@T03Z8Vb7dDCHTK zJ+qsW%oK$=-yWCN5|(~bycEc&B{Oh#XEn=gt9hF#%e2Mm#HG}DU&nWMUgMso#beX^ z!&i{Sm7U_Aw#`jYz2=0cIU6vKi6UeiM>WQ1!GL$KBRBKoewAtvwRn-jt0-t=42@6xJUe&0g?AL zlO^nQkm)mRLfgH@(|v^EY{EVabqzAAq{!MmDw^OFQlo7_C6Q~+didL#Dlk= z9UpZRwu+EG-eCF)-9Xe9Gsy^Y!Zo8c#iB!QJ0sU|vsB1E_H4bBP35!D(E9@y;0f?je`5)^2oHY{5}d}0SBj0 zvrCf@umnxe9)bB$E7l7W7AZ8!cwffHacs}5>9}+M0HOqLO937gCCWOifi)r{tFpTr()r>KZ9dR+F;HsMA($lG{hiQnCYihJ zD3l_xuMkHGP9mF&lpI$-FMr~Re*dRj{ zYd+>YpL5aTpk9@8-ek|sf^yH%DMv%qBJKEgLBr-jJjDLdmHxD|8G~3694Slp@h-Z?pWF(K*Q)Ur zZob2J%}gLsNCujcauA7}*T^IZv5yvcjC<8Ttllxk@mk=)75c_{CbG^x0dRufO05y^ zD8YdFyB6L$8Y0ZX9bMd>tRMyi43w(ohZHWwOK=n0+CslYBUkkvwmLgfuk=vP`K z%b^~;W#UAqdQHqnT9WC4`YG)-P)j@(S|f5xV({ykoeytYogyMp7w$#oOhj5rK*n}r z52v*=dl7ho$+&OZ47tutA6(Jz*0u0`h?RV+TH8i-=Y>V{=8>n{se+vH?o z3x{^nkZT&u^LZWCSu1rvM6D|9Py^8@OhWhE>UX4y&v)yP)smp{vJa)%;34ss`h`+Q zdBYxaaw-ZC)B1L%m5DB+m@mKm%c*|^X(lirGJoo|Db8PJQEp%ayUiMlx2lWY?z(EK z$C3+)uUOuWn>kz@XwSp+_9=rm-gtatP4yUP?RZGq0b7_7HtigzlZymzsbIEyGyt=` zYG?42xzTtW_)j@xO`IFF97yD#XFk`C+-WLJA^y zQHu!0nZ{Pc@v0OgYcG?2gdggBS>{CLg58%uAWpQ7rkbe`7*(a|%K7%Bs9322O^(5! z$e7aZoyij+u7wdCcDLw+skFJZFdR* zqn3$B24q9KL8F7<_-0``xj)5pI-(vvdT?^LOotNa*W7OSux~SUET>EgSq-h*hZ?w{ zXm=6jxa@E_+NVVDMo(?rN@`CP1|zQ`Qjs(E@z;@^J9X?e-;R=w9!k7kk>Ua@(Q9o| z*cbwID9fWUum5J9wm`BNA-EVS+44MsXhyqN5v^xV2;g06j4pttGCPZNcyqHhUWsss zM0*E;gSw3nzE#t=-lJJj z4veLgJaqC&Ne?n!GB56>J|e-OZJgRi-WdD{|88NOJCkUMA@9H)ecOyO`+t}WgEv}( zh$GY-Ere^4d~A}T1-FQyCyAwvE59kD|3{R~x2LolqC@+lDEE46dv*_~d$78WF}gp_ zLm%V&IFqY|xBn|^rYUWewJ_hXL)+>mgEM8ADU2gY2S;>)pLoe%YN(vV#6f}Z`LfIL z3uM2{;|+YXy%f@*m9e!_9^3)pvM4c!8tl%a;c3Bl%c4U}WuwQ%5GZK0^E%F?H_Jm# zI1Z&ObbB{Br|7Ig?9d_KI)3B&DVgRb+I?@Y*$+-1>vd=iUezN5iSXd*c&_SzGB^-e z(2tn$brsE2#mpv$z%Mswmj$gDul0MP9A-9RlDaCuz291lA^iT(wa}|u(@NgdAaLz& z_{9p2!twnL(d{}lJ>f*q&FQ2Mn)^SxjOw-)eZ@fy$G!|msi}6)q*lLn!oOvA#JC8c zo8CUhUG;M17pg?-p5?o?^X@JCI<5-uF>^|_DW~`-&JvgF1+)CvC!bH{5X8K4cL}z> zR{my(n)OQJZr%M0yp{6M`z4q+lZj33=G?=e_yb-IM&o5jx!10fMT6BfHa>hN$By`L>gaRv}?^d#hJE2wz{)Q+O%8|KM|z9Drz1UED+t2+~R+5 zQ38Q2l&1L8XMo^=j-bH=4~nsGwKBE4Ek|0;c$6^l{F&6=C5u;+sp2u%tI~od#Jtlp zTar_#+*jENld;QlURiU-IbVmRe9;Yj)n6B^>Ix za~HQPu@g5gwu{cI4Je9~0P;vBSEVh{PahAMW#pTimI?~5qppu(ubr9+#QW9apx9ik z?Dy5xik+REu1-!`va+&|zhu_aZD=2k1*h+x>)*CU@sr%{72NyYu5rn>y434Sfu7uy z-IY&%C@J;T_K>@c>_8|o`1Q?gFf$)iS;S&G(kws4y98&jGMMAWI{iG3p*W!!d8(rR z{^e)EiV)il=q*f1dlB&Fo7*gk5lxO$3mdc_#lqN9Bu;f+s3wnzC2^d^0RDEpIF9Uh z?-Ho+i`MQdkXHX+uDf!6Di{(y{XhuLD)n*0|qumUodYg@V+T9b6`{iJ2%Tb zQ{U0y>@pdG#cRVP8&3QBET>oK2H{;POfg=yx8IV-u=7mdH~bH4>zbRJ3I$<-p>W49 zJim!BtD*SsXJ6|-we}dsnLALpJXL|}&Tgkj7R-2qU++#+i4Oj|b&&29@LCdA13*-} zhTEe!SpIqL6|1eH>t`7*gU0LFYy=jtf#mKg2_Ns55>UVf(P3pjugoh@>6T&fAOx45nf*JWD&-N ztHPbLyAajiT*xMn3<2y?8P1l96~z#Bi|Ims~+rLsd)3Q8v1@H z?|#`$Eddco=?esc+1LF z7KEu0N(&yL)f<41jSF(c&wxo^i7pH?dTH8JU-zK#YW&ho@hUuD)0!t_SIBd1r&JI+ zG9RK^M`iaBUrRm(FMr)73)xxUaI}K}n94-2HzjcgXzgS~Ggoi`*}%m+IbmPUJ?&)q zZN>2!Tl;`esUuTdhKzq6YqrEyTa)|=Sx(-mn%9uq`ou1$PffOvA;G9S(^szL7v>8CFHHH_*rrf)>WmrsL?pwhsnc$Azz zD=G+xktk%VR@AlPXjx#%zj5UjOZ#MXyqd;F1Na5y7jkdnR`6aq3sr0%kQ% zjZSAMTq-M6Y=dEA1VtJ}HzuDpLABXT%X$mMs6;T*cY$mKv&!LeZkYzlNLKz3iB(Vw zd9Pv;nd~ti%OU2B{Z^&)IV`0@^qJ|Isq}lCrLbU+mt!9Jg$Df2MOx|TV%6?V#SGx9 zKv>2+Ew2F)S!kHpiiP3>o8PM372kWH;^W(&v;`{^Q0U zQ>|iF0a7136^d#nneUedkA%yVa}NtCvA3|`;fUUPyxo;-Yh;OP!j})~6?m|;!`nEU zO=hleQ^>z@l5)yAaUH0(MmWx7(lxJG>PRBBruLM(U@IJoQSUwyV6Bh%hY ztBN#;nXy@i`7Sp5c_Fw7H)nx@PB{6Fm_f-o+Y{$9!PIhpx-g@Am^UcMH-P&F`bOmdo zTO=0?%atS!o}-jZ)SSrw3cKJMEF5eWU`0uc?#>ajDX(xk?5-swR=u^y6p|DcO*@KS z+f9~TrXps#HiV!c`Zf?g{>YF?hk1-;4GE0C#nKI6gCGCc{35W(h>Ke zCa~ZoNloyRblx+~=fcosYJ4$|i;GW;rcU|~Rfjj{E}m46IaRe%JBj zA8vZ5Z*+`9U~43E!$#^?!go`judz*)YF<#`K^Yg*CGS=W;Fo%*ec|FAwyPqwOk=*y z7rAbVAT&6;;vtNFJxTc~RhH!s3DegXB2!tMg*u}HYyDuC@6GWV7erzA>%mZ0My4)| zx1^)bm*jWv9PWW*ckONJG7E7A<}amlm{3VR9^Qw8N+j&wj(r-7?A+dV^$m@c^15*0 z%E|eL@Q~>I?mexU#EZ?X@qBa0Fe`mU#$}rL)+pZL+0+Knx%PP_g{{5!JJZViyBYgx z9}6c+<5Wmow*{rlj1xM4Fy8*5TM3wgvzX?S5h%6EZ?dYm-_O?D3?zzm=*mbUt9jF4 z3c@!@HE)=6SXn+)7J;(7_St{mf0d6&9c`&{vEXa^@bsi^S}L+a<@_c(23O4fDmJigVjrR)s40(dzX>-nB- zaO#SiwQSMhboENoNs-fLp&0k=vwlH|E3|G6agzTny-SOIS+blo@Zcs3b=8vg!?Z%N z+umZK<_vk@!(!O)r?-v?#SJe?E)CXSY=nbAk3Q?e&Zy7sGhA@|HZg+6Q%ZW4m(n)^ z5(a1Qwtxw^&mCvXKAuuf@)qCl*?~V7)L5CurYWq{Up8vYzTWRg8!Por>;5#8sN~mI zzjL<(P=VsM`uXbQz;1s3W-+6_E7+CoF8|8valfv5)M1C!rybXV>08n6nUuhr5*Y~y zQfM`kYV`Z!#dE_o-|S)QHK#v%fVyw`&ENhrSMAULXMo}3Z{T17GCY5hH7u&*snKnc zvd&si0gS8v2HVR&3yp@RM+KekG41Zq*8K-w9ism%2YtE;V0+@6cBM^00If9CKsR!6 z>@_W|3_S-#_x~FLUg{oJ02k4o6yFdKfQj8#&L!-A=ia)Hv*eSS@?a556)xS{iHI2)9Q$ zp!6TTKI1Fc7PsW3zt3Fn{dcvqKZz8yZ@+R<=qStfAMoV;Q0UT8+V8*M(+!6IC7e_L zo&NfC*t@@l12lX2zp`m-@VOl2z3>m> ze?;-`3G)A8R%E!q67Girhld@;fdRll!*#Sil8PQap>j{kHy;B5pHahMa5&&0@MyWL z{>l%O2b@MAfM1EDWu@C+oSz( zOLG9X0cVf;zX=30wHvoTO3~?3bRSNLn!b}8#~unOu>h$S&zxxme1vcwpvgXMNPJnA z2de8^SyR$XM1*G2Ou7^S)C~keUtq@k;^N{gA)V-!=zzXCVgt z5x_|GD`0)jq@_N>Dm~p^hMJF7>)czdvqKUpE_KSb4xOx033d+ zj|ThtJwi{tc!zIf*EKmEkuw5lT{oceRn9OzcQ@k|?FWFBx)oq0!&$_y5SZeVdyalV zzZ!-LcFiF-*#RlT&fL}t9e(?L;9w305HOv5w7szQy9zBG;Hbl`Ib+l&pqJp%Py=~P zG5tc;NYF)qYlWY5ez$h(rQ6s7{n3}LAN7uDt1h&4 diff --git a/doc/screenshot/09_operators/0903_or-operator-without-ok.png b/doc/screenshot/09_operators/0903_or-operator-without-ok.png index b8097ee3a90476c17f96568a21a4f0d3eb13a7e8..e9fcd4ec494be84e7cba719364e2e89e617fdeca 100644 GIT binary patch literal 31421 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 scR2ew6myP;r^a^or|dZxuVmG)a>}UuNYJ9 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 diff --git a/doc/screenshot/09_operators/0904_min-operator.png b/doc/screenshot/09_operators/0904_min-operator.png index 04fa9be981c1cfb3a3fb71f71e1b66fdaad223ae..fd05ec39a5a5e16e51dd0be016eef4be17467724 100644 GIT binary patch literal 30888 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 WG;E+9 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 hs^N*$1iEM)b$=$J$f1T{{UCxUvB^a literal 94447 zcmdSBXH-+$8aB$_Di%=OsB}anfOG}vO+5$M#K!U(GbI#ei&v$;^KX=@lF*0B!bFDS!JKy@e&q}zqrpnnfEN7^wsLn!F z@9I)fol2vkI+k*Z8hmoXZaE+PIqr1_s(%W+{7>1u0LRSmd&Y1*cRRTELr+^OdpCDi zTR|^tPg`3zF9&z{`mq*yDyl0~(7THIJ}E0WZy$3~;?AZYCY!kf#f7ban4yXu#j%RN zv3l|J$yv!*;@R_euAhD?Fa~KDljw5$hFd|wu5{?4&KuLCikFWM-W30=&p758GvSIb z8&PE$c3eELzGWR3Q;d)KwCe>kSKmwZN=pQ?aDHP1`*XxPANIT}&5#^s( z>c_SI`9YuX|JRR44qfI*zQY3pnYXXp_(pog#}IMP!^5KjyBgCz;pR=t|3O;~3Jsq) zoXWf}S68WjV)*RM;!{*)9)<3lhDF=u&_<$h!k>Sy`N_ktHcX-Y*tXDzUuHMYOD=Op zv}Jz!bT?6*JD4ZS{QmuyPG$#~rJO(i!WLF zS$6x%mCCW==g*Iu2rwjes}sVxnP~aWpUN*NfVMu+2GfK>p)uc~`#nrdd*kV&C!A}a z-{A?pny7xWl$MJ6?W(r`nBuCXIUB+0?`u=tpe0F*4UCVooKA&sadp^L{w2Nqbj&5b z+fGkcS9h*vln{w9VY&tcfXeRX;yIN{#U!WB-El)-8~2tcg3lUu_SdCCGvrTbL3poT zRpb`R-%aYU(Y|Cg-zklNjvcayt7$Ytd(s%kvf7a^mN=9nVO`+qz zuJKW)>>1C~+qY3R)uv&^Z~8m!Dxqf(ZKtMo_Wa8QPAk1%hJ%lmV{FlI6Fc4Fu0NhA z8ffFr6X<_k0W9dT;W?ZpH8-24gM-8Csr6`t6qAi+p5ErUhBV`}l5OrfE7-YT-+cX~US!F_a_ao)))Snj`1SpuiL23yfJk9x@TTuV7)W3OA|)u0!@r`X8DNCfov zgs5owf_ZM*l^f4_)?cKhp5OEVE2K90@iQ%st*n}Hfv@L-(LYvv!}rl8f2Mb)C7#l$ zXO92rW>~PoJiU@Y!|$z_RXm&8iknt(}w9~bacW)CMP$y zc(8dNr~f0+{lUEp28(Bx!jJL%_bm?YY}mZHud2Fq1KI9Y+m3;NMwFYVxm?~cHv>)G6i@nD_@}{4PLg0DiA)hlr65_+fGz%_J_6gWsN$9=8O1jG)S1$)3JixtffM~QW z%8bA+0VfS~nzB&>{(mHh`0J8?s_@U})f3-uIhw{KPOJyGTrV2lmEh1;M0~tr zNd2~j5`zEpdMoNxOmq9_+bWU^0{KE96&4imj?BM0Q(Y36czN>5;73;CwrjhUsoIa9 z7RjlZ`;7LVtKtvqZVJP&Ep&F5)}(qDhY80UbYkEcN&@-vp>!{ zdk)%wgU{^zRW2VAIi@ZVW`FB66BDo+Cd!=-dP_yx%)Vk=HFN2U^R~q3R;~|sFr-6x zd#pyH88qX&U0xa#9GiJ02_j2UaWHD0Lo4}GGANqfZPa%-+s;4UyOItCW1O-=bf z$nQG&w@|34h^_fFX&390;qyfy(%Pc}Q1Wau-vMIS+*X<$mEE!mpC%JTd9L%^TzfSt zWjr%81H2H3pw}wL1j0W4ML=CUL=bciX4}KKpu!gNDn^UBq`JekUAiUU{!!V8q6PfR zm7&X{K?IzYT(iW*&)+t4xRMg2$;#(Kde>o~ zAe@e7P^d)o?b7{TU)FFwOZE2Wauz{9H)ja^8WdZ^3f~bmt6sgUM9a@=3fvb^Ehi@@ z6eS)?{Z%x6Ld8PC&}*FJ9-m^mtt>p!GF&6ywagTkfqu8KcQ6(l4uTxl$UK~)2tpZX z<)DZ)+}=rCB}qa@iKm~97)wYiY3Xm0IeM!cq!zZgmXy%;js5q8n3R<@Hs%s!)T*6u zn!}Hep|aPzyN8VOq7xu-5|0swG+5$?47_o?WOj;Xo{M-g3oGmV_MR0i3c?Fwym}sN zVEGwO&e@W2g4@f9pseggk{?b(dZdpJin->uLdDO12+m_eHe5ClhbGu^w_#F*wg%08 zXJ#7DMT?Qm;JqVL4%?f!gYm_M*#-nSf}c*8_3%gogAPhB{hsFyA7%fIPmH(VgitFS z>F|#ev>kTh%jGooOJOuTgoH({(Iz!d8`RJo9e#Y&yA3mObsjElTWvbr*Z21JmGcBo z2(O6H;)}d{ZPgmMQks(*;06^*>U^cHBRX1YwFIoUiU}eqMm8&Ca9KYEm&+4x@BGl| zPI1@r_owrN(i3!Hn!eciY?dFea@m zE`D*Wbm$N@i+dmj%yT<70ri%3idR?d3e)V%FiIo=0T=k#_E{YetOXd<)SWTcWDHtx zdRKXG$=lm`65rqTsp`3x*dfAu>)LWReXU!fSb00?TqQKU3ojjLSJnV+nJ_8z?wa6p zB)k&2I$261f{Nc*m%?o%(&$F z?LFi34?O!Z3&a5@lFUg1{m}r)MRk*y#Ntbd9qgAIf_g=dolAWV^qz1i*Sj?NIB0PG z4eNOG{>P`#0g_((a*-&vL&pzDP8)V;hOV%<++aPvp463^1Eji!+=nFJtL^US!>8Qp zz7OqVYA_Id`ZmhPl!y#B1CAyfz87xiq?>Z+;SptMm*e0c4C68LANQQdI_Vwj5Fk9o z^YO-9g$eQ5Pbdb7mz;-u?s#3*Qe&dEUNls8rfZIdMM*cv`zxwh+B&%TmTMzJl$yR% zia}_0CwG~Ae*PdBL)0+{NLc;+O|bA_WDk{1u$U@YJeS&Mi~fu+-7`r_$LpFlY7BSF zH<>Mr1eiq?=7&9)Ky8L&5XexWPIaBoK_U0|eQQa|2aZ8;ft3yBlWvn28pg6&w+0Xg zLz|siUc6%u4P1*XPvVn6NV?$bV^q)L4^s+mkq*K%%ShsBCw_!_n*1pd9G*vjI$;++vON^$UNfhvN zD?0RCc5yXEmlatG>KkltFe!=ZONVKpP$(Pm_R{k1&f<$>-Q16#g#u@hwcg!@ui$o2 zbx*)>LAwUq^To~&?ck}KJc_xUHnPFN=dHdFB8@0|z6wD*`V;d`-Mgj5@@b88YkbYc zj)z(i=NOIfK@t3j-9`bqM;5yF*NRUlJqsVIjzGvy3U#-_?^_Jw_Zd>VqD}0Q(lI5%|z;jbmD%^v- zMLdnM-~IzEwCdxw;Gv$PQbKoTkg=r65ys_ym>9EWL$kPbaOqd*;DCLt^4avCaF3cm z3`B(i&AVlsa!;B^4!W4lv;4Uc4%^u}m+C_Dp70Kal@+Juoml;R2W-^mHta2-$y~1i zG<8tbj~6v_|KbBf9$r% zKT&lq8pPYUt5SxG2NtQxxpNOa|2hnh*uIv54nxNC?HABpI{N14DT~ozYAN!m~~``vH=|eKwGv>o;|>wJQ;T|6h;|laE z(I9u_RL)hI46V@Nb4m9+4;SRx6n4_M6-XJEaj@KzJ;|j7)-ziB(ueaa<{F+-aO~%R zPM@t~QbF5kJ%LDP$Pz-wuHw+GbxyJ52u^yg#M3fmmQf$Hr++%SDX*%1YV=as%24yT zU82T7kYIYQRB9mhU^P&t^vmUwG6ICi$o&I5smr+h(^@Vg-Gm5u=2)IUf|9$rlqEFvgV%Ja$fjXLV8wMaQuC8T zul<|2ddC(ES$!PgAGwO;1!eP%IinC;(`vUod}GED=g%l9X5XD{FXHOiHu6|}mQL+y zrUBeKM;~yW4j&mA91sofKHw1{zVlx?M0NKQZN!r~Q*X*%)>3yiiM!z2l6*|D$!M}# z>7I{E&xC&7=XUJ1S)@}_V1Vv$^^Sy^)3w?%2XCPOMJ4Z+peyjNEBa0FHgiF?MO3#7 z3gIYe};=7^=<;W;UH>6y4yUgfhiPj;d{(dVbJaavloGge+N z!%gPoHBQ?1^>3+j=%rDMy#E)s|ZUjTKnw^`A>0pZQkgi_mZIIXVn`Ph!iCutDbbId?g{hNr95 z*|NmSF5$~@^Mwvug&iD2dF^thO{Lnlkr|`JrpG4ihu@hT4sbWs$avx=Dw~dvfY@$m z8#frtU%0K!V|L)XY8=^2w9BuI8iU|oCrm!vzuoY4oG~wQ^l1Ob>%fgx#nmEbLoe*9 zx9jfm=a~n+mb0UtzLktH*{u%InG`}0K%%rfJ9`;8C+FG*XwYt}qTCRJdA2l0g=V zG_JlTYO*L_YoI{hcpV5c&NYgPYE~%w<-KlHM85eRF6^*00yN0NOoFDUBRfp^O-7J$ zY)OR0M5#Spn&hf{U_;)W(MH4kcHy3gS0^1ePQXb;A>{ST7|U1spym}yP-}f~BX=6T z1A~HaH#om1F&+#_sDiytd;K8#71<{X(n+of_{wyl%yAVX*@z@&-yawHapdAyig7O9 z*o~;*3h6n(xCzZ*T;lUn*&)k*UZR|}mXXuB`Uro(@9>0v-RUq9m%uJPXb$N zby1Xvz_ogZ;aEuv55>1p-nFhTCSmz+F^XXXv+*6mD~vKq^VU9Q^$`&Xb@)08@~YVx zmzZ`V+dRIK)x!g9G_UDYewcUM^5E>{CSWfQAy$0SqS(Nzpc7Xm(9@EFa;T z(JrjPIyGItQ4Wko&P2apW_-cTlJ(bKop-DLSLir_5nzRE)4>|em1`A(CdqSKlocoCx$?+jJYf%Q zvhP~56}$IK^|}pP3MH3}mZjuTQd-k8%L}PHtwMgr@5WpJDB6}kD6gpYnaAl) zFpQ$TS7OHCeA+hnSiv(bC)+W50%7ch&Lf|mrv=TvbWX+ulpc6QXZ0gARtX#U$-=e3wGNP=$F;{*`RLs6uZ%WoVv(U_++-c@V zUDe`idE2NITYzHi8CDq;9Kv$B1?1sQ#r1!7tL0~+Ev&CM0m;?o=4RfM!}*fV(@;HGg&#jWPL+O@qHxm$)NLh-O6##01a1g`+!9#j^*R>@*z1^y!}FfCKgi|@ z?W`}zJ{3)iWub$1F-ZYV8~3IT)dBkHT$wYVoPPLNg&4#COfXMxBdg-E!!w@L-Ko7F z_DRDwFa6!*{2x3E@w!R#OKjC8oSh?7(@~y?+lDBmi<{YRlX1RWxahCiG|M z&Bw(}c?2e%MjkVF_~s3jfLIR)G7y0@4Kv7^B*xL#f4|JIR`?qKu8_R2O|4%xe~Z&u zJ@rs7g_uWko}4F)lNlFwRUpj+UG@DrBb#^;&$p$O&eos%(lpg!=iUcCq2zmMW%W^P-!r`>RIatZ7P)bV^)_0Le9$0)@6p&N5k6G>G2D-PapjkmJg8&3*@|vJ5e1M(D5Og2q z0(2_qq9I-ZX^>hzdzn-PXYxj0P8Z3BX${QE1ZrYf-^HlYM_QCrre!`kXe}k4eS` zbt{Vzmg?#Et$ps3UOH*#Y5LQVsnkjy2o$AR^Mhz5kwGc$9j!wbBwT}B(b?J#+;Xjf zNyDo(Mb1(1s6^C7td91tHNQ{1!S{?u(zfooX12C5WMcP$-s2MSxKZet6Y7~Hr7v1u zj^<{yPc<$fd|NVwwtPY>2_fINML*wlYk9PEw-!-F9qbGDejLr2EFM2v*l?PW!)RFL z^P{^oUsIsvw5h7>4Kk_&L!Vwl95pkfxx`*13rLsr2MzQ>wRBNUi&586a2>C}M7WFId0cG5|{pMIRs1O&?ohIn9xq#By}mV-M7`xU&XZ0;a!tk(0%bTyvH z)twa8fyD}4Vtw&NlYNoO{|gHgxI;tF zBDUxHCPSrLC(Urs&|qe&>%)ZB{1%x@uC4E&;U4#2R%p0crK~Ai<l zY9&BG#!d)ktRa-CXcmrf#0on&04Q+kv3q(Tx#J;pVAM`sTeG46+Vmz9s>&fn4SdrA zkf%~#_uIM-cl)9hWV5SJD&h1?lchE5Z?fdvWV^$oJNmtyqHY9Vde^CE?6S}*lWGzE z`KluUS5{$83QSFGxfh4Z#xB|{F)q#q4#EHC0%#6@s-cSQb{PN|RFfB?8C2K+-UxiR z_aMx=d4$2(So$hd!Ssd+(kp-eo^miuK}N=i0{tlLExkTBoK9}8TF=~UpD9$mJu{V{ z(Z9Q3$H&=P3cy4AXsscygx>zW3usb@ht|-ji{q%P^%3*poWHFNQZ=EQ{3=u)%n?n?-A%dvK@kk5Nx znLd@v06;SE=k!&muEqV}$$Dwa^sf6lzQHiBc4^YKtsYTW%?k{rtzLh<)zEZ_FaI1u zZf`ocgFL@C7?;e%gU&8LS5%rVt(n~X?l#bQ(_@MUMvBmcf3#XS+rA$P&oD8BIxpQt z8O~?pn@dzU89VLsAa~i5FEFfydSUb9f^y=Q_q*- z=<9>p{q}E(_vG?>=_0faAvm-GRO9e1NEEB*Zw!5>S?Y3M(|M?29Tspf$P-r0$7A5= zA%5^Pg%{)QSeo>+^@~G_C1dD@?HlxqUN6x`T2avFns^P>0j!QZt67vEaadv(?(>!L zR+TS+7csug3pvt=#R+wslmtKkosM=S$bXW_SikB~+^z4Xzk0GyjG1HDwYVE*V$=Ep zj5BI`0N(xl$J2FtN#>r63s7l4e-r@RWA>+`xN#kxQqr#u>s+>s5g510HqbSyB6Qgk zcE*^K64`|Fh6Reovcpd!VTtHMd*Od&`8-B>o9u#5^;%IjVFp^3B5KhvNu@<~Rn$i- z!<4pSX6qT!YzVq~p4`U5;ZE>hx+;-!hvy;Pn!xI#puopn`xzsovXVoF{yq(F-=xyxvw zB#Rb`$KxNpL`jWoRWZARoW9GCs_{*KR8!Ml8csXI-w5i>h!MB`^j!|4duXHPw;2G9 zw~#k4>21<~JGEM(ohos0z{6PjaHYMvA*im|q$>?qxL?C&pyP@T4$S~LWBTRYrJcxq zIF8V8aVd6@=@mI^^Tb)$mgm#J=G8Z#qUvJ3H77wEU~W(*Bfd7+nc$s2LKxjXskOv- zf=haG1uen!YDmtQ;s{fZeu^JBTE<0*RTYYzk8Nk{1DGhrYcNnSC@@)5`Sk5LG2iMR ziGt*vP^%_`8IUzt&K*qX;NBih1gbv{BHI|hium0br~Y8W)YNci5!t{6<>lp7GSzlJ zL95igDy>~LDy7}`o#rlVvC0IV1n3qb6G}WxZ>E`~Ph;P4TQb@~RMsSZB$J+%vfF+ZS?f3@l$_(9rnG)EAf)qM6D5k6z<>R?t`o);pE@%I%{Z z2+IH{#W)7>dQ|MjuAuOymQRLwy|@ga|;f>0AG;%~Vv++F1yH-nj8xQ@J+gy!2_m zihNyAiQ~kC`M2J5v6T5O9z-JR=$2yw%7{+H9?;mu$y--1rgEz0Q#1)I|Byi2GzZPzw%U+V6oH4Ym zG+W-}W#LH3bPT_MSpIYm7q$4@^HSMmu1eNtddgs?w#ZW|Yg&0B!xeHU7t{z4hY~hGN{E zrQhUhp>a6b-tNndjs`odn!4f6qz!F(A zelMKrz3M%{Nuiwfm-H{c1z2-7$F)Ll{_kKFF!i-Pp27~|l z-@!^?@Rk1=tPBSK@xO!bZ9qO#WcXb3*8-`ivY1=ZO#eGM$nM?kBdV5Yh1Kl4~cD7$6=h<;sRdt(X5~j)amg%9a}o zoS}YJSXP$MyGRhZL!Ed0nc|+m{P5@~1wyE<78?+w&eGb~6fZNn^$Ej9#iYNjmx{S5 zEH`5NkNb--2RK+-F@*wDJ*@wxq}(r(Up;QkIN{kh_U zyMFb_pAYVWcIgmqo2P&Iw|&UrjW&KCfl1!@|2-%3|836bh%qCTqmoIGwy0jY0K3Sp87_;k-~&XYXAmV6?+91hE06Y<#tAp(C=GcVot(=PI+>tx z2)ulgA3}cmpN``N#b>4)NR$Yl3DJDji(Hzkyat-2yFwj0tqJiCfrWbi2`t53|G4dg z+kjN~9x$nDHl;&tuEDoVP-vz+#H<1w*vgRdcZL9yA>ln!CLw`(*!Jr058668o z11mxe9ajF*ek!W>Unqn~@%X{{naVZLTZQ^F{Nr0rR^S*UX8@n?^o#P8Pm=%h?LU?U zs75sZ2n^sV|BsIFiMJz}#%>(02qF1w#SKJP~I_W24xaIqdfbjQ%NM^K+OBBJc0 zH8*s2##O}Il=T)ZfU7!~Qnsvfdk99A3g6~8K_Kvm?{#C~cTnX?YQm*W^(}r7sw_x8 zK>=Qek>r(Xd$HtLhIvsM|9F7eAV+T%W_A=EFS;Z1fS>}fO$VfqV_X7tpcGXwiOmvLheqfi ze$RUSQ)AOd(O%gszx5`g-ATVP;9IR=Juf^K8;jkPcu;Uq7jxF)kYfYIWgGY85%vcTJU;#`mBgtqhiolP~&LtAE^PxCS_wmhj#%BaFt#Q|)Ad+f#ckq5jr;4nNre=H6SWpu_Cm z{Q!XN%mw)Ed=GEE{)@##E84W?Q-NGHT^*}bLBWR&j2x#wgapWc!ypL6<-GL!D8o|o zg6$revflmMs{V8t=o@+6BH7L=Ne;6JX=hoD+NjkLtuHU|y z{l9uWv{v_i?O@(0;d{qSTLfn-+7(+vlJc3^-8V2cz7FWR-JQL?2@s7mS*eQ8R?LY{ zsUK8z!N*B!Nk1<)OsftU)I0jtFiv0iUfIcdi<0w8Ki4z_Xbpv)1GpXlcyebe>Thw8 z$^>-;WI5;KuzIE*{(0eEoHX9CAGckBd7hXX89thj z8<~*pR{M*n#c2i@-}UwN_W^euyK3m@SfH6Anc*?(tKgZFpRXz?D2U2V6t(Z1_k^P2 zg*_2F@TuR%D}@TG;Ep=iDsfR6@k z(d|3F0a~*;PmK3)psQTy9zN0H4UIZ;fk)WBm!4 za%bw`Q7dGgo3!RF;j&}A_x^6@e(n1{bow@QTHRu%ut$$nG< z3j&nq2nN9ctb2i5e86gSX?rayYthHjS$}1DwjKeH!oQt zCl={h3o=^DgD3xby~waQ3F!L@3YLV?GNT(zLs9H9Ri5+r6T24%-HeQk@;-*qsi9D4 zv={*Zt#m_832?Kd_5g#zZE6U#g--yDvl{t2cRW$Lgv1(ZA?2y- zH~s-4e7SVQm37x~`8fn3U#SS?FdSKq%i=kCbmE~g&3(*r>NVz2xRM2N11bsM`m(kq zYRY;8<)YAkzMlQE!a!<-2s$q2fze~^m(&kQ%E3HLNO7Z~w%>KxdFy~PX?5m8-6>Lf ze!FW1pxL&wip^_mYy{KS);`a?U-4-APNI6=3|+76_ABK2q#%?$O&65^{Q2|zeMz5< zw`b0r(bv_@3=O4D?6w2MZCiVL=hom8ojpBk?+ypG6o!FAfIuzx$474kkcs*G0dp}b z`UVDEP}54g$gS<|tWrPna$a@NQQ+7r@?c3t0o6v2^*D)`d=j{|Ic-rwI&t>EA6ss* zz7NO+zAhI-PwKK6j(z3c3&zpW+_#mDfH+okWuyys53jQB0yrQR(6;>nV3J)rjb6LM z10o9{jE0-gu)d0}4ck3X|MAn(8y|_%=80c06V^`Q@^x5?(7J_H(KX^{z{_`!in7;!Pcz-i+Iv0cq>8B@UC zo(mAhLv8bdMY^=U8ay?)3~#@kPVQhvS7kdMz++7;O+>?RGmuRzeeCQbRKL+kI`2LR zf(GWMd#2DArVEIMV~FmgLt;BvKyPwx!-DOyu~HEw3zCQ)UQ)&WNaTfXg8AG6Aeaes zXIdfnGvh7&b(*_t_L8f4I6F@(bBK@b;0$ZUI5nQ&zCJv-Ul{9B+j&s3ZKLYD@ZRG9 zsTHz=VMR1b5lvtK0i8-$C}@v@c|cm!@X|{)O-1Lrr;6!p zj-)A-AM6Q{LIGZJLfFL!q-^S_LwJWkz+>OuKe9wKFl~89-;nBMY*GbTX$(>VcJq)n zAe31^BP$*Z3>rxPR$OS8ZkGpf7&YpNhaCL)s6>ulWj}I@*$<1pR!h^;c-QN*G-+wg z6F0fTO8jbDDf4skr<+!Y+nBZhl<&uk6==>Z&ldX1z01-!iyAGe$}sRStX#;&z(H-@ z{CMP(&>!PBg8KRZ5=Y7lFaTsv-AaZ0l~0lZ5AP=desRv}(@0$ZS}*Tz_acIs=2wM4 z&g(sD3+T_hH{Re~Mrn`^p3tKGsI92zp#NmdWhD3n4H@1zGGZuq^mCg}NN8;7lu zyi0mChsV3@yz7?S+!^0F5>LRl$=6Ece6DR7D>Yns4go}8V#p}6Ab;>%323=FnI7;J zI}QnZ$1fjx<>4E=M6;SFK^tHSkU1^zKYfp7%(54k4T0DR3QbrG?55s`rh<44a+fvW zj{t3xvS9)e$-JmzJeUtWVbi00Qx1y;ZB4V4pkzP#8`7a=UsHo#XT7U3qkrLwEK-^F z8d;+I!f^{eOTH%8R95&g2`Hk4+kWxk;Y{NfcU5h?YfZ8*KN-)>J$A`p+e@XLtN;rZv%V5}_uWpF#R3SiO zK-EE3^2nLQ@L6&vUL@aB@RIf)Jy4WuEK>JwuC;7MI-55A0Vtw*yZrd7`b^E1mO8?e z46FYiu&u3g0s010)0@Bp9qiXwQyfxRNm^MFvgPXOk3V<+j<8Q+vU^+61$udWQc@<> z)z#xIK`oRgS3K{v)NzJ@kLxv>-MO~A?9=0%$fBx}~P}uWo~|T>6Sf;Wcmz;DHtRQ9UkN0%L0!YIm?_eQ8wOS;H+U z?S-e#;?Q_Fa4dL|wb-#j1w*$lYSC~4C1)QuHz@-J)j%|(W|W6*`EK0uY;{Afj6^RSXS`_Y)q)FyIEmz_#Ybq$S#OKJY#_%ohcWAlBBJkfE(F1nfx z8{>d;X4q{0wnDi~9n~x+qhy&XuQ-UF9bTeY!c~|abmgh&kAEwakyteX5L;RAo4#pK z-YiGBuSCHU_RI}muB9d9)E8(1DAiSFy1&I;CO5he4}i)X0d91lcmLOO`wkp;c>zfe zF!Dg}JNHP^z7WtWV>=*}@lEN^op>pBbml%$OU;wozqC(bx;GK<*g!vr1Y#3;#N+}g zXL&X*?ZN0KciG{)vil(RbiO7wY3x(j9-gG>nImtB)#&G%b~%tG4#vf$6e5JnSWtS# zv0v|A9H5RT-e)x<)hC>(+UK|Dm&>p=N_^^{pt%Sl;kESrqgu%Z?1PcSIXV{8ZPSMk z_*PrNED`YTVv{cldlzYyaTN9U%FAW4PL1(LK(}_UdT+UR(rhME1x z_<-tYZqL&Shw-wCagM<`brd7HuWk`JL|ff4$; z^zG&%z~ce+mO{>+8ZZ~UoStnLbej^ugRs8(qfO0fQmcVRt4;a8pl70H`o9uW8b+ZZ zGKl~l%dEC;KPPC}+=wM%Yu%$KEE;`0(xbqKQL0NeYZLXDg(PR`SIf}*_XnyR2Z_W% zEka+05+$8w5Hin)qPd}GLTqZ>aD`i2o&Yi%b761KXOm}RF%Wg1lnvPG;PGt00btDt zJV+Xbn0|8KC;emV*SRIm@DD&ifp;EXb(3B-t%P=}c@);w>{U5)If69%#o4sCenA); z!=ZK~8*a)I8dVs*A9H4e2x8dG{U$R*?85`%%}w9kqe}0oY1h=ny>@r1A6g5R=#Y#;(YuWNiWmjfwCKhqHCbr&Zrt@m?QeL2VvYJ)H<)!$VDm&{cW@6(%3jX zugCRtK{qxEnF;u4m6-GnUuJrizJXV~(ts*Ir*3Jo^si>4xI?I8R z=J85jH;?1kx{yhl(O~7)*SW41HOwW|fx%qSzy=1~=0t{F&X>(@=K@#PmqxAgu%w)L3)gN$bM#}2Z%t+Rlu6i|Tzh0G zY20b4s6ng9@x953nda3l(lT_qCWqGplL1jmzKkteXw?bWi`2u^-_nC#o_=aMQdKA1 z9Q4Sf=5jM~`1uIaiSV1_Iw={cEmFmdtPP~^<#xDgkzP4VsL12S-lJ@ciL)p@u~RVa z!uV5tJMKaeQE2kzDSoK$7JR?)T-rCbb7I6ub)RC}NBVibp+8F{Tv*Ev`b6=?(r9@) z?6Wtr7WPv(vocHbN>8inymE?0m$D1IzL^+g_gW2d^dOf(udW$VGgC=yPvlhih z0}&MlVvDI|<*YA7xsN+m%ziCYjU0{Ja~$9LVG()!+qrIsM~166eb}bCvmPoxy|C*O zZGGUk&jKIql*I+vwmsi{rRIscWG{l}cbDotnJ$Zyzv|;zVXxZ4;uj60=O`JSG%HY# zu6b-ZrC-dyJqT|bJPG$qn*G%&InI+`$`}_Hw-zs+){5#-R#u*HeGGK^&r*g8zg^Hf zfy1jxTMo&mGcGWqJF?kjkaaMst>bJ8dtN7Y)KPSyczbU&8Mpsk&C<+ajOEJiY z@19cs##NSqHgYRSp_evUVcAc8`pm%bw7i*jBfs#ymZpcPhj6U&fx*1bi8TI9ho66Q z0lbc7jf)uy&W{IIoo4KWS*a@@tmazn_G+awyXVY4ZX6+vR2d`6G@oo z);gV9H`k^@SQnSs9hP_LFLTE72pmN#*>g#Kble zZ7L{CW)`2E+8B4Tlds2IalOyQmOv-K?k=Y{EVhJrC2{0c)e&&ikPzz|Ag4MorO&`C z)59$7v!b6&Eo%yeEtSu82}ji~nXL~&QEtM$15F9S>4&Gg-+Lia$$Oje%u^OlD`^#x z?OKt&N38O}CV(-kv`ja^Vh- zkeL^n6jHr+)eZ7@w)}qPuc6UgGzwMazvs!W5NOWM&Mxh@Q{2$`A}>oNy3@)d-g~Of zBWv{g3*m!<11DF6#c@GlVIvop;@)x-6O+y_U$pJ*^BV5FgaD1|cyQy(^rQTY48@$B z*{R!W>+41;VcUP|KYW;RhK2^QHX$`UJnV?WAl5vP4LDq(eY3vIQ+Kh&lL*4LiUCe; znH?Jq4zc0ZdOOeAYrs$|X(@OEU`@)B~y#in4qABhNmUFF>CoMkj)AGC-Up3_F zc-J_io3~nYpntX_`Kfiye2zmv?z;Gcj96BVlF78It8S~q8Bu}h+v7U7#J=r(7!%sP zH_UD!6x%Rio>Z_9ZCUu$xU%=q6>!h3TDaMFTSiF)VpW+e+l7^fULlpgk{dG{ff~){;isJqoob}( z{O!|scY>NJD=IoOz%9Grq=05&&xxoAsFiL6&h!W|P`WRh8zj{RrQrW_~I%B_`6`g>CPc(9iJ*k6B`IV%*Z!eiG47^UDInrzY_9v4w zozIFte3!s;>`dy{p?qA%$--oWL15C_hL?`m0L)RqsVr=BQY_9K~~{$+qAuV^|iwQpOy# z-5QUkj*^JS)4O(Rqfc_uXTBP&c>;}$8rahzJl|VgXDaK7VRlYKvVtxC-cjGGgNQbc zTj0vC;Oh?B7w$bHl7(!@-eZ(yF7ICRTi6hAcdseg+Llh<*tJbIIS8NBNyfJqQX6Eq z@!KU?+f}z8M#G~{YT0cYd%F4Eu9XYYXJ}ALuAnCod#VR}1YLFdI3LA^9tTxrATrF?-gzmUZ7 z$%k?VG696AkEBElU8gN;;+G45-fFQ{*xT}8$Fub@jw}$YtuL|q*YA_i{PpjT{Vjzr4u; zceHqkylA_$vn3GcE45}Cri|Ma^=JDi8h2@N-^w?vz3p3rMQP%uxEXc(;$r>TQLmJO zkyf3uR&=(*(UJNIT_{aPjLi=F;pqkUu1jgJvt1O*9y0dMW)E89#$@A@sFjJMASqfm z=1*_I8L#XOMfgbKPrz0!ShO1h4zK$Gv;^E(D8B?WFBvICHSdRIcZTh2f@C zU?!d^;`@&LSD@k6jHkCRSmm-O%kKEq^e*x!gqdfc)7jlOr9KNS&j!hIL%rzb_wv*_ ziPe$!Dw}cIH(0Wd#+%L4P0(fQ91eYzh*W6>r{Nd4jD+MK!hG&F8NW8@>u!=8_@mU8 zPo2#@Oms%)k`<te?Ylhb2Fr_L=zwQ`dG`hrayz9~O`%dE-9 z&Y^D>acPm$Wx1pBR z;swnZHfrRQE*n_}RM)s-8HU(s&YZb;;X+nS%wNFm6}^3XTTV_6zqS?+iHnV`YiD3& zEUK*3Lm&_oL>2s4Oi!8|zhhwam`C|H_6yCY*P^?xB7Bdl|Md7`lF1R#RgiYIn$Dz3 z%zH*+B_Ko-*#5E%V*(y6JenUQaO=CUzm>OYivl*MM5-h3*!dV2m~!xCj9re)xv-t8 zo#j2U=0RzO+Wz?d+-st~YZ$VYh+oA@6g&{{pD`KEclKF}QtNd(>pqFmNm!t^aBTHr zoocGn2Wg@#zt_hV=uSSL$E1oMr@O4BUq)$E%y}{S#a1e8E0=F0xBa#;OSO!C3R70{ zeNjYj47b?XSNIFU?4zPGqZWNgd$j#|YfO!@lHq!L0;;+7X72vjQ}Ej0(bqYW-Dk>u z%}-7&K+&i#Ow}_um)g2b+&14yw@cZ%o<#Aph)$iM!6P?F&3jS-Ah1Vj3*zlV*V*A0 z(Hyw5YX{i@QV_rhxU$S%HtlmkjF)5e=9l4h7jf6YN`{T*{)gBmwUp#i0)C*M4(HuA zZkysP>hS7`oy(Q4c0wO^N@9d6MNgted^QKnSU1NP%nZ`f%N&gKO90vFb1|&uxuFo8 z_C)$*xB;>WAl?|tb$4PY2U^9-?RUiVil)VStS`Yt0Mi?LrhNKP`gBua zxyta&J+eZU3}aQ}Dm8t0b@b?DWX9GaLnrwcl4f-tyRBeALuIS-9@F4+D<2s53mUse zN09m!93fDFcwB91h4>6^KE$e3TDiV)&q#~6#>GM&SggZe+L^l~n!^`w(B{3#+T)z_ zK!RmW!k}v|zVyCvqY4)1CprkpGA(o&H5bfu32#ucy^2#WAC^h^s#LVzEzK}%r&`%l zFd-!VK}PLiK65btXN>b8J?jq{O2^Op0S2+V+YhKJE^KNu=0d{^`FpPC9W#<)m{}YU z^Q7mS^-$RWh~TSkIgpel_SbXoyu3W5y2bNzcP5>$5^;c;x%oa4ItUi>az6YetHY?q zV$)ob_#6YHw7h)Sa-WimYf5OjsfpihKMz1E$o^TCqd^_x3B2ut(42??NQQ>%BN7OA{Hny^>wctK0FF%zt`>bhU2ENu6Q$1aFe6i{Lqx9bo4*{iN z4adGJ2vAB=M9uv6t&;|9&!oQ^KM0=NyA?p8fh1A5v@W%uya(|f|73)mI74Dc1*gj@ zcPbLwl`vJL{F9HBzn_L-xv)i~?&1gIJrW>a(k`T&9 zhpOfSd+jQs@)ypn+yZlq(+%9Nvu&1I3V6%~qWea$N>8tz`V0A%48y*P@^+3^TKe}b zAIO^~F12{P18dm+UB6dx`i}eER-7eYzpBPfE-aL_dY##rb?bcfIocS;uiatNtCxu* zMh|w~nWIV{-f&rneJy=_eFTBWN|TNOm`2dtLrN-0RZWdb7O(`jcXkpvx!fsa0h|(- zcX{c_#lH zwlle5UK2LajTU{WCrj+Gz*{Kn$;r(l%fd3-I)UReQw?9rtr2s+e;^#Mr^^I-rv;`s z^86O`U@jTry{OQH>fIIHfG*3^Bi+%eKH~#XU>&XW-hw8Hq~oJ$FO&_gt4-iX>92Eh?d~aoF^) zW@YWRYFI?G#+;eooonVublqT+tvT34kUn>4z1mq^Hb}U=_hPPcmvl0DiI*?;WFrlJ zAvex*mT^E>?@?VnzxbZz<$(&c9lF6<`x9`gb@|+hpo6EX?6=#80bFoQ7EDN^-u5@} z@Sq0vS#L*Xyf>2QWX`s-9}rp5e%HB_bZl%YgUKxIUv?^t+6{v-$TaQk%SST!a-Wd8 zivl74i8v~GGa#V8xL7V8jJ~zf;UAa52elp4l;OikDR#MMcD0_L-S25C<=+#_@9C#E$|wn*kEa6W zj`~E7QG~`se<%mMlqmdj8q4RSO!)!lZy-?wt_!-wGB};|wI7rp1B@xaxuFXfg>^#W zmj>d=O77|jmsXNdZC|rl89|2Wv0qpmXeZAwz*C`Mazw408%e4rUK$;X+&6%8^H|iS z##aUEZIDRQx1Elks4zRCPb$CMUZ!6O7O2cMc+}M1qysoH+!{Qd^#aZ?7uFCw-i9P| zgf|KuL3FnsMy(@gQQHk@22Hm-!7gV_4{>RFNqP+YBiQ7W-T zijr?N@faUJeQHON2+h+1MtHLb=D6(0uKCKBH8cAz5V<0W5w`$61To5ApA zaQXw<{BH!1BiSJw-4Qm_B4Wp`vxUt)ol4fu4NM>RRe7>QtLH2ZcxiS6;OLGUEcwAlL(M2)z`2TgYas0PR9!m=Et z=o?!j>wK5f^Ol?d9Edjk#36gxVJY|#} z$IGF0+;m8d-bultPQV%VZ0d;FdF^mfexO#EL*-7*MG1h|QH4{qKfcaLkyO3i<>@Wt{#UZ?8s+0HG9ofs8M31I&LHK9?e+E_8oR3GCJc|k> zl`~y6^*3ME|1e{vWg*wahf%@-s0?uJE{N!et58*E8Buo=FCp7AX@#`_H7Bsb7#RLljvpa z)b3jV$EMfByLfpd0mzssK1&k>@?b2NRd&2JG!iM^#VQp(7OO*;Ny`^QbpU&6_`vXP zj&6|wJ6BEdQEnI;fqEQH>HI(qVsho8xaqj4<%a!p|7qXDrRv>8a3~_$)MWdXI`>Ua zD4T8)A&)e~ssvyml15NCLd1c~;p#qFN7t4*HW|Wg6v_xcVnCAUUqSTFm4LW{5?QQw z->7nEz%?Rnt<^hs-lWF1dyppyJ12r&q3PVbPJq)c-7}U>cz_m~SM3@s?qB0fz7!7y zX(6@lGAP0dy=y$a&JTP&?)K6wt@e`$#Mn6%aP^V;jPAQakx5ofzth2U9mS*^HC2pZ z^kP55K)=%ena6F7HFf2n7mHB=q`d#EX^4Ca!T&nsUF+MQIa}Q)E?-%oFzR=4Hls#04jG=DerQ zqR$tk6FR;$&s;dnJbLh5!R5K0^Ij~qh8tQD06dnP^M>HxUS~eCA+^nyLV5nL-hG^v zEX`z1Dc2N;HEF9&ds=rfZS&;8$3Tl8Hd?!oC3V2!Ij7BC@>sSgmkZBg?cI$5jKM13 z`B5q$#3)qiVymOcTktnisHg;ckQV}KiL$QcL|kt7Qpk>Qf6@~65xw*Hrt*aU(xnNA z*%iYlxth_N#A)xq}NohRB+&7o~iMUOsI`zJ)i)BLPtu~}DV=2wM(=<{O^8j`^ zUR~#7CwiLsuW>(Moxjf+`mUq7;FaPGP9Cs!e=jle_c|*7{c`{L4EsNKv?B$s$iBp( z=?(BgMX3P{KG~N4x?BDkuv?z>8-)ndf|_W`&9!?trQzQh0$TeR7ztGN_Li(TihA90 zB1snpFrA$U4MR^Wq`0(y@8}Q#uTT*Vqw8~M=YX8fF zzP&;Y?t1f^Twx?y`{W=w3ZBYAvI<5O+uRsexVbLDm5U5TJyZXW3P{QupS03O;IKZu zV>z{k?JMa{A(Ej_YuzsmVzUaOD}Us-{(FId0Hz71;NS2Hq8ZV*5v%_zT`Qsl4@jhq z`272Wg8JX4`+psW2X6W-_MfL?-jKWh8{h+%KYsb&ADDA_dHKtcw^InAXWyx;5)%WT zDMHBpiBGr2R?piT9^$8)*ja zuGLWHwFGufi&7pvH}&!wddI5pG~*og3#Kq)io{;i$Givx{(10_!(h{lI`J*_9b)7X zUqwGt#{1I-AjtCLXgE7z291fskpnLxJNGbj*XgnPD;BFgdT{dPX+XBiVc z4|;k=6AgN-{3pG0Hg1nB!b8b=<{hXc*hLLg@mb~wVfXL>PFFp65F)YENhy`90u+2|3BQseLvf1S0%COxYM!?=NA ze3W71qh-Ia;3Qn+iSMWM?|22oQqXhUOMfe_Am|kZ?S8qx6Yt|bKX{(`(~jHiXSd7p z5gSB~cHAAFxpj(|3r5QLM-&y9p_b;@S}WZ^j^+0a&EmkWZ0kRqYj}UI z=p!Fz<3K1}84?o;WdEMBaaqnH7EaZ_K|C!){k9|{MS&WyxEt>x!ot$NRxG~HdV3S_ z9Wk@4XMa)$le0GVL^0?C$JG`(upw9A4jjlR>iuaQiIV}K6q>aIe=z*r zNQ#R%H}{t!hR7jRA%N?y8Q7QL$bPZG;=MM<3|z;g(|?2ImyKOBD@Y!*L+HTz(yV57 z;f#g_F_o+h7Q}*$r#+R!>w<{3LJosV@2m$*!T;bu@C1NV@Pl`|%U!I91Bma8`D@?S ziu~ORaFAK4VBHU`9L~EW#R|E#^0iRQQj+kV7b9B; z-gp+(W8xI71mu|&@LnSjbSsMX6ZA;h}8ic{1&3AmTKn7rXV6s1$!!j<*&JJ=(QR9Jtg_|H{V=@y^S9i5AA z4sS#c-fd6^E9rN{_y3_pQ1pEhtbKwEnF{Zlp_f$%p8P)K@hnq87>3x=j!F1uZ86iX zvw80Y!Yjum-QPcVP92pI@>DzF-%B^s0^{L$dM{KyRnOX~jg(TU?A(*uqkoYa&_+YU z15~mI1b2K&^=95-a_sa#oCW>&WA?8{y*})D$bJ6TEy6+<-U#j$-TWg?Hc~1v+6>4N zjyiY|)l#-b^7;A@9Tf}yGaF(FcZjbRPhiu)$MWV$`PEi|3}0CCHFu7U6TD7^55&PX#ewA9VX8GaQ|L@@c+9Y{XhHh zRP+njC^YdMMYR6b15mtX4OhNS*4Mynz51M@FfwnZ8Eyu!hfmuVDfoV8 zXCbr(UZo_FAf3{WF)htS>iFc9eh>NfHlK4Ww0Ws6Rt`iP4{?6UW?dBFtW&vk{pF;FQb?pU1+}PmO=?@RXDB@wkQ25d`^!ywZWUB6eX@Ysk@~?sx-5Ro|HAR%G9Z6)dmM zRu_|}Ay^vo)8U6}7Kj4I@V#6?Nl;($^YC`H+CXrx3>L9qf0W`BQ(!VZ5BD(qkeDnw zx^mCwVmyzkse0u_58*JrpfqsfyN&^cWLJGEb4z!lUAR*+BUwlMIK|fDe16L2vve}V zvp@D&%F8>%zVOCDRY;+R?J&5`sVQe?7E_i7V z(J2hJy({uDpjjM@WTzFP?%(77K&>IjHt>byLa+Aq9R-2eXjp>SqL+6vvi)&BFzoLX zYMPWj$3Cid5w$My$K9au)$N0IDgT7D-+n}?@t^6W{GF$oGk9{}=<3qn{8q6J={*LX zt*t+vBnuaLE!iU%IG?{AoImXY9Ym9&b4`2rIo_WRIaj@@%Y)-(-ZAd@Cod}a%5Ml_ zOySDi8iK_#%%d>+_v&SIQgJx;oN#RU<=px3`hF```hMa{_%r4tr?f)Dw3Jf$8cn)h zE6p&zH*S?Jk^)B!KVJD$7E_XI8R=gbQb}N;-FN?Mt;FT|lMEnTMHsg{S&L-Ts&2nk z!VBy?TV}VVvqD;XWG|x&m^+s2&tU!2 zLU=&Osw1xj`~Dn$JNFEz@!fi;$7N?&I_^#`n$pz|k9=vGLC!^;#$c?gqB7TJ$jAQK z4(^+(OFFc9rZ>X`Kp$fJ0B32S?X3>*QV8G|c&7r8F%nQyxw*N7q@>fMqcK52L7c3t zUjXlf!P$!1D){tR4mD4CVe5Ii`@|Sie!fh>gTtNIxpBiA0`JBrDHiXlKnR)7x^d>V zSOU1JfKVvn)e%6ludv8S4Z!aKyqO~>C&!FE)r^zSoRjdRyBTd2d|0bGm_NY6+eN+f zyk6dEE3Sj{$bL?WvU$qwd){7I?OAYKq?kX@?*2YPCz7$@Dt|RqJDCk5@U-Wg2#A3BrC=0PDAk!lpnny zZ1@y`>q0~iX2*jdmq6MiRd3CA+1UL$2i-;*@p)p_H-&|jUl0s`j?GpWpKMXCx}fcq z`L07%SNjyPA2FbN<3v?IWln*aDVCk1v&I1^dxeywPcIo*JZR<_$Z?Kn0Exlm zGYv}}v3jNXE5<9~Q5QKTaRcL71a!lE;n4Q_aAx_ zGLGH;bmzVtlV~RqeVJue+`CC=ltM#@c+Lmt(yK!Wg?)**k>iHV{vaN)`gVX&c0~^K z0Qw-Gr$O|K8%=Q>ME=|$Izq19d;H?QY}Io_h6en6@z(D3c=i?5yyNC6Afi70z)|VI zmi4SVsUmzb|46qG!e3OsdPG3lXzCa~}*4KVH zu9m-0w$&G@o5!=1v?NTMxkun9$f7srTCLvb+B9KrJ&d~L#vqn>OsIST znI%yopKMn`dMogrb+unbSQNi&HcQ!X_R7=p zgk6nqS<(Q^P~0wC;wi&_jomLiyydDNlwjy&3__rjyvK$IX6ACSnuRzFG|Y;CY8eQT zO)^faRGcH`UUXaI1A2H);`Rle@FK^=*|J~5x6dbgjoKypwA8#vue@u~hG2WVV^{Y? z2lWwfsAsusA=B$Gobc^XWG4Tbf$F)F|PrYQ%w+OoHk+KtjO=21=Loa|EHMxjjl)G zol~MwOi*+FCp_yf8iaPSbLjkkYID>9yNt37>($1jK%(%LC0F&6M;x~L7gBnO^#G5` zidAH(Am>Zc&@u7LGN^@7%EHG7oE?TMK5ihEYDj>rO)(7px3``HSqx#irLgOfXYmhZ zCMW;ANi&%Jh4x8&;$U9ZjnTV%UB8j)l9i+|_Njd0xM@;Pq^sINM!sH-j_S6rr-09a zfFV=FvOFGrf#_!o&^DmHH#G%50ZXw}USIODckjIj-oEgVl-hSVV%SGYUjVJ)dG+oc z^o#`6n{4CNpB`}_Y7}pkfA7tjCpj1Xe18AliSUKb=wPIQwW<>9B91REgvbSSSO_lp z-fxnq`%uvDy-jL*BcfTX-uJ0(JtJm5Xdn)J#0?WUsNm%bEfkh!epuuR6PXK)iM8tSTq_4xX0;=|?yoK0d{B-p}(W;#hI17%9&<(9Z2B+TnvgTml@Mm|Pe@BOfmc z@`d(Y>J0>ss-<#kUDQ^tHg_<*Nr1}lz*`RJ-kEEqmcrBT5>OkSv_;2)zs~@bzOUf{ z0zyB;kN>jhgULh!Nji{3OpZx4jBgCapSUIO;I{8xu=%oKKd6?GCCnRM+}0cB{c}qB%c; z^Ul=sD)XO|Q}p6i`R&bwZNf)hq(IH@g0--$yZ~Z4VXy0?YPrL+SZCM#1h?wR7R$>W ztrnxO!DA7NJgseqIAq=Yj_Ub~x$j^ECa404nmgD47R2u|l6%;Hn&INB9t<`(@r=UE-aOTyAHY zcRcC1r95pb&(>8`#uaDe^eo;+?swcJ>iQS8Aav3Y2t9q$Z^Q#c_mjEYz5VV)(?=#O zEODf5+oy4iQKLn9pxy40@Aq9S=l3&OV16Ax0n65%?#6H9thTDzLzwFm#YPa}>3862 zkkKgSP_MD2;1?cb_gap{BB~ zY^aH5VJQyiu94TO*uz!)e}w`70MH%6>Yf@u&TP3Qw$uh)>5ZxD z?s+DVUPzIV1sKL`*#A}zjBcRyYH zs(;nD+avDng3fYwPcs*#Q?BhcY)Joh)o{nX_}fU0 zRoS9xj}vw(RIfF=K3K)tI#`y`Fg1#2WR4NOQn{PwUuFQH@}$es#nEZ`xXV0Mt~7UB z{Tt6sr~ZL^NlTGsuRZ4%t$y*CF5m3h30|ds5;N)h;{qg?>O7`(?O^*&Z|>}ob^Nvvnt$JOO$%;XKq#bak9J@0Yl0KKU`pBGCS~{%wApO641wjt`}aeRS1N&B!bWv= zHnG0PEAD_bvrUx0ji=#Ea4F5UwIQ=QnFyP`>Rm(x zzc~4N&&Y$YVR^~8QzbgSu`_P|=0aiD5~a)48&$)onx1>8i833Me4dASZ-?Go;C{3nxe7BA*C_dd zpT&bg0{P&%Q3%4P5I&QG2Cj`h-ULG-0r!y-QM2veNu<}yju6CvLS)2u#&5kkg%FOp z?+B*`Lf-xT`5yTH=Ai#S+piRO@BjNd+W+t2iT@e>zvu43|5Yx{{kz%bBX`-7%iFt3 zkdlVW*`nocroa`eK+Qj06!a7;$S-npLW8;~scnW1r>tH;lQwxo8Yp|Id=-z=Uq-6r z_EyU0NJ+er6n*;=*)hmCc=l}P{i1;eEMu9h@N#K>LTKLn@krtN{dgn&$k>)|#XXlO*)CzZ4<6G# zb`L~V`@M#tWZK8471j&G;!_sB7CWMe?QK-;X%rhtL@*n8oDe?ImO`ThJ_+DcW)n}K zi^dcSxihA8rwHIJ_t@*QTk_C-G^9j8-)_67g9`VQpMc@lO z&$==9+_!SU`9~8M`cDx{kx|jo=iw;2%Q!7yC*zU(_GNx(Lg$xJN$r)|bs_XB-!=V4 z*^XTqI*NQY-RxG8@<+H}M}zex{2BEF$q21gXxg}ht|<;J#MaaYeDTj9oTqJ~z+q@Y^l zEX^0s9_7g~tXk7lYLp&$aJE&q(Q9Y{wK(HfLNV8B3&P}RaPf~awQhX|p(3-cJbUL` z?O!60K{oiTee%`7n&pk*EZ^fm^HbQ#n1kRZA*$e64U8b)Fa4Ur%`d~%<^auIh_RYhoVL-AihRq<7l$I}r`12fuoJ)huN* zsX$Q+JiC)f<sZAdt?=M@>Yqlp z$#VNE_id&DzJWPtYeFVIFf-k12@he6sg+PGp5#-r3aNf)r4j{pmo_V-O>d=Lc6K8g zH@aza-VYgW=Q#rzs>tOOCb-ze0WvgJB&O;}x04#*@x)LLCaF5G$-AwYIlr9k(ssmC z{8*W1L{hePh!kKh@6riYW~xtOrvZ-$FkdlEj|kV84+;2QD=&O-#2)BYw(+oE@A5c& zy~PWJ2wy#rm3X6mN(;+TG5&>O~ zbPohF__G5eq{++;Q}EwByVEYLUy6S6Le-L>CW$RQdqhWZ-5NIDY(XV^$C|P7|E}I4|rE9Oh_PAbp%#w@KW8c@v*f%frj1)X6K$0lpS=FsZylncb zRhln)7?|S&xTQ!mjH%7>`T*^U)B-m8Cghlo;9tzgrNNlm0ONbyv70k4yGz1lNzku0 zZXQnH-DSI_-BNWDvKEr3N=>j?2+Nq-A4q0D9ew@#RwRqU%j(&plLCR*`LCyC-Y@1J zk*w!R{rCZD>Qj0svLsi0lZ%t3_Um4vuN9Y$oo-llyny7@ZTHn?VeyYKiNg zOBS#rkl$NZ!MHMB%;sr#B(_RJUCNxSDs8oToOJh;qNJYwA1_NU5-^__oLa|dWBNftqiJH3J-Ow?zBpxfEuXxyEU zIgR*?zp{98?dgsSKnWx4*C22Yfy1p&0vpXWF^N20^=9s#DSY{sEXbja1eakzDjPh> z@Bar_3i^7FsV-hdOh(3P1-V~HTe91l!=8#rtB(ubOmU?8-O?^!$1ldv;SlEH$n`7w ziJ>?(#R2j(r(8<@CD#(RP{Q2Xk2BcMs^bS?7gFU`)X{YH;;U2Lr#rn|^cI}Ek;G*F z4<+S`+X|dG@z>t=+$ro5+-b|-aP1DML$B-w_o~mJ;q>H7{B}a(8cdZs2V%Zg3;0-D z*xD~0ejm|wK5C-%5_Y;lk`~a46fhJg%Axq8)*uM#rRQJ!aCD>>+`w#CC>SXbb(S&7 zTX}O{H|1I0VCWb5DC3(__{@X87NtOhQvb+Gmgkh5cLv?rP*+_$-B~458fwH0WY_OP99AuBC z!Yp26Lr8Y7c=d{JrVH+gK4(_Gl54{`D6qJ>7TOx~|Y z3lz8zD;^PYwP_El^kw0!(+F!tkiqhNNT9soy(z!il%~**2KR_~i%0v-K-12LE$ta2 zE`DqZIDJ;;`-URcpsmxrj$g`eBhRXDu2?;;y9*nN4Ok+5=#^YE=r^YNh$hb6cn|lw z&e_PI`~q{!(Hk@T9#`?LBLJ7aMsTTagtB&dU(;H+=bmU_XaF~%gP7+mR7Fk^Rm*+h zJS7KG|1h6xfOeEH0^K;wWWoJenn{@(_7$q>^OsY#b1!>waGCXAMl(b z?x$xIJE6V7H>n3O!3uEJPu@KhYJDQw?`&JT7})mtTynOo5q@khbg3@huFd00i`;sK z!4=?Z@+7JD&w$m*dCRD;i!m+m0an$+bBY?0&`GP9_r@!%QTmE)b(OUN)f5K{b)9B| z%y@3CdI=wT?JoMARx*!k>{sAkj=iGx=TmKbIR^nNUF}IZ;{>s*wV8M{f{3hW)@Vp; zmq6IkA@(ZaW2<~Ndg4k=LN4oy1$UofPz3+rZ=SZ@qU`v~B_H*M_tMFO&WtJ2lT%Ga z6%pBYE|qI5M%P^CrXkdd1<`ojeEH-V#q<@i`zo|8%TcUaE|EM7_pkJ z{B(@C;0e=K62Hnc@wclUiU)0(KaO}FYDbzjEaA;8bmzE1zm>a5rjy8iK~Q92y3}TO z9JH(_HX4Fo%l?uiyOmB1ql7K77g{CU*C=b6z_Q^;m`lNl)s#XK8GVEvjRwL_hK5aZ zN3sQlgc9H?AmQq#hNFsdyfoN8_My8Xq51z+3GWVebf3#EL{ zIq4ojUHmJD3<&FAsf&DPsc7-N%nf?4w;~^L-XPrj3Jk zi?NH5%AbFkLt+S1$9%Nw5&v4kKLCcAZ0yJVfD6yJwvQ@}s*xOj52S3;e^-Xp0rnIn-QOn8& zd&Hd>nXw#L_uhFhbDSO z^VpmMqPXbC$@e=YJ`;Y2MJ00J)dnb)xn1||%&>BD50L3!4ivYV+dmYH_s1d^#d`Px z3OMX9Fslwy(GsN(L(i!5oYhf$B#=pn)J-}YIp~oR%DVCi>Ir>|HUz!K8kw4_Pcppo z!XQlip<*AA#3WO7gGy$hQ5@?i26CNFR=81h@11m_AWUC6Pw;KkUj$Y~oUC@)Z%|k8 zh!O;{uX1fsiuJ8#T=l^P5xlfU*YEKoBNxE+)2eQGdqPsS1HGfh6ayvNy_(R8x2mwB zIXmwN20WzKxV;(*5#x{+G_NAB!<;XdY*_UGeER*E`A{5eG^+O+%VF!D3-kbtT! z01BBNGQ9WxM-_`svJ8!?TsDH7xsyF!oQ1}j`Qwn64Kw42#ZoMvv>_5*gsOy`+IU)A zluRwn^eV%rsw_-(nM^9rUXKJ=T~L#KU2m7)8OEf;C7mpmdxdn`R^=_%M(bKh(oQo( zrwhFF{%bWql|A8Lv*f-dMa0ApP{6wgRC!1VN}k9kkjOI1XPiVMRhUdBiAeOca&3wo zQjm$gOfAJ&!YY9v>D0WE@8r%AXS{1AnGx!&~eJkpO9tV+l64$ z%I5v+R8YYA)0fT%8LI^WW#2Rrs>`YAsZl+wLdm92#sCct!U>b1p==T}p_foV7vd%6 zOD&IWVpG-Yx@0VK$YrA^XTyDAKt7#+u>B&E)|KDdXvEU-SDX5awgi?=^l8{HW~wu~ zM)_*tXGW9IaMt%IFJ5M1mIlZqvhu%2ZO! zhi<(RHpw_j8Y(oams`}RW`68F(Pm;m-?q1pU0M09_d~L=k70nlpyzdqlmtEbc>ez7 zoT26Fp8AH(B*KhTx)i|0-eRw&4`jtpTF5u+aq*#;Ni7R~=5%=va{_79T|$WUuMVT* zQa0|?uXoCgR?;#XvK3=T^NT*j>Hr!C&f-DF!Cz1(xCis~MayctOFN*aj+BIAzWm{_ zJYh6Q^$d`Z7b9H_`yE+#PkK`vuL{u;#qET;ra;rj%)e&kM>c-z$fqs}0k3(XIT19! z`)SNgw$P8kz1%U}%pFremms#^1INxfcPA5L^T2(93!2TSY4kn_%oyWI@2Id=KT25a zx@xo@H1LLJr}M=`WFvfCIbXSP|v{KM21c06wG?=q~V2-T#jPLZ`_^r zUCoWgN1kmb`@@svfvPFzp5HB#Gz^}dcWd~$4&7XLRkr1Bo!vQK@q9DwYrUS3Uvf&o z+UdJFGFbk#Ox8qNj>|mUc)Ctj@FFp-{^DTcq~)lXYjlMk(& z%S#GyiuCz-A9bX=JDSlHWCVQF$h$Wm#8AEzrKunx<&+u?EExHDOh7L_`TzDgA!7T; zR#JrW;voiCIuz{1cC>VSIZacav{QL46j38-9)syyH=@>%G`$;>yKh+baJW;#o<;XV)Le)&Du zk(3d<8=f`hN;WTi!gtKnz@c3cV-?BpnfHnC$zxB=$}g5vVH^L*#g^#?weIY$JqvJT z=71H=X4qi$IxXcUQjDdAaVIDSjC%@d-AU|A2Br+@*i5rqFr8GO9z4b$^|<9rz-NB7 z3#Z!N?bNjW6&&2@)!_RmcxF+u)>?zNx#SDZn*)<4Jr{ws?mM|2K}Jm>13k)x zwiho3Krl=fmoGUX-ew8Td&0fki;y3YB9e1RKulGB_LK>f%)Aj57rxgzK}M|^ z6)=O&+eQAG<VpN6_rPwLc?_@_R! zgDj$IeFIBjPBs+X#6avS1RFie{YUsrV4x0+Q1e<9p97Mi1Q|lgH+EMZs27lKgz0q= zx3$alJI8La$3{KndM5s*$*awzH%@Ml8GWbdV9{-ly1!5*RA5vtzByv`D(HN7S#V&A zOmB?cVwW#dTZB;TY16@$B}I2^qb`>2zLj~1OK1RUHNC0&ka`JNp@KWEF=0}pcwWUb znODVb#px6C4NIc@V9Bn$fi4plY7P|C?TE(?C zK4==9b7!w@4+8}C>I<`ZH9RA~80B>=8lpE&+5* zulJ{S7fL9cGTUD!nKizG!$^IoxS75kwDZa-|KgX(In=oAY{WnN@D)J~%V?RqF^~Ts zkW7QuDbwCSWI$+{*kZGT-h4u`Y*2!qpz=9g0PhXLk2D58nw*G;^denbn6=~MLxn#w$$b4s#uHetEt)Q2|yBl9l5 zV9!^fU>n(8UyJSUEfseekMNZjYhx$LH z_TylPvjm9N~)y;2fbz1HM{kji7J!XQ`IL;B{DW!L5l(Im> z-3$gr9ImPH$PBeOiw`3acCC_awpyO$aRu5jF_vIxfpYHjjH1UkIaMU0x7mtHQyb1@ z)&>iYzrXx_C^@<35hHPxBaq+u&?Om~3?5^rT&zo<+igvVe=#S(4kM@|$j!tpxLGA* z-B~M)*4j%i6STxz=d0P&@xr@xY45Lq_yvj^wFiNJOk|tHNqt*En*173;>LImo#Aj? zKhh&*83xN*pDJ8}Pn?5xzop-hT}oeDaV?M(yNqda;AHOVyI2gmXBGS;TaYk{0{|d} zeVF8X$wfZ&WnW9%eWXzzA1IUgXturCHskH%WLD^QvZ4($_UiUD(-9hr+8mW!JTm?s!~H1cVtEv&1d9QNI^O`^&E ziGhlOjtWjH#%jFdGWDeWhzwXIT_pGuPg_();@~`~+QN)H@C*A&HRRr(7_oHqz)Sc# z`lrDac^GXfaAd3VS&CJBg5~pM)63iAvsBl9NhXM%4r}zlXOCkeUjjhL_CMOYz?5}8 zJn{tqubAM82l0t#??|NSkU&GDi^-kb@Xc}s7Mxv}GvPU|s<)iAYpeYx(z|IsHW5%4 zWmAOKfqM+O8-WW??@Gxu*De!0$WfSX!wd}Iomni;q^XPb26T2?Nn1VXc!`AO*T{I9 z+P+(yQm5wncO99(Tc~nhxWsP`xS#)W&p4X=O-sUo!{T#Cu>oG3`l@)>iF)&lA>(HJ zpWX8TL*LVW@fA;Tq30yoVPVc7h>eiuN5z@vvAR#c!bX~ih^T!H0mf~HV02e3{@$BD0xsse3Ez#Z z`9)WFURR9s%gc=!f#49a|&GOQ=ULw2U&x}Pl+T5HYwH6vP#RpUert_TkFK6cqY_GS>ztp&V zsDD4xy4tSJTpL|I6~O=#jBGHx)|0sG{!I8N)5m-NvBNKDgKuD^;Nj~C%@j(T<}bc^ zj1ZkMfvo78Lp@sQezu14ZmQeE@tN;v;JqE)=<%i^))xbV*10OxtG(rJ2eI>Q-EGb< z7d3imt4y~{>4(d`&sSE*GYAre>79;pKwPEJablw=@y%pBN&6gxc0ZX^^2-omkteD5n{@#?=Zl5Iq{d>cO33>eZ@+&?~uLz7C zs}HbZoxzA2Es~Q)=oEtt&qDYKvNFy9D}K2=y(P2#tgqD#@~a^dwRM6)P%j?D^46#| z(S5EOCIGFZiAudm({kDzGAF)FZ0 z%N-rNn^6%~=Oghf=IaaVVv@y98;WKyh~~F2Nmw zv}p0-4#gdcJCtI@T?4^`6Ffi&dD7qieb>4-`IdE)oHH|f_TF=3&a>_^h}mu`n)4L~ zAK3Wxb|Wp>ZV>SLtBD6e-$BP{4&O17iPh3=UW+eK(3TA`yjrbfzzl=x2`&limvfi7!)Th$!&Ndt!bl@&>M zBb$Va$jFSIx{Rb%9S*1_oeH_8YBct;wM}0HHFJEDWfUMgBLD8Qk3n);5C>a_)L;jz zB`NNNNRA4)sg}81F)r}<8v`2?hLVCV0v%q+l|YNTsc;<}G;M(9Nv3;KSv1I1ao60< z4%TJffuox;ygWjU0sOqAKkHL0PfE&gcifeM;)3J+9w6RySHyWfWxaM24M(5HxeScbx zrg+e;Z{>%oMv{?kSkmN5t*y-eyq$8#>FYS6dv$XHYO397o5DYxA|Lyt_4d$pI-@8N z3THfcvmx0lKC5B%+xLnyk-lUUY=8H(S%J^*T< z7`roqH;Q(Z26DV);LC=aUQGhRC)j}2RQ^+30U~DGoV*8ETP#l54B2~kJ@eoF z<=*xg2L+vL++qa(3NV|=ku z(zwU*hKp-cO|=~MygO+FwU$>&c=yv3u@oYjR!327d8*x=yags z=r!s7?Rb+%<$D&@MDdN-Yi@xf3`M-DKZK(S)Y6s{K~b6f!4@)yW)@Pr8OenlD=z!w zXfgKhPlJ*3t+#td6q8Jp8zZQxeX&u1{N8&S>W#^^cAA!;7&28nii{B-{WWy`UUb%=90u%_52C1{@@fJv{8yFI4jtdMoycsW-?~m@ zz?i7$OHJW4pGaWIEc0?z@NHQiwN|(;Ece&dtju9mQ`~J&X0*uNpHX2+rTDdwW{ROP2GqTwkowq;BKkoXL4~ih^g(| z@U9$@TP5Y?9BsWnM&~(Y+~dl#brsxSJLA2Jl^)_g`xH8O#OqXj6cjcYH0!-z>a zOo{Lh$}7hPXrW>+NTY!#1RwqhBz@?X<H|&$aKlXCt@%}|rC0?q40E{V3B_Pz|JRDb^s)Tupe#mTo$A&!X{6}}Vw?(okvQfR z4<)l6GaPnHm8f#CLy=u9aIv14tB421@@L94ovm9JONMMG1*Nd)+VCx@Ci?SQ!!o^7&vZ!goR zg1a(xfzi{HPMfWl2d9*DaPi+Koc=M({&;!sq-@9Jp3kb`)vltSi1Ci zN0jJz#=-yB0+gZFt>njldbCsn=M%=V$2wSZX0DT|^#cU~;6WxViPo2#gpQdiEpu)vDap3{+J@ zlz&-ND<2H#A|kH^cOBZzi3;fWip#u*w)mxSO-U7?c9j8gq4G`_clO%#hVWWh?;BbE zI;p(rsH+qRFVU`%Sd3du##{q(loz1u>l0D6AWZZkS@vj=>rc>yFM0_zmiIk)2#*^O zz1U?JX1*AAaFll2_7HG#VD$38emicEh4;8*W!K@UGDg#UDQv<06FH1MDkqW4TIn$B z{`WkK333L5Z0U_-hZ3S{ZEc9%I}T`!ig2^w9XkM;9TS0o%&G@`I?Iu#`;HIL5|ecl@w8ZA1NL4>CR&82M+B9+ zKVOX(1G?AK3l&%qVA*&4S4}sRoYH#d^Ut*lHi<%fpz1tprG^ChgN5T$F4}IH*$xsn z+;j%baVXC#${orVQvJJ3wZVhATLOQ;X z0V+y}20ffriJpcvYpgYQd;FMk?^;(s7*8O%5U3)GpMS5PSh^`2E-};puH+(bSZ)rA zy+c<2u#FedrZ1sE+2uhsq?`PC|Cj2f7I)|Zdk_39wOX@Q2z7Ho?TW__oKgXV=eSKc zE-?T^`;dY6p64}z;kF1oZVlTP0|$N0m0KHv9oZWQY8x^_53ea?1!u9H8xQP{q!6_e zpZ|ov=g4(+PTg*AZlOdYHiISl>)n+zgT?P7ng&-rrb1_pwjkrG^u;G^Mx4IJ;Q5kX zbl`33zDF0*p1k!dJ)^D|Vj$eQT_lYqDyBK>K7tUPBlLkJ*5g}U|B{qOb_E*K{V2oSWh9F zh66#b45Y}K18gZMy0|0B_wxYhA60lhoA4z1fjA`|*6}H7Y>^!<&c&>oY zPs_=oB)|5Fbl~(PHU^JbCcsv2xdffM+V>~MGa9kYdzL1{`T$X$zs#IXN5to0tu&VC zX`sA~_rnLfP4@L(+iw>{U0)SveM!Ki8cchSRtKKzo`nLsW_X~_qd5DDgtub^m1)d|Q{}hcmJSfUO=lAlQ>U!=9 z`Ks~L6$pq?>_2p_6{40V?8T^o zODHFkVzYN z(E0aZnAoV4AdTZ)eXF&Hxl*K?PnrTKYL2;HyWvH$SG5ZFFwq=~T^541>X<7WKHmz< zP#Z2z?9=@0p5B)vr--2j>8UbVoa3>&edUYB8;2K!SS~Psn`nSIucEAIOl)bK{H%iP zimbJ04AP52AfU#hiu}u2fA+RG`*M}yXi?+*mP9$G69`tjUDzbgPs5NdHasHUfKS+5 zo$Gji@;Ho|=TlpVw)Bs_a1s7^Wv+6hQV_b!>QOK}GQ^=v!k+Bxj?*9>=)ojw&h?3u z_;p#xr&Q)l4v_-!lLz$}1BuQ!81l-q>#W4!X4=VVHw+&8MN`PQfUv2irb!f*HD@HP z$~^eGx_(?w_E}b?^^6BX_?Q1X3!+qhEoVv=Gw)RM zna1#?o7JcG_a^}Y0q{qe)ncRHa9;nTZdl)o7y@5gQa|kHrR=hKkoiK(&pb65&DILc zSFY1(+cw3~k0z3DEK-2JY>!%=pLFMqjXn9jsUR{?!)q(S*|#sNe~d}HtX_(*{vG?! ztNHq;iC7ET!uRg=A+1-IAkb$Jnk;f8qTWj5ELGI+&lc zlvDu4dyiDABr_G_}}C=vjq#0${`%b|;`#^hr}$HU6=vJg~#V z5HVThU_dywcl2r@9s{$7)FX?>Prf2QNb%-uxS&$}%!NfW%LPIuczYe+3tdu=K?K=z0MFSNef zH(V`mSUx<0iR|K8(huAk=8K$$f)&@*M~k&AjWnyHUn9!WzW1e_G7km|yq@WopF}5R*wL&n?e48|HHjbYXfV-W zZRi|1Uh$7o%VCkcidM}tN8HUvGP-Gd#Up~zeT_+7b!g7QebECHjHj_`E!0pivv#Cv z`>xF9E|sht&%)+iDW$pgDsgJu#nbffcoi+=!KM6N+p|s`WV;i+=1D08#r>8M+4KR1~;OjC18Clxj zg>(Y~tS1l6q78GjJ$q@N89#~q0R_%BDO1guiCBGG%`M0pxQl+iD-c*yYd(WtXxUUL zF?!ibxUin(HnQRsC{yUlCOmIBsyC-!MgJ^Igj?i~ckhI_I%8wwyV3ZkrU8^?q&2;u zowLRKjG4LYngCfQNR-vD-}l0E`kkI&x<)Fed!% zP!V0JD6pV4sms8IFz$>P3~JiOF)xep6SALzC)iplJmDj3yJJRE4gZ?8c_ZA1&4N0L z!q(2VrO)CG{7%qxa;YW!(9<5vC^&69Sq48KO@thjOFf*5HY5Hm&L>5h zHq8at1rE!{Nl~7FbT%g|JjNxKoE8BcYF!gaAP)F(t(fV2#{bScux};MzZ&Yq>3@hN zJfboR6tqO^*m{VP<@q8@G5J3=CQZo-G*bbg6SSQAR!yV7ItG>Ot}L){x8eVE_B`fE@VogiS0Zk|g|H?BQ+8`5CW$Z~K2S*xILwe= z$S-4?1)r_7WKvklog1u)LE2{LiPBBf%`?uE=QDM@5Si@^h+!9jNXM^vt?=pt z7fkE)fzO*CiqtT1C%d$6Ex-$N5grkr!<&Tkfeq8>EMGy;9tg2gesRfJx&HU8q2|*@ z=OEz|-ZCn4KEUWYFHgWRVbngkjToce+*y^EeJ`E|K_-^Il4AuSq~=p9Q>J5E!TwfN zc-z)vbT%ef{ideIy$d)Q5#Rh0C06>q6R)W$C0(H8&tbQpK==K|#}rg~iTM&fog-(# z?Z;_9qC+=6@`6Owc$w4)%^+>Hsi3_*hit3r&wu?z0tztOkRQ}vIs$)GOF2r5JjGcVxj!|V#UJVGau3PDvdE&(ji=~q!Y{1uG9^C z8uMGzx=P4(QYa!I&IH+MdN^VCzI??uo0vA+$g2^rg%T!0D0y#|7>R}+O-btBMUw+R zm?y%F@EV^fXe*oioxp{J>qP49h+BE6ti;%MZta3-29nH9R{SNp8_qY+2It2O#{)%g zdR1T2)mLWJ{<1_JdP2f^+V&Rq(pQ%Z#U@{7t=(tJ-Eqgi>Q6dO`QscN3CeEjr^nQEX+^Qkv1x8wv74gKw zhM>w_V=@WHmlhjt?~ZET{Q`r%DOq=S9jqO6XeooOC@oC)vzsdgN}S|XndX!+C_(*o zi}9)q*?RQ`_AbStUAqqMZ1yx}65daJ08fn$-Hcu#vRK@+UF)dd;G$y6h zk{F#Rd$vR;+`jgsP)Dmi9Tqx9FysXJb@c|eSn=*mDCI^*@%Tx$4UKE(|AGy z)XCN;DObj``d6#nG(%q}Wy~kU35vM;e#z~6N1F3tu|?V+eOSAi z*-c*3Vob}pxc)Ks=qhA#v*6*7-KHhI;s)_;WE zEV>$c`yX5nb{piW&8!TZ{=ztn9RB!;KR)s#0L&yIV@@{^T` zs)p*@;((jJK}q_=QvMbFwO`}6=}0t@?X#6oy%y(CnV7+X5cIx?gHebBI1>)DR24ESShH5qpHN(Uw8~>SgO!OXpO)eHF7^H^D#sU2t@uY zX4sNCo40wZ3gjnMW)(XW*Xo_v8Y4Hxh>i$8P(Cdc8eBY)<%MJ&p@-CJI;3a7jsdLy zcC>ZLVy1DTjZzoV#gA30L?dxt3aB$Pjde(g1Jf0t^HyK$NRF)ChVVX2zIoHJEuFoV zJZ~cBwjiFQ{$9s$xgK_=gqP^f;`?m$Gi-5Z=rhS^ZpNr+?-#zT>b&IG zkR{G~Cx)GpCC8*cmlhx2)eYa`k5=zDDCU)D4l#RTv@wW?QyM!x)dWzAD#6Gm^a~}< zk(K^iaX&|P7+p@e&8a1SBfeH&22ejbO-#&|XJ4I=#^$vpGOa_o{R1uEt-FL$a_I4Y zRrft04!&+~9=3PSO0;y!*c85R>-$EQOpabKl5cSHgX!T)DMp>8)@uks{#rXsO?#jQ zb?dLOXEJXXLe@7$&)Jwy2E1djiV0t&QD3TNv%JlKesVf}_FJ2FR@83U&x6sOK%dV) zMnF;%@oLDn9Fl6oemq^jgnV#gC5QG zcRnr&&g4a_&K*pGmuo9$63Rr)(%WS;z;l1Xqv;RBKuu!TAE-1M8qa8d+%n(@_9X1? ztUM^Nwq1J!j5`u^3Fj2}t3CExceA>Cq4E>;Z;5;U&<03;|3-AC;9-eFfp@%ji)@ny zo>ftJO!(j^%tgeHque%iq74xW}R~ZWm4ANWJ8nYF4_@aVWQ##ayn8= zWf3M-oTp#9G-LAKh#@Fly9LCk`oq7bJA7Z37w|t|VCj056=(Slgq2D}*nj+UVn$93 z_@>vKe_hJt40{`y`)zi4Q)+hRu;ZV-;LJ!}bM}{fyvSf*(+PJ|-J5zVVw_yUH|#$f zy!D+tVMEPFKkfM}f$4sw?K_{ZmOc173N~Da{eu`2Gn;>q2djzT0y$1^mT|Srqlo;W z_~_zo>-{#{t2=F!OAAYpi$xI;Z86#D2dG#g$FAml->NSmQ2Z3=FU8oET)P`gV|C7H zwrBB|;k`7|R+(`&$Fs?~hsQrA?bK&2DO>8)@n0C~pcg&ll-6C6QL6im!t+GHvR?0yglH zK#PH!egH0cd^4Mt&ojtl9rF&Zq)Bhyb8zAjca&A=G2N%l(=Q~w{|ey97FSrC{nBo} zd{VDhse*{-`+=?WY)WApuun*9zfg`Y_bqGgCWd&6&6hn3Sh0(^=Pvbu3btBpLH5tE z4DI7>5bcY3e(jQ^Q7*iI!lBM?fQ(yybIjD+9kmf93E$TeSG8JfzK&60nQ!4rey3l_ z7w2tG?|qGiXg4_-!aB<>M_1Y*390ZTZ{=`}OwI4Q=fhnqa+IFYVoofV!+Pnhyk#s zKNJyD=oM(>BlJEhB~#?y%F$(wb^2h*D-mEU(PH0Bk_4tKf1LR6V(2zGn&=-_z?-Np z4Ir~Db%6ZY^H|kVnr7wL*ro%Jwzh%%#LgC#?d#<-k|rU%wU!18FxeWtLF&|kB(o*0 z)j7&hBYJdzoXTMriu$UU$2k1l2=Hvinf z0@(x|#4RK}5nS&oQ!guRSOihi5)orc8CKKiRJ;!Q^IQcgb`aY9Ydx9s*k}?I8-UD= zUV}e+*mE&-ARu|-kz0RFg5q^sFq&#tUg-JigpEl|KlE?$Vt*|+{EZ*|U+=++h+MomX;yZp*xm`DV(xt4sj{*k|P7OM$Qpxr7^LG<#*R@+eTfK2AZ z=gX4{1#bKg_dH!%hZ4CR))y~vkJI}0Jhc**CS>!thMnyJy4h&$oT;;SzFSwlvJi%S z8LGp`c%vbq6dm<+-f--@KdX#7y}5BpW^WNZ4etQ1loo-T_N z5%*@zMQ+6{=(+TER6886a(&~cuarMq=54Y~s4y0|%3|+!{H}y@C&(6gW3o&oDtvzP zeo0PBxc1o-9~*W3>Frpr>Q7g#*$8Tpu_lnRvz>~vo9K`BtWo|}D8HM}$)Qg6*4&Zj z{Dj^z>aHobzT|+a6-{8(x| z&pa-V<%K2AGPwYiUjwVRYwtAcOaV?wQn>O)w&FJ79oRU|H*SVhyZ4 z<8bGfHkk1W(j(Rq2vTRNnv}^Sh*Gw1r@;>XLr+&k8-%wGDshp*dB~f?MMs+a#bfwE zDbc7WkysG>>^CEBorRH8e}_K>gPdj&FNe1L3?)ngvg(0i?z$xzEZcis$#M0p^(lTN z=Y`hy3y2KkdzPlhkqA=JVwN~v(b#pdy~Th!(v(4mt+O6A>SNTLiNI?nl5dY_L|Z3p z+Ft(ow{dz$^jg}yasW=gT{oGa#S14ci(L&K;%NEFVXn^AiNFxj1GGD`h|i~>&)kcD z>3V2ORpjsVp+<_KhS}1bR*EsdqV3}4TI{#fF1ObxlnT10*~wShIdaIx74?nO67-PZ zG^e1@)ry@+cct|H)xJ42d?;(%CadSNgum=*(&G7Bjx`uBXH*c)sg?UneZmVkc?-XX z#xEXx#>q>12WMw6Qr_B541CqZXMffsvA=6SIr0Ks!g2gFvs#sWuvLw)>V1%H3u1h9 z_@sFAc*wsC(~In?%I*$Y7lnY_ z)5t`>*XNGNavrp!r44lb;$4Ds;>)Jre>cnv5It|!QX^M6Yw*szh_IM3}9>$SwX*cTWfAg5AKYdVasGN9P<*4Vm zf=%~J63LP|1*q80jsl|k5SQv>#mz(3tI6}&Gd4z1l$G}VeI}yX?J|ecZ8HwNAD6i- z*vo3&As@4kb)$YLVSdFjGNRMs{(C}njo^s8;`^e?=M{H_^!FK)w}ZUiq7U1z@1=c4 zSxcp6yVLK#;B*3^2xfnFKJ_}xDkSw$hHRW#H=NZ_lZDrwuyVQuEn)>KtLe?6+|)9k z@I^v59&(STEfq-d&ajJ{_p^LCDEF5c;n&6gGHBQ+Jx1r&q zQQa45QROPth>wgfvUT0_qX^u;{lM@$IcufcmR1)e`u2nO*;kUdQENS)$FvvEcDMQ* z)E@T(&{p(nBX_+u4;qOsJWCuKEk)h%eEH$o+#8WKO&g0J_>sR}&CKTtY)CXZsQeYJ zPTtBqiv#YQ-E_kAcWv22#wlud-NljffZn?W&Nl2d*Jrx`I35jV>!5WkkV7Br)#;7$ z@Dre4W&ej11&E*GX)~+urY+8k4N&XXVz+w|C(}oj1nh}bRRKOH4JZQVcyCp`+Oy+< z^BU<(Rv4vD5XpRgnSLyW7op<(%JnKYg$*{eZR#IcrSs9#(<3Fw4LWwxK`IqDi5PJ} zosYr_bHIfe=h~vESC3&*_UVLgFJe3Ni`rbJVUdt6`0*f<^xGG&?KnzmU71O`FG%jj z?P8Hzj6x4R66Tt~@_{dnABnZJ3^9dZfIzdK1I^ZTTc12Jw|i!sbK1NV+p^lc_zXq8 zOxV1Nxpxv@1AY#m4}+dRUI!_($5nSH6gTo^Gs3Cyq<6%fY0w0K-ky^qATq>2hb@^TturX4@ z8|*Z+6l6GAxEt7hZT^EbqT+G^%Rg(GEF-b#Q=|;;nsM!$%WP>1=IARq%snEti%CtO zLb)4$uV^+&5ZM=iDB!Q7u%uDJA*nFDYSIgz^B;+bHwx9qYXtYFTZy{KKfhP)@~#!; z#9d5#O;|78LF|GV@%U~AbN!OXZA?KNJQ&dwTPQ!g`a#J;`~E{H-j4^ghs{3`yGKQk`Ey_{5k-Rg#6(rybo${DIV zRIuoZV9lArk4#fR2)7pp0%xz?is#aM<NNI`@g;X}Bu~un8Ai_1>4XG@K5RVg*$Js! zbOIUeMrm{QYgXgkurbyM4h>K=C@W2i@XHB6-qr}7=|Nt$iS7^=%^=8>%DFG&ce5|z zs(whuGm3;?N$z2{VE7y-a}MzH_|>;yjBmJx19w`i21XWEroB3qFg$-Mz7|d3Zu*x# ziq&TR&^4wXdnRor(4bU|B+AhqgX~IkKu@ABchT7?ozVz;%ZZ&#bz27rMEgUmBm2`J zoE?2Aad9C(VJ7v7n1Fd{*Lo|TA$2glc$ZX~k4o=O^saEnb#e>9_`?MhnATxI91{hd zX?U|c;kfDD6XjUMZ5UDX(@1#)kTE{xEX<#((TbeUzcX!)kfrX2o;k?S{M@G`)UUtq z?(VFxQv@$c1jf?^BGuF#RGH54ZF~nUPDbM&7A4_&h%l0mJJrG2(0)3eAgP9#ifwAGlC`g|+=kQZXPuoaY z^+A>Qw5T^}&f<)%SfM+^ZrDY|ejGk{_i4S+{uA!ku5)|OY-+K+1 zv3&>cMBX2*u25mNZ15|P<*bR}F1rO{SJ^mBv78u~m(lQKQ39_iSL;0Ju-UyVy1uan z(TWRYIZe5G%-+AO_V!=j)UjY|Y5jOLEte3AlVz9ffw^_J!2WZC!KPKtb?rS~mGYy4 z4aSxOtAt-)t1L(@V0|cTNva5_WA297c+c7 zuHXc$dtfBu^z(}7pFlrkqPOcKzBd)-tOc4npFKiraXc~_JFG_rl(kH!h#a!d(fyJ( z`qWt0{#Wf4$m3NZ?qj_v>A%dT_8L{dRxQEtjZI)%FeIF&B0i4famgmo;JKKV-m-iF z7R=4?uS=KQ%!2JUKL`u@nL4J zWpf8<@TDo2H}oSzf2j9${J&0~9&-_8xtQRE=}#Sma;XOJ5GCqnni&-u{Jhfimm%XN$j6qJ9ixh#%I0C-njQ@?b}58GKL2t;+$!J*u~(fdI>lB6d0Z*I_qv79yRBpXyg?eAs^A`glO#oOWf^GXiR0ylJdYXO9l}fI-TCa zxA~!2;=VzngVWGNALa9NuxLN)#uOCHQJQ{LhKKoeV+o`8yKpk?fVlDZYehO#AUF{H5-S7oj0{W^&xQG}EVy6f z2(Q~Ui_6O?rfa6Ev3&b^+7sXUVggx|v?CZx)RSRG#pi`Ocu5Yz*7wNxk`w&(LRb*x z7kX85jQe%eB=K~r<~W~-N8M{cH@&ew7&6ZNxk_=k@*`@oy406zZ)@i^6Th-Z z5@aaJQXlGjIySbu=iz^50j&yKc?woF%znMK>V(jWsF@)PewcBPICQSUPX#8%$ zH}x>TASy=q<6jMRUvt~`=fv^|zp6MQ2xJc!xsuCVor7OA(>^0GzfD}Y#|peXR=L;_ zqYz%o`m%HSF5t+=>-6cNZ!@0rLQ@UCdQ4LrreI$an~rvBZ3CY~lY_0!3MM|!An~g^ zIBU1*(2iz;YvsEF%@Uk=-qU0{y#7Mp*Ttt*Sv$QXYI1EDHCL4pPCFs4K>_kQq7jyl zlfRwKTddIsoF0Ie0xa;>gig8U3)x6BM#k?xdfK2p!Z=mXKwf2t0AHSD;)a{Alr!LzE$3bSyY zRr8}eD7$8ZjF(8y;JQ5d7eBBkRPhyU64bqWL#TFtL)nHtjP5tS!QNtayKtu|Z-Jm^ zIH^1d`*wna9}P(2{e4g*4?-aRCG72+VbcxS1RhviTAphX6wcuPN=N(6B?`9x?!V{(tfHXQnUUcVidwz94lO9EN0d#Nb zNS>-v06uu^Z<2cETHVldZf?s;yu{B1JTK|?c3NAPv%FQGf0%OOzSaqxxS6NI7u~6- zF&&%eh&aedt{qd&wG&#!@EsUo{s;d`xck|@Jpzm23*Fn`2%2(796w`RPG-7x5?O6L z8s++M>U`Ss#!_tgioR_=Y&Lc2VTo|%oKSeKb=9Qa=x7jmjhiZ2hZe0 zW7+taIDd^AO@UMT!3-RQ(l@lu)xj+v*5f&|tdPKV@H|^r$1o7}g?a5RlaA7NkI&+4 zr+59SXJ75T%!q@8m-K{3hS2op;`Q%e5ffOZz6K>Hk&GWyewQIDnTi0p@CJFIHZevg zZ+qcbQ)_YSN9Hq6l(Dolp>jekRRi>#XkE_5xmP9BxHAfwsjN;eVCauvn(&_?x0g$7 z79||a95qtk*WWGI88si-^(;v4$;|V9E`=g71sfwz`0o+ZNc)FbZU*Hb4j&GXPjYG} zQvFUbq8_#JQu#;~8{Ck_oBFL4e?s8D_!EB+B8!ctCeu8Ya4@KuSyYMGtu)oH`fR9$ zyE0QoJ}aTb69KVDR`2*eD>ecX^ld}su&*lnodT}t?jfve^Ytee+D5(TTMFv>#B^Q! zI!pAgiP)u{=92r9$5^5Jygx8*4q_3l*PE3~>>moz3ZgkjfqL*uhLX`LUM9*LO#oQO$h0 z`I_H@wX1wCXS=$h3K=$ZU@i3*6Kl)epi`)VdTLMc8Ixe)^g2KLe4Zy9O53lmE3Xnu4be=iw#- z&+6C#q;uTPd65UsGR*2#Xu@ilSTw!tVf{^c_M|*zs?FQEjPhDaWUxfZ-3Hzl*)~Rd z){#`#TPGxocO0;ZE7^7J7@-{{)r~R@BTloujeR8cIHXC;q$NCg4TS|oADjyv$5g>~ z-QMz2tDci{(AR9eNNcPRnKQPM-;GWfCp$*8e>|Vr;>#*9doth0>@3S99|qSG_r9!z zy)^!eRYg>Wg$)idM}Iy`;CaAw=&FhF`vSVkhtTHVoEpQ{P?TIUj={avnbL%Gy-aZ!Mu= z%>K3GUiJHruQ7iOyI#JQg`7VHr&BJ!mSSzgtZI;LlOd~Qj-RVoL1vnFoWOle7z_~| zK9&9uQNuTwwAd?yXJR;A7dj=M=L{Qoo@t^d#_l2dAIhXWVvjP`>voO$+#tU~c02L} zDaAA}Pa7qK<>hp^MQEReUkH!XP>E_AcQgf3Brm1KC!!Hqh@qYXJ=<-XJ>al%@0}<7Z643etu+hC3ZFd z#Iv({)3(HKP*K>VBIt7;qk?C+-9MIE zaHZiEsv$b-Az5puKH_4R^^n$3e&}A!6}6Yo3tr?&yW?J5a82O_k)6hpox^QB7}j8? z8kTA{Y4Xi_ix-RM&%Bo(++Vq{(>+ZX51g-+t1Ev+(C&^n@bDWpO2lT@KQ1uv$kh=# zLSCjcJ9!g0SfUo`I2B?5Y@SXwPLxy0OW)(NNTA4>_P3zrO`6q~G&M5_JA=qK!2`RH5~<-9z3DV>+vMppn; zYdonOJsgK` z9l`n$^Q2q4GAS?YQ;g~;=fZJTMs;A$Xbmm!a>SHjz60+#7`+()Kj~3V-)^TUB>@ik zs~(=ski5n*<>vCfS{saS`B=uyH@bC(h;{extNRI)=_oqcF4*mXYltLjZ+J(y>?r-d z&(D4=rLiRxbW^VR!F9Di%l z`iBm3`sdkbA&c7l5?(aR$^N{pMgFZRtS!p}zd*5qw%V+nhY68MT86Du1=Oz`KbI^| zu@KsYDH$ar(OZWx{=a-+YT~d>FQdFf5eGr_|5a%)Wjq;{kPEg-; z)WD$EX?_H)VyV(=)v)rGb7D)%gZ9`N&fZ6f3t?*|S>Thi<6F(!VK4Na^wMA(U;eNL zyvd#&Iu{PuB?z?&s`s|3)_&Mvp3&%-q#}Q*!<;wN3tAOyZeNm9M~Ux0 zIY(#6oE5V zk0zjkS0?xki4J0(7BCsL>muUdULkeO3lH^o9CVWr*;?7> zo{l%E?KnNP4Nkp+R8p1Ef3FLIkeylhrcGbt- zUZv#K?Jw>x!{6n-u6eNO8x@BkOa^U|Dn;8=ZjUAHxd{sC%FwG(^~P@5>>%a_dQP_G zHqb1n{U^<+W1d_}XWJ=5B}2=6imTC@Q|{+Kl)SPB%glmU3fhozxlfS8aO6NZ?pz?J zTXW)C&SIlu1dSwZvOUQ>=`BtrD;z3TcQ<+(tNP*HGIP^3+dbQ);ygq1jH4pBJ#xorKJ( zZ~Wf0e2cQHzyyW7Kl#;OS)rYMSi}#+&dOkn#S|CP^}T*%dEOkH9`0PNH%=^m*xugx z0fo2x%zlztP#TY(R2(&uxd<+>NMFRnEFk#|!*=LO|0gf_eMc&jZl0Y8wdB`m^T**_ zl_8_^0%KF3X~OxabvT<+=D$B-ZF~QpFJ3qahg7C z-u;&^!13!>T~TqXg3#+2&tH!^Z~bnI4sE|jhZyUGQoVu<>erY+VC(Urls9kQ*a~`E z#WO!fs=F3n#k^oP7xbysws7wj#=y+I*OG{;t$2Z*%y*8CKdtOB2QjhD1X*! zz6+crMo4&lm)Iz)Zo*{XVt0RYNK;GA7I{B(_6FS7Ko>@@>YS(a(R>_E(tDg@kDIe? zzol~=3T36xrFv6vQVYDkrSy4#BV)DMk5-y8Gx##H?1i9=PxjqUPls-R4dXu#)FMy& zX;CmYx~1{LFA^%bC`Bs9srH7(x&AdvEwI?iLKjl|C2 zOHtxb__fitYg#%+*Ani@$=yhw$#y6EE+VOT?UU5k_EC(%q8hb*K+cfj`T53B__I{~ zh38%)qFrB}l}3u02KbbDN>k=pcHO;7obx2_Q)M@4@G*7=t*STo6U*QBxvPWh-A}hB z4YV&o*eF)^=OiU?u*c%}bDl8C$%EAZeIh!`iiA%J9F%+A&B4)0Wi8*NCT9Cn{Q4kf zOaKq@cza4`hH4Fm%k8SFeNt4Z{iKB6t!cl1VWs($teExWhEn&CuP4WYzBh`lz$HZ1 zQq;~BqaPmu@~%i!+d~08%u#4OZsgF2AJTR9$TiHrtJ(9)Rx@ND%I^EOkPu zwOv{vSsN2zJ_8j&TjD%nd?)ch=$9gy)9YZf6Lx*g`tmLN ztquk@p`+3+Y}QxYql`XnagNoq6RtJ!wpiY{!B&15&M47%&+~VYmwRVu%##;wmCV25 zObx=kVtRm^kjmh5s(Weo=$i17+{Jnpn8BYnDZi!Uue4>UC1K9>I%glbQvh+~ zwN8z5(E6knkwkGl*HFOf@#YL{3QiDQ)@%E;VC0%#<NV@U?C@al@6*~JT&$I_owA#vH6CR`%hT>j^4cOx>eCd!bTwbQQzlH~O z4!07TP!bZ+x`qaIT(_lE>ZkA<;ffae4JI$ux&-v8xEbeW&y^46=chVSUL-}_|5X!I zUz|^@Y|+b^2UsLQA;*x8$E`0b*Zrsy&7?a2yyQyIh=gA`(4trH5t*uY11aoeuuADZ z6!CbidbJotcU>c5K9ZZhNu@|VEM`Tq>vdJ!gy{ebkQF7tZoSmybmj{)f*n|`l-jgW z5+mue9rWgreEOyxBqIHJcAuS7+9TckJB5vLROuFD+SH!Z7QVj<&pdj<`9?=bM-g=C zym{}x3%p#WU#3Vsa|fxO{~<0mGq&i8rlu+36KWFIl@thPFP36JOTZ3=#ami`mX)i! zdqzGK(Sg=cg+7`QY<(G}d83pfoXf-a&1odYh!kHEf~+oM@DR9; zr_>X=$4O4grj;deDU;A;SrWJlY*2JvS1yBUrl;OAo*(A?8OAujtx1f7*VyW2xFLDlC5bJr=`o9HM6)m2dThE<|{lWv(HqmY>%H z&-CcAzR*Ehy5!K}Zh34q8tb)p#~Nz$^+kf^G7Z}Wm#fn>f5V$cZyLPQ+=hTX{N#Hh zvee?TEPQu>ak8JZkw;0HCw{zARc+dWip<+#Px#Xl2@yxfbLmNtvuVc^kll@3Widzl75YS2yj+n+YRsn z?*9XM)NpIE{zf`$u8Eqx5!pMIW5BL63}yhh0(@_twjc&yoxTY0e1#}vE_1-G%*8T z!2)CHt@5N--|SQy3k~mNDnwxThV~>V#Jo=1>_(@9=Vst3y1U5?bHn>F(w(1Q0}{cr z#b?X*W%q)-wA5@6hEhmaxN~UeR)SKPQl5OHF}tc3i1nvoqyYQ1(VCSz<#8cm*LPKJ z%l{xz*iID=N>40C%afT!anx4jHpxSISlNT=%Od9;(pEehhO(D8giX?C#dcq|Gv-)^ zMFQJ#s#l+n;3D^LE&B3Z`0wC&_l5xXGUMOx9`G}WcQ?@+-lIyOF^{@itQjSmuEep0 zb$`HtrAToBC6=S*W8}@fK8{<1vOg+IpVJuFEdY)NZCbotaTcmd*?j_2AGx|gmss2l z+W@zKkv)pNA<3NyDejt3K{mi0Kb!ky7g-n#jK2o>LhpN}!QVfrZ7J*CD4rQN9o&)l zYB|ZcQ(Y8rOE3*i+A#I1nvM>zw;Dv%O)WC(r+?R>LI?~rz(+F^^2@=ElG9PP)mF)s-P~HTlNk!{6+9bvC{)h8nZcqrijHB)_clyX3$myyV3?-mEF0$tL=;#!a1-; zgqW7ZS&LeBUppY>mL!IW#}!6-b5*}Kr@9=1*fEwG#muC`qdCiBxeUivA6AwNvqw*k zG~^2H&Q)*vZE6)|GlWNndZgR6sN3UiYbsHHNR`EvUB~P*8zncnyz=2j7A`7Z&!c|T zMVcLVtmbRA-bBkA*gxiR2iIj#PBI_SL%5_T$(Oo1C1%RD>xbk8l6S1K|+=N!hnxc9A z{I)pc2H8Lh9hC5`&#ok*)W^6I>7ASx#E%G>VS%W8HH(OkUSs^iedzk;<;M3#JYTR& z0-MgI*eyfb73{UR^`~6PbR}G}QJ!)ep(!+f*DH`byN}t*oYue%6}JLyOK1>nbWwGq z^0ZwkT}N~ybiZ}jjNgq;M4R8paVii|ZMSdpUIwdGbn1iN{JN({d_{ipNH;68mwk6? zX2Z)>YVbilPkg*eZFTh2h0U+i0=^)qu0oqSdjU(1&vL>nq;>#Hl7psX#g$W@}YYu<4E=ch}Ps$NWvr(^Nm zwtbx#VdBXHl|oqz)%i4Nb#Xf5u&B)B13Px$!z0Y0C{+R|`3BM4(O?^36yKFqld%Q- zaQH9$a0ZopRy)2^q{k^#zSzyYWY$z4l20+SVKGp2NuBZ0A*s{8RE+4IEBu$Dx9?Iy zxQl1!^4IIPJq^3K?*rQ>Ym7<%V(jA&kYk!eQuO%fofhzo1J-yRr+tA25aU zJuYEsm;9>ZqH;T88<+R&MEOG-Tobj`jenPS;_5SWNPdYze>6y)gtr{H+cU$?zwJ-* zS&Nr!Wt&$15OFWoz%SyLIhT7Bwf%H87^s=v4^w2Y({FnW0OMx)xDz7TTZRt^4WWzJ z3h1+u$o$Zkxi&Sv-vxJ&xG?cZW4(S+jIM<9uQp*STaR$+E~%r>@7XehcwJ>0bg!zy z%<{))Sf*BHdZfRRn?&NI%E_>|!#S`eoxp~Q>4q9A#O-eD#=b$wgr)9$pm_6%nf4;! z{U@0kMD`#9xeuYexXAH>LjUb2`!BBkk3`_VoqpedLz=)eEYXNjVduv+p|85%!NfH-Kj@7At+l@X*S{wKXI(u} z<>A!fd^rMFLb(7plUPEmED-==Q7%IM!$dM@c`!ikJ+S*c+lA7PR(ss!H2mt~B8mUq zYM_1oT1w_ma`S(g_+$Vo&(eeEmkbRwO&*L>N7a#+-QoLmtMwuP?5)LVo|ydM@R#?MsyZN~U(qtJ*Z$3s(I<)4yULUYv6IpTONr|6=!l0vU|_e~EVe4>kTz zAphyazoGa4R$+e8M%nPALOIFtl#+u~B({bwJE&7MVMziyoZIrZtTy|A!U)Me`e zSsFMnO{tG=-)Bx^_8W+fdkoEldcJ;@&@^= zAP^V$p=um4DHZXDphk=|0X^H?pub6Wc&nN0u`CPRp)vs8h?x%Hhru%lbC`ccoNv9Z z{;${7m%f+(>-{PJuRH%r_P?F+uh*f-Kg9p_{@(Nx$G?*IA4*^PulMh?3#9)_{!i5a zCjNtv3v&1mg#bwS&y=|!h5w)Mkcul%=*-#!BBCEN96 z646_ai4?6=qbo!|4(|XQ^oJ-_I`A82evzA&S6c zrg|Iq9f~uPZ7(3+`U_E?R~(YY$wGcjN?MYLsG)}ZTByg$c+dK!8$czsf8j*y@{!8Y zk^g;H1pCz}>t81NF(`D01gO7mZw5QM(|`A(t`*fU96Xq5U71Tn@3+_he*d1gYNls< zJR7|5uHj0~6{7dblkdchMPv;W-vfv+Qolflk==6bik_*3tvI6%@O)7KI-QgVfj~SK z!D|ve4<#=uTP#fgTGOR#YHCZBLH?yfSQT97?BoBHi0GXn?<*4|>Yy9``_j?c4? zZq_+#DJdfA>=B}>qgKKUdG;xfd3j6m0@F5o0*$dfgp}?pL=~wjUmk+rTS;<5jI-TK zV|zqLi!)WW9goj|hLXV}E(RtnU;Vp!xv!>D576D4uXX3zbUg*}!0blaEGvB|?&1Iw zS?}!tNRj?x+PD}#1qjT#FBf97?&m(~zNXT((4WwHRkcDf)#?_dh*e^u_kCTxM^<|R zOqnVQoTEw8kefi$-)}woi(}!Sk>;|E8t3MgS=_#;mq~$r%JR5cekgzH1Xw z@LOw6K?uLP8K14BEF?xX|6Hb3GlJ+U05bM3;HNq|#h)LHPC_yRk-`H89HV+h%T~({ z9NB=3_Xe-Mwpw0x*EJ$oxzlH??UYleTz>=L&XM#2gOR1)*#XN^0?J%{JlQH=*ugq# zF90lTdh?*cOS67hPphiEJxLz9ixxk)Xt8s}UZ;2VRfbwgmXpSCZzUZYF5E%;u?k;$I5~aGa|8>)W`j`WH6Gpw^in zV0IY6{=q$aF+?S#bz*CDxMyi2q4T08HXEgZf_R+2dG9M6&}C!a3(aN9;$9aAPdmT( zC8BxvdX4vjgaf=288C;Kl4dR%Sv5QskTb4E1bnS^9|vQRG(Z{uza=l_F91Zg@KyDK ze$vkKyywmz8Htkv->rl3X5|6c-aBa5lYVulWji2;9)92Gd|HhXXd_**kN*XO`}-KD zT+r%2&wqp;fQSDJ!Y^q-4R9f(xb~&M-s)ez07#fpPF^lALXH_2(3jVA(#^fL0|Sbf z@}e&oE5PSm-r+xU)XydZ2NT#kbbf&`X0Oli3SfNL77HyvZI|n}wf%;9!+iv8+k3aqaUK6D3gcVY!qq3_7d`GM4dp z8ME2$lB)1mm;RyK5ZD2}M_C?nlI2)u3vluZGGx{HP*c5`oX>%1^xsVHOKSo;z|SXH zcaCC~jve*dgGzVQjq6|e?o~bN@tI5Agap~6FL?0OfrlQZ*_CiO`^4wnID)c#mmqXf z9(v1Kvn0ua~F1Nrc63zTO>bFa^p4W)46d zWR|#6Uw6z_59*x18Ni&4EvWqj*@Fr;(wyv}J^|OaHJ;%7V`kF=H#Wf2(@Q_7dqM~w zmP%dMv%#zq?pk{tEUyo@kRvQ4L_~b-J}eDv=L1MoLgO)%iP@ zz7Y1m!+Tt;#I@W~7kD1)wEKqdJ;GH{_9)22sVc=11`gF@3sv10C5u!XEn!NQ4i?6* z!kV`LCb5`wevmI3g0Ky?h`i>$&~h4a4~s4jRJWOIARinhgDw*+Qb_k9N9E$F%^D6)jriGf% zpzLC(xYHlF3P*VP2Xan30)Qw;P1l!9hz(w@AC2EicV$Tr5oHNE5<>W^`~^3N+9p*8Ee*rK z>dt7zwXm)w6u}Tj5A?LLJY71)EMOm3zvWA|Wg&Y!50my@UsK(}{#w<}ND1M?4y>#o z+Rw)be(q;S`9Ln~?7^734C!%SY^&M3V~YlncRDx>$53V*TV$97n&VHzcBJC# zXaA`Bp|hH+hd-ShknHrkN*{l*w`>D6MnEQ2&Y1833Q~^@3N&`_RG&kQ{d^t8evaG8 zU;@VVjyhZWY0pwpunfKPJHoLe5a1_pTKS$30QR8`^x3w|=?qYc!Odc=>y+Q@csy{g z@_eTRm}<;&UXR=V{3*bCm=R*_dylbOjyT5ONIm2+2=*87kBP<_J?X}cn5D8Lj!6@+ zv5&L+fsSJ9PeHaEc6^xG+GX&;Y1fsWxz-+BizQ(zc(q+AL++dOfy&-~<@SgaPHxJi z?P6Y zKyJf!f_-B6Gx~=|Vc4b9T}By#lWfT8LQ93G!>AmdQ(e#Jv~ZYj zw3*W7&LQVT{3{t7rs)VAs$x)A=jNa(B(z#@MMsZG5!7-x&xHRS+Fo1a_LmeYMEJIp zx12;J6+!TzU=PIkTBhq6osdj7F#BjB1Hi1?`=TD?riC~k9yOcW7qD6XnUDL2h#ZY) z7J6)Wqd__Mj4f>QV6iR(`T%Vu8F1%F2OmQK5?qZ;P0PG;(Y<#XjV-^xqu5lGZScac zSRlG=u@skpS-dz{P$Z%jm8@CgXSAsJCF-cl4~8oV5BB+PIDl&G!)Kq_O9KlY?$EgIAA zY{G#H>|2R-TU=TJ`T(HsPC@4MzN~BGLh4`uq6zA;voPs$Ob6%BnAw;8TZ2 zO~_I?Gh!AFw3;?6v+4YfgtX6-Nw`Vt>F#=QEWoO3F$k3BKsqp2^j4~2%u|2PP$7s^ z4?DQdhKmP4;?lwEfM0Hiw0eeY1_veClEFyQf1Lg=QX#q;oHs;shH%8%0(5KAT)elOuX)v{^oWI6?g4bGz@olF3*tHC@R>~vJh=ymV5h(m1r}Oh z;rPw~kG7;-LDtWK8~wNNhu@(W;0NwewhD&)8KcG4f)zZP41OmFow(yZ7`X$3u`<7z zaF2Pzks~$&P;`NZ&%K#n+Q3*zttGDCqFm{cPRf?K!~QPB*?@-pGTmn{Hqu9R${R4j?TL2!5!VYf9ZTCOHpW)a~4qeVGFT{j#Gv=x6pQ@dy zL-e3_$LSxQIS8Sn(OK>vv2^dEC{sOKwUCs@Ccp=Q!vtG^X5KJ`44O~upO6wlwRyuo z%vS9T#W4OAe(w*qGX5;Joq)fvAR(3^XUaW#=MJ_p0P{o41H|=P&&)SaA%?&KmyRb< zm#%vRh&bSR8`R7pZJ)A)I&LJ37yYGC$nShZYAE;NxCsCf+Y|FlLWR~7N5YCgaP0cBY#r)_$ z6WKwp;W2RhTqp-~pB&*A|4Jg^%ic1kJ@^?6SQ7#ZhKZ>lo(vUX)xDvPVn7|E%_zZ4 zRTqbxFL4cDSUXw)rU8s`2?HRa!Pw$YvlzD%vYgS2r8j^*<=@*B>Y{sNl?SdNi$z=X zfRx;nS5Gs2w8R{6I(7}~c9DySkF*)9DTP7*Y~R%7o36&pB4Xr{r1z!{FXoDOIKK?; zHM97U-O4rK(_#OwaOuFk)tga(jR$~0wzWs0o*|JDxQW`?=LD!$&) zG^LoA2I0}$nij%v>nM#6#Dat}rwzf4ULug{vOw7p)jAm#pszo?fxW(@JP@dkHAizK zUNonURYy@N;aLLthGZyo@cVij?~|!q%@KBcB|(Q&;XG9-FZsYXI`q0;pS=?NsV?PN z#e+0P^XV0M6cd`Df+f&x{A{1W`!Z1ly4N>&tcJ@uwT?-z5nYkRJjNBu zt)t`9Q`tD2$erhT5NI?KlM?SuMUtTHl@2Wf1F+X~eJ>QszXnD=xx7fVM5WZx91XSl zoPIGAI*o!}Clg!L+vLWd_XF0St?#Zg(ymW|eZtjrFR!&pdPHr{{>f{FzEV`w0)^Sc zYpH_qHt}6`s!%KaaY!)<(lTv(gOxsSX}_>%&4vr>4A$T(QWDgfoR*@q*#T;Omd36$?ZdA3_LYNo8QWA^Uv+Q%%pDsa z+c9h2@w!k`5vsnIjlGqcJeDJ!Q&%X;`&7@DSTd>yc4G+^G;;Vg@?yyYabiDvl5}J5 ze50$myv{g@ynxBoqiv3)OnU8}w}G4f_>)Gfhw&h8ReO&nd-w74W4Wbcy;--zEoEiD zy#U!{NKBkz z8Joaa@6#O+`_>UM#h@*|ucA!Ih*HpK5>mRs_g>M9)MO^F`O~mGBA3g0oOdOa{p3qW ze~g|ZOD$XEmfg6sLY`G6lUZ3oiYd#AJY}<#h730wc0kgSOLeB-X$x4MdC%-wdn?tC z^l;DQu{)3E@^x(QNf}9`)#XN|2$SX1L@L`Wu-PNFyPMQxN;KhvRu#7FIwCjUcz^3* zdw{6RH8CdOSDAA}?Gf6`d(d3?3l7zpF42Ksn!TD}?;=H<)LTu8^<5>I4)Q~CEsASM z9Dfe%LL098_=mXRu~*VZE_&+&&TL*bt}TXomql^Fkja+g_Q}mbxHr;E5L;RfZxd^g zCE4-!vniK~|Jl}RpOiR~7AQcbE}fu78O+8Z=VP{)M^f$j1RNCl%x2>m?f3XdIaw~W zoMx1g0ak!9&&2d9yP_uBmOtfD-AiWMjOuaE`e>AMD)Io(cHSpILGg8}_7lm4wRz2B zeGHYmVQ-YyVuTp1h1=s@r$Sg+{C4EjYI|q@pv_L(_dF;Gne^lv)#bL0sU%>PDmGGFU$38TSx2!b`Jl7<=|je)0r%8i@BKW0~egAvT6mt3!-@V z729;eSFG=VNOO7RXI>M3T zgF|kw@^KKpxY0e|imzjLog?XKAV_GZR~l2-(`>7Z6Vg^(*M=CNO^T38PeRE&rgN~` z6TWVqa(bztZK`L3T33jgO>`!1Dl7Fu`jVYK^l;PU*^fRJrSDHV?KBE`JD~ra$&1H$ zth&R*rw9UtYHH>&ly6r-{R11bpfk0|0f*irkr`3d8GP5QV2h~Sep7qv%He>;Xeqf+ zb95+R*L`oI;(NJ*T1nBUsjn){B~{uih4JW%T#Dn|-ij)6U=HCruyu|N$>az=41tqn z9;+AGLdQb6$N2)xOhwu{hvqcEmU0LDRYSt|Bl${#CF}jtK7t;h+wRYkCb>L`h(>Dc z6;xA3Bk@CGEgTAEZRT6fh>_AE(8yIGTECK3dmW#~v?kxx-hovO&$+3t$= z`m{OJzn;)t@jnIjMcLRN+3B6X^Iul6ST7u?aMyk&EUTd1rgsc*%iPwH(%}s4Z*0vj>)7`WZ#Ajwv zpeWTI-;6`0?F1kZVpFz(QM@ht@EKT!^zTvl=utg*z27o@R~0;Nk&lTUMU)lA^S zl<0NwA+bnQ>CA8)*SPo_mYZ7eF-0U2_Nsh*4P!01xQ5~HkwB!wvGvCr-UpK%)3IIM z=c*;%B_oM7$~nSVGQV@4GvLaHqveg*a+81qWngUHVn1;_wLMk9=Ci8W16E~WG*zyV zS9b4rs89*G$tv*B?I5TrwfRpDqM-MQ4%B_+lerI9DkwjGH`rQ2nqFJyvsb!#Q}x35 zSmli19RJ1EDU2tQ6)c_)R3TVcJhs;DueR?lO9?yj09$F##Ivdzji{xkm%w6s?(1AL z*{EQoj^DMc8WOcPBSbLzhB3_=_E0og0lQQ8H%b>rjUB7O6B+ye%3Cwn14nPHgsyy4SI2Q%t9H4cWrD;DYEDb8a%d#GVnrRB zuWH|2&c_U05b0;tjPVmW6 zNv%7%Y9H7Sf|hBGdkOxAEZUy7)Sw&K6~zRYH??u+aqeo&=?2%ctHn{HafFeO{9%jEip4w zQDtl(p!ivW!;|1Nn=eJS?rNSI&|S2Q>D7D#Mz7n-Ab;`K$eTh_T6tsWgv-i`QVv=) z3djcFFI;aDDR35YI4IR$mh%L))1T(yG7TNyhT=?}4BUTGSl+XA(o!KiNTTDo_C74MHF&77y>dW?Y#rmG0%>l^|xB zxmK;gw153*>p|X60^3X@7nFK%pVzd09xecv8v>%iaWd zsFeC-=5;nf>Z&Py%SAe{_-;%b6@)Ynaw~z9`;3pGeS1RRQ{owI@2uxIg;l6s;n6~Y z?z`QzyaI228Rl3Rde>L_?>}jRroM~2zVAJ?7!s%GKI)mlb0=F$vZdG7SLP{po?hbi zLcA+u-nMRT+|y)l$CejMO{BDz2R`bx!w5goWmT0Zx33Ky>0-&QNzYx4-jU|E>6v zlbRbz?=NVF9^|Q{LFlV*_bStS4C7y*XTrOMZ?kOWja9~GpkzCL1W{@wbuQ^VeZ@8A zHVNi@-qENGJ?8iJ9KpwCX7%XrK^}8cJCMiUISkqE8-u5+68hJ4w#MSaSIZtfcVVD; zX2JWilq>lY$a|6Q(x;-Y9JIt%BT=|fkYp~fzv=aEO`Yln{xPI4^Eoz;76chmn;Lr& zxX-yfcx7Mu=(O{5G7+Lh-8HaX^C<#zRCWU zIEhj%`|^9C@t`X~CMBy=o$z|;--&HOg-%P|cNsB)Aj!TZuiqx+$MsM*=@wfNmcV_- z?X(x`k{~-%!DXsBuQ{ILbu(-Z?#V6KTk;Qy#&U#*e3@-g5MFRmr2BK+PFp(9QCHm; zPJ0T7CC>Gop%km6B6)t=cVz(zb_RcDcG0@wG{^7FL&^&9OWV_jtUf!zX~9PF`h7eY z(;lh8^J?g>iO(>#Ua$8h^ zZ0vL!*$1|qH1)_Aan7#RZ@U;U@$PAN6c>g$=q;}vn7?MF)_iL5nE1^Qse)cf8JF~J z^JO{2pnb=i6v2#%*i)vJ2JD@uZp)GpW=E1AZoM9}hd51*HRcwIv?@l)hLCE_5o|to ze>R`AdaSXbzfQ~l^t`JWxP30905?Z66fPTX8F#}Dl(HON8(-RetLgQF*=j?<&$8)n z(u6ZAT^qlBuBM%EDtDLA=2NiwC7!}BPJ6cQ<%v9b+J*i04FnEqzuZ8PD{hJXuJGX$r**-Clq+5#8jkH4%E&cZ*KV2+aJ#Q)~)G23)~{d+0`-858l z6{}ZU+;?@Bey!8N+zxo7ie1fz8w^^4r^)b{1C-cCj*!mxe2=Pbe|j$?@za~ivHvL~ zDdWI+&acPucVRDH%?L?1v)*0dxfp0V>A}m=xKr%J=Sg&1@a|Vbi_2;A-SHxKMOd2l zUR^Hwy#5%~nt^f(ii)+G^VhUgk?MBns8P9h9(Z76vN`nTFm674F#2>9$|6p3Gf&Nc z{qbWuOMy!B@5Uum8Nvz&tTI>gqv+urWqv#!Mg_VD0zv&R@?#;tm1#@{ak_+v@{$t? z2C`4vkk^l7qD5D$ih@#REG(jX^-HSsuZRke-z9OFfU`$rSWuD~=6m$%xaPICXLCLdl+Hs4W8qBfrp7| zY4B7f{$+GKfuSAI_K_V@EYW6>^}fi1IT3~eTi%wsW};*Vj&3Ergg=7>mR5B5TW}@%sb@={c&{kRtMggR!sgVGEfO3-YP@jKbUe&Bk?raumqBYF5JOvTcNSOatEn(QIH z5^w|jbw>?(kOnA_jw%A(dDG&}X-DPDKjy21FL7Um2VuMo?A>puK7Oywg9c}1#egQ3 z;vdErEYy5!N{^4uH-jZdCJG$n`@}Nb$=Q>z30ZC3r@28V)AWZp?FmO^E$xtrfrExC zG6r5Hu+Jf|{1Tgd{H^`DO|cm?>T7(B@d4xdpy5*(D)_Ej4JG}n7rz>Rr;&>?X>n06 zz2FbIWSQyXr_);2ypwYtAeY6}-w;3|Yx7r$$dL0hj_OGXHR9Yzwo9I}cs8odEZaot z_->HRWig72jXH+B!(c=*l3JlIThKnvoZDuo(tKfRP3ItUs`>$;r!h2HQ(pGwQUCak zh51Q8ST@xWW7=z8X?ZWReMRQ< zfT_Nscq}YV&`XA%W+#WYu0%0HAf$30dgI$Gu5f(kPFr|y*r)ZoiNYhlAF_StmCJ`V zaP?bSMn~TrS*A!2M8&=8Z@8XrVGQMllhCI)#hm*Nlh~Cy%9@*9{<)E8{M;mdS*S1M zYushF=d@Qpo&0(`aQzqfSv{TOZSRVS z7eL9bJ<3?5Gx>`Du^eLhplW7#{Aa!HT+eKx!-xN-wE0SB6l8)Czm|4=Gw|1GJF`FC zA4-`!NG*n1tqeRAWeD}~f1*!SEPzIQoiS9{Y;xJX+}lmw7@RDeUEm~)$B)Z{0BNEj zZ}E80`pR>}mpKzHPYZN%M(w>-|4qe+bP{N9^&ObdnI+5jNxKNcoM-&$RhqpD0^XP0@>XQMH^8eiyz!zHgy&S3oq%E?iJp;kF<3{Y%aiFD+Nqg@Y7T zTp6{lHB}xh$Pn3wQ6y6R8((V0H@==T{Fzh&bNGY`6P3BqN%=V|39oyv zMD#I(STXc$FX&$SyN-`sjxYXKdv6)lR@b$SQrud+cyU4~?(P(VySo-E65P__?ykih ziaWHpQ{17&f>Ye#OYi%A&-a}F=g0Z+>@hO3laaBr_S$P*YtCz4YfjL`@aS_}@gD6w zT7>}5#h)0>qeFfjO_5d`vfS2l@>?6p5iyT8hoifF*17$Ct)Ih@4Cr20`|L2+0@j3FgALJki(u<2Ln&y+GK+ za@N$P#OF1BZYtS9ka1FORLP!nZtif;ukr4Y>s9W zATETBIzwnDx_VUh_tmsK=xh?+0FvVBV^+7oK7S2vLT2s@eMWv;d0pQ}#JLA#1J{Hf zv?MV8@b@f6tI0_I*2Kd3*+W-MI3h8v={*Hk!tT6l)uRQ2mOZ!C7xu&H29Mfzcm z{O@X?utEtP_Je@)vD9uN;*caPkEye43idzSw)SLr6KOpy3msX-BwNEu=~9=g^1$^6 zHsXCLr9t_%}}x&gXM(i@`?iE6A_R4Vs#)%m^}E zNLJs-?S7k`PG-!U3R}i*x2I+@#+%P9DX_F}jx#rz4=OuEc!=Aqes9&+U1(Inc&gx; zeR9b5mpo@B!B)GP%819QBHWdii%fh9Z~VELSOsZnvvbdZjz{UJ?h`M9tBZQ;1h0vH zS}c(d#|zkV9}f{fgxBKJN1G3zY@pStjq-mp=Y4oNtLMUyHbM$2YZ-0N{Idb-^65(#=ibGr7o;r{Ag=OW7zr453ntToI{4A!$I@Phin(DN{swGkQ zP0mH_;^p_&rp^)6$;fBjZH(w}ps~)J6YJDKnm?T1Zq>dz%g0~w)v&bsq?xZ3CQ9Nn zS4w!^P$sYFAsu)2N2U~g?Wd3x-nGH5E*8BDMFYVH>gSE=!;g+1f0s+o^*o5H-k&`n zAN}$e>C2aAHy^r)i8RujIvK1uHGP^|D^<`T*nxrazpnM)H|W@}f2RdJbQ(tvWO~(B ze%|I)AAbB598SeP;YJP7vK*Vp@i{GVyjjoNu%wq{^P#V0|Clx7Y0v!oC|#5F5W`0R z+fXK6% zrBbQ8RuTaseu1M>ddht;pP{5fG_ zwPuh;^F!y7 z7Hbb>0imNZI1(m}R27m&KGzo&19cTX6co?Lke{jHXqktoncyHrFaKr;ckc6AbH%|% z%aL^0V)3W9Y|DscB8gBjV?y5NONv(W8yYf9qmHK1=4X@t2DU+856{V9 z=NO2b`of9$y+F?9jh{I;R=lyAPdak3L~jY!AyBAo4#xL>yvd$EdOxk#Jo8-PWZGjw zHC9ioBA1fSZg;VZmTf;@Cn!ygF3hhDheDp{;0VJ7Ff-TdO(_DJ(p&;qlDuAmYYLwE zno}m$C4If-juBh2iIK=gxv&0XDhz_@&wB7;2RVcAKzuUM7BgB3t?w&`YksMSU zxUJuV&j%8);OiJEEAaV?hES-UZq}8ZAw_W2amM)l|rgkf?#T#Yx zVk(+SspC(PeTY(hmHqPURvKSnBw`VTZ5 z$dcIY8+BzUo<3s-Q#?m?pobOWeM4O(sl*OYL9L@<`idffjkfb#OL3wqj6NTLY-T=W z7qJz*i=4J(`;l&&|<4%G#AL9wr!zfwe1H8CoCd#g$a z3=&g?7t&^ac*h+|93k2oDf!~}-sk05bm{81a@|eUX~`+)3y1+xEvhTYae6QB9VVXR zvpz@fs*OTz-$ZwJ@cl`_ED}|`1_P_WKOh865B?sGpJZXUa9vK6*v2rJ)W&lov0lhd z8*a74#+v}R`DAjJ^O_)+*(Nu!>!*hjkcXX#Ot8QfRrzG?v#hyPC69sdu@Fi9oHN~q z{@wdcI1L^t=~o=CFPcknFH6r1*}|cW2fWsY{LOALc)>(IYT%(s;YWnFemHTzl&>t3 zDyiag(xvxIxn8&J-2E6BgX0!aeIYIB?X4 zXLQEnhQz2j8>5YbaVK`9(T^yE94prRWwcQ?bigR4e)EPE_hDZ}U>D!H37rRT%N2XzLl>82YX;BkWWPG?kDS=e1|t1@g6nB3|;?Pb96locWHa{1kZ zA@nUy(I%}Z%D*7sXI5;w=eO2}31Y>|D%xWQ?vHHiQ*~gIrN=n6#9^i zZc?05hm%37nivD!RE)4|$DbEf4w7hTof|JDqzO9d2z6sH!CQ08TJG()TKa_uWUViz z2LYe6k}TA;W5smERNqK=`#%W|7(rbKVZ#mR( z3l~_h;bAEwhp`|bxY)1qG^AkPZBdLD^qcHQkB<3GX4)8ZnCRr04gy5wtp?v61cXJY zF?=EXUn@rv6`&L+hl4S?JW-|TEQq0R{mtVAUBTp=9;e7c&uvJpy z-S$Y{WU5ly=uPu_B=;vHyGAS32ZfOO4lt)gt8NvDi%`kPKojNH+1lZ>0J0Q(m^qFZ z(YvMEkkl+cY3WS)lC0h>yC#z=;wxAc$M32qEA6;*Y0{SPsH>y?bZgE6-ffHDAcBzt zljR*DsBaq-w&HWfW$`F0rBm@-seVgpcjhQKF>N|8#4B|*J}X&>NQK}gE@t4c0VHJO ztj??&l*a9}=zDQXiSm0A{mtFfliYu+2TOXcETHrI1wuDj9VVA{8(cyRq zUtywaf;@5>)2i$gst?eI+f-saKjktzW){&ki9#|fP*+xkmPmcUa5MXumPJkK4L2LYD6 z>VfMwK4vswRrFx@oyeQ6lBT$D^9Va$E#LKTA77zVQZ>C*D@nR1iRaj9BpoW^84c&& zw$?s9LEJl841F7sz=OEISy2m%L)^P6wAk_Dg)|P2XNY$38lZ`U$_*@%Fh)p3p@ z4ulI&6Q@=v+>!%NHT+(jmS8z!HebJxU67g_wj1NC{$aI^+3O`@b=!HM&^=E;97ek|@kwrzpz^IA=$p5I8;(sI2Mhe;w3{O$v4Tf)|BJ z=m1yA_l+2*<*slp#H(t?_6>M4&o53rO@~H9fD>e>^0~Ue|f3)LRKT55L)T&Je#!urM`xoE-m`NNgRD zcQ$^-n@?p+pYGGbS+0kOz9rzOft4bYeR!Q`@liRwq~eSa5PS42N*CALYpmLR)8wTA z^Js^Srdp$g%Y%G>@ToOW-HwQVz{^of^dD4L^$AdEG^Umwna~&4rq$6Chk2d$^J?%t zx)OTduHuPO4@oP{(q!=sV|@QlzVB}12TYdqP8kXQFbJSF&CA4sLMaO25&nRO4g!&q zOjP3+UsfB*7$NN;pa3ZjsBIlyiOucAa~7+tcVfL-oPXPsGLn|mQ!PA1BaCP|z+Cqp z#MM-^%g6dMeq7@F>5f=^Y5J$OFZ`E@=GLy zKa3hbF{`EGayLj`Nd+k?D)_FwXE1UGK8QSm`toRo#3+-=aC2pU`=b})wP99EVtqIZ z`%y0(Ev;=Xt}kEQS>^5p6^BxDaFK)<@gS;U>kut=rrz_Jq=HZ)97!Rafq_#Szj9xk{Dr}52;?Gygz{d21*c(F0!a@>nFRBkXIb7qJ<1LXB zHM%LTZg|D{6hO69;_k)czjnhUC+-(GAkG)F{^xPcoydXlKBfg!I`&$trCTq8ol!v^ zD$Z9A=xbz0hs9O?m~dCBG3n8Gi$)@0*la8_V~f7((ktYK^ZT^$^hDpZ+#Ss*nsK#z zV|~r2I}z;pCW#8%SG?b6zM6?Ei&7Xtq*7GP5vhn*t`8jC?G;of#Pw3(vZ#8{MT;3g z*l#WwdG$U$qA3~=#gu7_RL}06x#J6!6wh(@W?^=z2+p_q_Q0hobvvx-9eXpi+F1g; ziQf^rP)&`yvA~T2;{im~0sivBErEDh86CnOwzZPWU{;O)mmhe^2iEt3b!{$fpb}YL z5^ZLa*+}pCfwfWz6B1n&ki?Kq2v}*Ptb}Ayl<%Qf1T%g=iom`nmgIAEpR4uJuBJ;s zPiB#g@O`%Nvtg~*wGe^M~LSN9_O@({|K zfb0BHaOC&P!1pnUSE?@Zx#5oHgnFmi_d6MMF+vyPm{ zMpDwmoMc;W_U-S>x^csox8}@@xfO=iCML2`oR30C6R?=xP40QEa^KfQ`U3db-D9%b zb%%nccvY#bgnosN-*aP+sj=)^KF0JHAq&n8Eb=u<3?#==pcGZ(>TSKjwvJnpG0#I| z7^MgzdAM{v`S7osa3S-7u^d~juG&t}(vaUVXGVaa$PhContPO96J1%$^^?ShSB!Yy z%r=T6>cGoT6TIjcZj1q?8i7kZA6`m$?rjq_LW^9j+(v`6JeIM!j0r90hS^gy-Ravr zDk)nu8YI7>15c^XzG?j*1A%}&i7^z`I}DfK>?Iutorb<=wfZ=DcxWqqCT7tfOs$2O zDzYf^+S(r<1G%kaeW{WAf2dI>OEK=O$|On2@o!7G(C;x{nHRdnFc0Nzp;E;N%d1W6 zmp_ryP*~u&t1z8iP8lA72j80Q*~OA(s=v`?dfHjOnbgawmu36|BZ?u`d(1aj{^CSt zdmX`WXu>pE9``%1%~!!{*3|1hAj`f9gq0NV6_UFG#$V|^aNJl3@`9%zsx@vz#rPW6r@s;fWR|Nf!rdT@86FvZ@x$L|H zeFg0jrHP56<*L&2Q80dVaVcIMcMt%fVgUyY$^p+-UUOrEJ-0v=Or#lR8rg4-QQe3Q zFQ|~jsgV@E$|7&aZetK#i|l|YU^s+XNLvG+(Hl0e5Yx2Cw)@?*uLd%h!u!H(7+X_% zz$@rQoqkxIU&`&BwC1BsIFGJ^jx)viBk+(n`DmAbS3tn#H1?VIC zlB|x~g82HXp>tcH*zXvel*&@f8V=MA{1L+_CxDZF&68pDq=uZ3R_FY5*KhZaHIkDa z=Bfltrp8HW%+`NDf>4$=BSfqoL7Zw+?G(s1Uw8kL#{!>{hEN(T1S4@HSpbVJJ^Awo zd&4`~nQ`JI3-Ev_Cn3WF@Ev2V7;^-OSV=_@&QcvFTvo;5A;9nWI3S%R>SZc@2RMBe zK-iIBQ~=^(CCT2)?>%!AC(Rzs*h;D~B;t?knMDEZetuHAhVZk#?<=B$5J*)yw@i-A zoC&u4uNDAwY)63f1K5v|&9wZ{+y{qCcOMaRrPv|M(5wV305e=#!a5-vlKIBS(Bvqp=L+ZlH*<#CzrD z!x&|Bp5t0b#Q8w|+d6pwDpgvGiPDaERZ)i(LUfsYC_cPC!z@|uT*jKmV}#0xc{MFS zhyogigAN+d3&2B@Ltc?e$74~@$Dod|O-VPyiPUdas6?_;I}3lG+9Tc107Q$ka1uOh zXtc2StT5vGxRPpfH<4Q2$E&CSJan=XWAaC)P<%~uqdRf6?gtOCr&<^#2R2EPKin%o&&Q~G8lJ(g`vs@VNufzGe5wx*^czPc7rcjqRy|( z4>RKPV0eo~W+1Oi1YI}x+m87MXZ}Z?P!d6y1B*g2BF>{J7Zy7Hr8QSOmRxBw&U($< z@3m@ZXbAG+WRcvpQ9zCq;*!E}reHkxO;2>68&y$jE$Njn`qT(&ZlBkVje zFjc^2g-S%H@x6c|!}%A9*Tzmw$)gz(sQB) zlVj?ut<4rkHV>hN7gix^izRS7IAja1TM-v%G08T9Bu3cu6o+u~h|nSG5>q08iYtL@ zZdisMtBTgx*vvUHR=85Z%Y5X^tVRQUA#S38_ zXR-4<;HAsOz*Ou(-*NlTcrHB+o$Vi_3F5bCFgpN-Tz4BXlwxvHUv+9BV9mRpCgME; zG*0K9YMio$0V*qD2T%n+;Fq)Kt_SlQD;of7uusOXn+Twa$m$xB$^>F&F`2vKh z{$ucEDydQ=QJEa4D$%rX<8`H?Ax{+EESHrnWNo}iZOmT%Opc0WTE+bFwQ7#P z9pmg;AXJ!viFm&QWbRv8+pv>S9>JRF^DcE<_%vzo5lYxmx_P7ha%6Q4=+vRZc?pH5 z`_DM%v&KJ^p?a_wWiV}0!e7pi|HFsDx3#3ZlSRgZT)Fiv`G(F{$S!KQa$gz}WYN7B zKADV3L$T(DbGUQ)Fyqq|q*wl-4Qa8J_9&4U5Q`=dEJ_s0Nz5hfNMFl%e?+B$r;6Xy zLF{CAXV~oPi3^mYoPG{A2`W6L;+QG^>BziHQYqXd=2+GLONuT%9L5Ml3t~|^eFFTj zoTN_U&i+~!|Ft#VNr6)p%=z&0tiEXIgCj1RhR!2(&?d}hgtzc*=`FmAuDv}nN>cTP z9#ei#QGXQ(1983+pFdjK7AOW1-~aw2qX&;WFWcgfC5pV`zGp3PR!tBMp$-p_bM7ny z6JR8=sM#H!G-6}RfhdvqGv7hR={Ge=_nJbK?65hD)gX6tQQgmN5l~`EUOz^wWs8K) z2gBJ!@+HOHz58f;ubWVtxQIeKZkZed&_yd$W7bB%5x6#~H}D;=BI__*lcD1frip;9 z8Iybl6R#ye^KK3`xDcjyq8RFo;FE8t=>*xCIO3mCX+K6{(!IZN*sUX$4?XxR5Yr`% zd(F5ek+a(Vide2NfkjALE(jME`s{09$14w6oS*G6)ubH?MJ>WM`)Nb%cjtJ-J{4xc zAR=4%6#G`06Ff#crWMF-!zHh0jOkv*oJhK2*L1um92R#TH4$IQqvMeEO;V3-f9$SB zBl(Bj=I)sFz%ezcRMaHTjAg`$-fPap+JT=$+hvm)kwp)32$yt75~?>4`Yd9c_p3KV zbbLP-4Anh3TDzj7cl?y>)!E0JbR5vCENr8#Zx-37UGq6hJ9zclp@E#IjQjtwW=?X( zmx!V+Z=F5v(;(ua22oDKIKAX{-a~q2+BE*?)m!I55w4K)`|%)&{FulCVjXqj<{77X zYL{Mf_s=~CZiD$?Omn8qI^IO{w<-dS-TE(NsJn4$Sic zwF6(@4~Bm}i1ett9dw0Dgm&7yz?S zG_~%ZP z?`NgG=+Vo86FvHY)~oHpe0EG?JWC={%a2%`v!_R2p@$omPbi{V^~T&?%6=sWJNE<%29~wW%;ncr7=riPp(P_Fg7vdFM?fgc1%1Vw(uXcN@6Yw_8i_)JJXEU2JMUv znwJaVFS2GXVsm^Od{%{DPmG%xG8qa1Uf=w&{A&-$)CSGL=<+TcH=D3 zZmf5fIG=Tw*f&tP*RH8qf;_yhDXA&TDR53-r!8g$?a7;Y!;~Q|>9AZcl`cDQ4DKh& zhNi1+rTzRB_zlH?n0-b z0s)d5@Urk>dW?jhE>GMg-m|I$+ho>e=6l)+&%;|lLr<2?Nh8@^L&rkj^(D-`AX+yj zv>=}t4!L;w7ksTMI%1;I13g55H9UO~WkN(HdMTDfzHl~K+u=#Mce=B~Z1=hMePY`5 zFJV4OR`!1*u#XhfP63}`v|547$@`#RAsEI6XG`j#?o-wg*h6`Q*VNdR0y;o4evbo* zx5}kaB@H@S?^Xjax8wGZfbn0phy5C%c9WS`Os>EmeaHpT;4w}T^1qHF!Ljv4K8Wz_ zs1`#vE4OF+YjDTwTD_8<9lS~70p6&co-+*gU=DhvZ9;z95432$L0mUco1Mjw6Wmam7b>0CvLZp~mJ00d zld@SRn}~)AZ2f7eAH2d6GLwZ4p3rfjJ2F--v~f`{}O)KeaO34 zSsclTzP3?|UnV1ZwKs%A7%`~5$ z$R!IVCP;xcVEW(+|7B~1fqjpjb8}yd3Q-m#KEYM=oVMfXwWiyFl>*H}K*e6y;X7PX zY*cBp*H0h`&;Ft)e#p`=#UI+*`2-!s6INsSmBz^`285z9F{33moF80QAB_7S#RcQ;Hdv{-V-*IlD7wh`aF0No#IT9!=Rd zIjYLo)qhqWXnK%|ictQ)7U7(=q2Ad;L`?LM3RRJhsq%qNU6~JWf1wnQ)5R{@xPt-D zX-7npGWn`v4GVU8haHsZ09*X~>2>ul!+w#By5zI4$y^A#=!z4C-Gh5x0%}1JIGX_w zg_UvpQ<@jMe8lVGSpVHG@S%SI-?Q)wS}`nN*EP8i?2hykc;Dpk2IehMb0^&x58IY z&xtiy#4Kr~@c96ERp}WHTX>UxG%P-x!g1J48{OfPm8}GHbPR4E##krPxnf~%&i9&Y zp)c&nFte8wrVKaj)u_&RsLVJ%S?Qb(XDO`oVt#R~ooEH92z|4rJKdhs`xm7Wc7lrvIWgfsR^3GR9uvy=>AWEgKV_}wt}0 z>bLVR4};|bj@?&p--)(N2?Lf;(_hD#It}Ef{EHm_Lbg}&zhMq~C813N`2`=y)InmYqY==>n@{{k%Gi_|kKdv;p9LIf>Zqso~`Yg-nvJ)gJ z+8TIP15w<$O|m!vyyO@fKe4`9eSoV|=|g_CWX){3tp8jm=V}%~7xVb5gp0#|+_z9# z+HP1eXJ`!afJnaaC=#kw(@T%`yMtfB@2SGZKts?9y2t7d^Mj?-%s$&2?Eb3iHhIkL zt}FlaY14Ce-Gy_fnkMO*LM-Uj9WXI2UE!FWSaQR#J5QA{fD37rnD^hx{453&=9#>Q#iaRLR; zyQ|MDx_YB;AF$Y8zP

59EK?MZyBBv!b+Md7=B%Kcey%E{>GY+AeL8)LH6I@W&1 zt$EYwTZ++cDJUK%j*gZuAYjd>CPs;*TQPJ+xc9j3pm2ZKU0R73+|YH0+$MU@YEdXf zgfwqsOsoKj|d$T3k1E zJ07MNw8E7lKsmIrBPzE}OcXSuO!1LqUteR}ntN3QFx{qp=i zX2)sSD?E>H34j{g)xnqum2a|XM$wApwDc8#@1`b|5flE2QA=AQ6w1{!a_cytA}V|; zjcHi*vY_CZ#|D10p19jAe*c_+rrdCz7~Q=k+Zr2%>9sx!_FAYnKHSag)mdpx9{2M> zBdOcZ^1k#sc%fJFq>KBKU+dfvXJKwZfF<2;81+V2YBP8Djbi0Sz}~OB}A-bIwx>0 znNQ$hAOB8}0?~ED8^w>1slfktM}#|Ls`IQ z6s!D{UDXFsrxn()YjR3FD>Z8(k2lMDxcWY?mJ2Q2hv=VXnUsTq#bnRrrml=d^Y>T5 zVz2eFQxZTmzQ9DIyXkV4d-tRKpKFRM({#y(SXa&w2Y6J|L=53;9mzB|!crGtma{zSjf1G4#`g**I#@hWl&ysttbXYV6eecvsG<1vH;;@mGY?hE3+)Q|*fr5pG?F_N#x%$kAF4$}mQXnVe)$jEuusN*lc z)Q#_At+FB`F`iM7r>7hKtV>)e9F}Ztb9Gg3X8*2(W&_AXvH~gR7yX=TM4==cKX zck{H3Ak9Fl1~;$EIr{DTO-q4trO5&ogyXy=RP{jUd!F)(;FY*6ZI(|Y?*46+$&1WO z`g62$wkxD}zwN;T)Avy3uhu4EKSteILB@spAx_lfY_^I@9wtRvt__W;@q-qwWVnol z=sy$8@T#oUs11fI$A}so*P@G|qU}e1R*`dI{Q3YkE^_ochRQR5RE(8pId+342cJ(j zkZ(lgl#mf!_C{g^-o}eaqKj)G&C={Y+8!Tro-so};%G2kQzf}`X!XD3zo@F(Sr{t8 z=#2we?ee^&&mOn*4Tr%S9`dMz_(~zRbKfbQ(ehq>Z1K;0A`~j0Rp5z{!VJDE-ayh{ zqcp`XPKHYXjJ-D9Pgb88IPj>|@&ZZo=+JE^Gbxr@Lr#VK2gCf{loUWIDg6E%vaHi$ zW_=Yy4N8)wifsM1wjM>;#Xbt&Hg>O1vpG^No{1AS@s*cJ+=9d89vY@*sZ| zE&ET`pCK&Wjb_qhG;B3?*O}vR8m|7YvJB%)bpWSx>@YmOu|+(=tJe_{h$qj|uQKm% z&WmImNn6L+%(9&>vW83$u zyJEi}37DFU3|6?yb%gm3~~y{fQl9kt`8zJ~{Bw97lqBRgXIldpkK`Q0r&Ai=t-c*sXiU z^N}~M9lOp^_~X{Uf%L~=c7}KHd1gC5m}%zq*IR+nBOr3+AX($(_R@qa8TWW1!}{Z5 zNkL*tch>3H%o5Cjz%a3Vj#t8UeJlPKy8bP@pGNMtcgKBVPN2fwkGx$Mvo&Z3)D|QV za}?t~3=mH_ISN1Ji0|33{@rz=hslRwHG`?z@aCrj&P!xVC|6!g`x`)X1#1A#Zu4}w z4q|WrTX$JX)p~7q1_?gSiv|Vk+JYB2$EPLcqeEfWp0?nYzLIyhJk2L9v6Q6Lf#1<= z)T}|;#wH$(_uru_-cK2zGOMkWakzja$u^o#+^ELrcR2U_u}O4 zh`+%i+Y$EgPnipCrjp^Ku;afb%fX!wHw}oNB&C`Gi$Y0O>?I4Dh@&bZnR{H&s7ZHqw_Cq|o0 z8aajO`{ZN)aK<`h=uUM<7dfPqDX};kHYP>;gwSWWhH1Yz_I>O9&)6#38vHvpmmZ?u zW*U{>WFx`4Wfc`(Cs&dRYPorzPD__%z}GQ#|Vpq z+S8N>=i;(S5st`&l>~9|BjE%MCck7vtp|@i;#>EGT;$&-W^yKegVCB@@9Z!^#uPh& zp+Ng(3DbU(O@NjffZ&demL~9$Br=bWnhG%w+d@XC^mPy=?noKtu?`jcZ1%pQW=t#)In4g!_vLs+si&l?d3z--z~`X`hYWzHUf@eL`F~N9joccl!i47xv}l z>(@Z+34V))3+xv19IAviN{RiTFQ@Ax*DEKK;4`o72_sqe5sUn5Ee(-SOnBE?sp$n} z=NqF4{U-K5doF#&%&=|2EKx(U(v&D`-b(&Vf$fUP_!g+8ydgBkPmUyAPNQ*#H=(O`J1(S1-VsCQ}DL5&#m^f31s;K2w2s@tOSoRDE8LxQ)x>v7= z7RFn`B8!=<4E!+S(fJoQ#&;##@8+6hJa4}XSn$veNwJtgxeQ<=2mwDC6wZZ=LuE*X zzd16Z5EPDCDA=v{^yV69=sG=9C9NWdvn`QBvbWvX3`u%l!m?FP3}rVTqt!c)zD&h{ zO_#AiL2Vc4^~Q_?ipm`(wM%~D%f@209Z`?JrJ5vHX zm4(|X+S;|C^!wKjzg!;H1*{jA?M_3~OZ=^?A`RMU-OAHrKIxwAjCdvWhQc>7Y}30n zSK+EvPig~o&C3f6KV?AGnl;^RTOZlYS9Td#X}ixRAz7jizczODH(;5fMkXKXI<8(j zj(p0vFs|{XeYrn}Y#W|JJf8OgA=wMpCFx2r9BbbK#+RObAI_XC8o#$y`MO+qDa*_p zpW(uCP&io^-3<;D(7O}1+oO4vmAc1%=L2wu{8hoGR*)xX1FvU zy$$7!^>JKk&Vi+Gtr!)#N%foXQ9kuEbgpY8wuKVbn>P~~ZnD`x- zt*drAm=Do${nlCvlPu)MtE;yJ%E2)Q_Z!@)6}5#oOr6k5W-kZbLHBt*J@4WqGG%Un z+eCHsLuhVuN`2FIWh2uH4^X`Prw%du0MLN*7KX|$?7WW|}Eo4}H{uc@%kYHrFI^v|7XvH&UXr>;z`X6|Mw zT+QG4QFoTmEj6cHth+3yWU*jP47bS*3EUid`gkj)roe7gSAV)*n%r#!mhH)BMUH=e zScJLeIJKiG3;OKtK;iaI8+!FP(vc&|R?~U&{{2sT^Q?KVwdBy#*!laPI&W@fpWffh zPV3vsxz8je3hV^iv_%;pYv;Ynq3V8)5fpwT^?wO9F8KnNi(1uq=_fC^QL?sC^J28z z_Va_G`DgDAdEp#&sEwiG=AX9KtIMXsY!=;#Ya46m{zJ~yu;rTG_Mg=?*IKoqK<`tK zzOiHT1>KV`Xoc10A*CUu%YLx(P!21U8C2{gw-l3EW@In8=%eiDCp@q(a(pRt?7I|@ zbet8lJ6l#TZXv=5etj2e>+^QS>?7mmhWMQf`Oj?AYfr zIYiU$CU`gKBV-#IYTqwT&~%oZ>Zi>3EiZZd&EE}?6lRT;$+XK%oYK_1OiwG_@NdzU zxWU0;J%OaeHGJ;O?{*xYYki0HMP8N{jD@>%YhLC~Cm%x+xjl8}?PgNDjx&}Ps)BYi zYvPDiAmnfmd^wF#256tvZyNX7d$&}5L#no@UoH7L0e5 zEhAZ~g_|wP=>VWzwTn$IV|&gze};OCYPU5Bx~q9*f)q6l%O`9o*Z9&LcZ<%Oso~#= zUczOKg`eIxDij&mkJnYp`Q4G*g532Pzy@|HIfa)F$*EVqZz@!qZAPYxnS}RON{(U4 zlZ36FL{c4pZg4$w>&X_2SZbGKH2|4Ghs?(Z01R;J^r%40$|Ti_GpwfSysTw3^E|>k ziO90b`UefiqEGJ^k8GDF@^+0nvl7=A_^WoTb%@*%6(WvR`H-8L7p}aVVEnmE5E>95>nrW3aixhf3P&%v5Kr#lb`m64e8k&-;)x^wIuj@gW};&e`Ck! zvCFYH#i<$;I5T|Ww48c#tik%s0z+{)Wf@O+q3PeL4`8|7G7Fzvuczhy?$O`EQ=vU! z%L}~pC9{`CHOvXVVN7!Oy_0^Ply+QkZjDLniL<>W2(0UZon#l+kWWG$)Tixbg zt=>vS+h!QawCU5F%HVefln1pN(55p$`ax1s;f*)@bMH;}Xzc==mGHH}LnD9J%%ey+ z%Ea$o{^7>f(Ix?fjrGS)vW4pw1238K zH!JBvWFf0uF_KAsVekjnJ=@rN22oI_F_)cItZa229z9flbKpkuD}gawi7&NYujWLHP<9Mr`bbetB$rv9f>%)|Hs$qfpLmmuG-^bj%KD;MbZ1oM&~i%iS`x znic8Ik0FQdH{B1Te_ZZ5Dj;23>=aSB@4TWarh3V{Ck+kyxOvCst3;iJ*eGbgXJ^Q{b=mJM{$0`3ZZn% zQIpe*fL-K!3Ez8I5iK}4w!+KGiU|D;RXL6+S^52gf+suGpC*GqF2!yskwX1 zFHa+(U`LOHR3)R1GfxUZA7;@P!tRuP&(ylig!_93$lr=EzP>tVf8T!rEA`th-Q?5s zNy52v_Hw_g`UND>HWp5RpFQq${I?Cetnb_UX=k3&UFM#93g70%Gbaef^$@h1r2!J)a zBW>%Bp(dv@C3YRcefshTU+J!-;!f+ zfAHnx)a;74_&1&&L^Iu+ls8xpwRbbxGS!uLXZP>)&uEvLa1MmaxZP4`^=90`A}tX9 z?)!C*qL;1H;>MhY_xi8r67=NjGGRD&ArB~@P7bkZ9Fyr From 83194e4942bd6ce8c19e776818f4f1abec815b35 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 11 Jul 2023 16:49:31 +0200 Subject: [PATCH 008/105] Drop support for `external_info` and `extra_info` flag --- library/Businessprocess/BpNode.php | 18 ++--------------- .../Storage/LegacyConfigParser.php | 20 ------------------- 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 10e3655..c729c7c 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -15,8 +15,9 @@ class BpNode extends Node const OP_DEGRADED = '%'; protected $operator = '&'; + protected $url; - protected $info_command; + protected $display = 0; /** @var Node[] */ @@ -336,21 +337,6 @@ class BpNode extends Node return $this->url; } - public function setInfoCommand($cmd) - { - $this->info_command = $cmd; - } - - public function hasInfoCommand() - { - return $this->info_command !== null; - } - - public function getInfoCommand() - { - return $this->info_command; - } - public function setStateOverrides(array $overrides, $name = null) { if ($name === null) { diff --git a/library/Businessprocess/Storage/LegacyConfigParser.php b/library/Businessprocess/Storage/LegacyConfigParser.php index 437e369..68cc1be 100644 --- a/library/Businessprocess/Storage/LegacyConfigParser.php +++ b/library/Businessprocess/Storage/LegacyConfigParser.php @@ -237,23 +237,6 @@ class LegacyConfigParser } } - /** - * @param $line - * @param BpConfig $bp - */ - protected function parseExternalInfo(&$line, BpConfig $bp) - { - list($name, $script) = preg_split('~\s*;\s*~', substr($line, 14), 2); - $bp->getBpNode($name)->setInfoCommand($script); - } - - protected function parseExtraInfo(&$line, BpConfig $bp) - { - // TODO: Not yet - // list($name, $script) = preg_split('~\s*;\s*~', substr($line, 14), 2); - // $this->getNode($name)->setExtraInfo($script); - } - protected function parseInfoUrl(&$line, BpConfig $bp) { list($name, $url) = preg_split('~\s*;\s*~', substr($line, 9), 2); @@ -288,10 +271,7 @@ class LegacyConfigParser switch ($type) { case 'external_info': - $this->parseExternalInfo($line, $bp); - break; case 'extra_info': - $this->parseExtraInfo($line, $bp); break; case 'info_url': $this->parseInfoUrl($line, $bp); From cbb6b018da37540fc8655071afea484a4401759c Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon <54990055+sukhwinder33445@users.noreply.github.com> Date: Thu, 20 Jul 2023 13:31:46 +0200 Subject: [PATCH 009/105] Show node id in edit mode (#382) ref #308 --- application/forms/ProcessForm.php | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/application/forms/ProcessForm.php b/application/forms/ProcessForm.php index 604b774..cbc4466 100644 --- a/application/forms/ProcessForm.php +++ b/application/forms/ProcessForm.php @@ -23,24 +23,12 @@ class ProcessForm extends QuickForm /** @var BpNode */ protected $node; - protected $objectList = array(); - - protected $processList = array(); - /** @var SessionNamespace */ protected $session; public function setup() { - if ($this->node === null) { - $this->addElement('text', 'name', array( - 'label' => $this->translate('ID'), - 'required' => true, - 'description' => $this->translate( - 'This is the unique identifier of this process' - ), - )); - } else { + if ($this->node !== null) { $this->addHtml( '

' . $this->getView()->escape( sprintf($this->translate('Modify "%s"'), $this->node->getAlias()) @@ -48,6 +36,14 @@ class ProcessForm extends QuickForm ); } + $this->addElement('text', 'name', [ + 'label' => $this->translate('ID'), + 'value' => (string) $this->node, + 'required' => true, + 'readonly' => $this->node ? true : null, + 'description' => $this->translate('This is the unique identifier of this process') + ]); + $this->addElement('text', 'alias', array( 'label' => $this->translate('Display Name'), 'description' => $this->translate( From 5b4056e1b2b4b0465657426bb9943b52643fd240 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 4 Oct 2022 10:23:55 +0200 Subject: [PATCH 010/105] ServiceNode: `getAlias()` returns null if host or service alias is null --- library/Businessprocess/ServiceNode.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/Businessprocess/ServiceNode.php b/library/Businessprocess/ServiceNode.php index 6160bce..53cef21 100644 --- a/library/Businessprocess/ServiceNode.php +++ b/library/Businessprocess/ServiceNode.php @@ -65,6 +65,10 @@ class ServiceNode extends MonitoredNode public function getAlias() { + if ($this->getHostAlias() === null || $this->alias === null) { + return null; + } + return $this->getHostAlias() . ': ' . $this->alias; } From 2f730cc52669262d564710abb2eda2a41d982260 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 4 Oct 2022 10:54:32 +0200 Subject: [PATCH 011/105] Display node name if alias is missing This fixes the issue that the name of a missing monitoring node is not displayed in forms and in Tree/Tile view. --- application/forms/DeleteNodeForm.php | 9 +++++---- application/forms/EditNodeForm.php | 3 ++- application/forms/SimulationForm.php | 2 +- library/Businessprocess/MonitoredNode.php | 4 ++-- .../Businessprocess/Renderer/TileRenderer/NodeTile.php | 6 +++++- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/application/forms/DeleteNodeForm.php b/application/forms/DeleteNodeForm.php index dada9d3..67635bb 100644 --- a/application/forms/DeleteNodeForm.php +++ b/application/forms/DeleteNodeForm.php @@ -31,15 +31,16 @@ class DeleteNodeForm extends QuickForm public function setup() { $node = $this->node; + $nodeName = $node->getAlias() ?? $node->getName(); $view = $this->getView(); $this->addHtml( '

' . $view->escape( - sprintf($this->translate('Delete "%s"'), $node->getAlias()) + sprintf($this->translate('Delete "%s"'), $nodeName) ) . '

' ); $biLink = $view->qlink( - $node->getAlias(), + $nodeName, 'businessprocess/node/impact', array('name' => $node->getName()), array('data-base-target' => '_next') @@ -61,7 +62,7 @@ class DeleteNodeForm extends QuickForm } else { $yesMsg = sprintf( $this->translate('Delete root node "%s"'), - $this->node->getAlias() + $nodeName ); } @@ -74,7 +75,7 @@ class DeleteNodeForm extends QuickForm 'multiOptions' => $this->optionalEnum(array( 'no' => $this->translate('No'), 'yes' => $yesMsg, - 'all' => sprintf($this->translate('Delete all occurrences of %s'), $node->getAlias()), + 'all' => sprintf($this->translate('Delete all occurrences of %s'), $nodeName), )) )); } diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php index f26dd04..b22117e 100644 --- a/application/forms/EditNodeForm.php +++ b/application/forms/EditNodeForm.php @@ -48,9 +48,10 @@ class EditNodeForm extends QuickForm } $view = $this->getView(); + $nodeName = $this->getNode()->getAlias() ?? $this->getNode()->getName(); $this->addHtml( '

' . $view->escape( - sprintf($this->translate('Modify "%s"'), $this->getNode()->getAlias()) + sprintf($this->translate('Modify "%s"'), $nodeName) ) . '

' ); diff --git a/application/forms/SimulationForm.php b/application/forms/SimulationForm.php index 263976b..47c9f52 100644 --- a/application/forms/SimulationForm.php +++ b/application/forms/SimulationForm.php @@ -44,7 +44,7 @@ class SimulationForm extends QuickForm } $this->addHtml( '

' - . $view->escape(sprintf($title, $node->getAlias())) + . $view->escape(sprintf($title, $node->getAlias() ?? $node->getName())) . '

' ); diff --git a/library/Businessprocess/MonitoredNode.php b/library/Businessprocess/MonitoredNode.php index 3c4167d..7047e5d 100644 --- a/library/Businessprocess/MonitoredNode.php +++ b/library/Businessprocess/MonitoredNode.php @@ -11,9 +11,9 @@ abstract class MonitoredNode extends Node public function getLink() { if ($this->isMissing()) { - return Html::tag('a', ['href' => '#'], $this->getAlias()); + return Html::tag('a', ['href' => '#'], $this->getAlias() ?? $this->getName()); } else { - return Html::tag('a', ['href' => $this->getUrl()], $this->getAlias()); + return Html::tag('a', ['href' => $this->getUrl()], $this->getAlias() ?? $this->getName()); } } } diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index 67bb4a6..a9d67b7 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -180,7 +180,11 @@ class NodeTile extends BaseHtmlElement $node = $this->node; $url = $this->getMainNodeUrl($node); if ($node instanceof MonitoredNode) { - $link = Html::tag('a', ['href' => $url, 'data-base-target' => '_next'], $node->getAlias()); + $link = Html::tag( + 'a', + ['href' => $url, 'data-base-target' => '_next'], + $node->getAlias() ?? $node->getName() + ); } else { $link = Html::tag('a', ['href' => $url], $node->getAlias()); } From c2e06aca0a20b20481b2d06fdc76cf58b293120b Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 21 Jul 2022 15:48:15 +0200 Subject: [PATCH 012/105] TreeRenderer: Use Icinga Web's collapsible implementation now resolves #254 --- library/Businessprocess/Renderer/Renderer.php | 2 +- .../Businessprocess/Renderer/TreeRenderer.php | 43 +++++++--- public/css/module.less | 78 +++++++++---------- public/js/module.js | 50 ++++++------ 4 files changed, 95 insertions(+), 78 deletions(-) diff --git a/library/Businessprocess/Renderer/Renderer.php b/library/Businessprocess/Renderer/Renderer.php index 58e1c4d..94a9667 100644 --- a/library/Businessprocess/Renderer/Renderer.php +++ b/library/Businessprocess/Renderer/Renderer.php @@ -265,7 +265,7 @@ abstract class Renderer extends HtmlDocument */ public function getId(Node $node, $path) { - return md5((empty($path) ? '' : implode(';', $path)) . $node->getName()); + return 'businessprocess-' . md5((empty($path) ? '' : implode(';', $path)) . $node->getName()); } public function setPath(array $path) diff --git a/library/Businessprocess/Renderer/TreeRenderer.php b/library/Businessprocess/Renderer/TreeRenderer.php index a34ac35..add4334 100644 --- a/library/Businessprocess/Renderer/TreeRenderer.php +++ b/library/Businessprocess/Renderer/TreeRenderer.php @@ -2,19 +2,24 @@ namespace Icinga\Module\Businessprocess\Renderer; +use Icinga\Application\Version; use Icinga\Date\DateFormatter; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Form\CsrfToken; -use Icinga\Module\Icingadb\Model\State; +use ipl\Html\Attributes; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; +use ipl\Html\HtmlElement; +use ipl\Web\Widget\Icon; use ipl\Web\Widget\StateBall; class TreeRenderer extends Renderer { + const NEW_COLLAPSIBLE_IMPLEMENTATION_SINCE = '2.11.2'; + public function assemble() { $bp = $this->config; @@ -32,7 +37,6 @@ class TreeRenderer extends Renderer 'put' => 'function:rowPutAllowed' ]), 'data-sortable-invert-swap' => 'true', - 'data-is-root-config' => $this->wantsRootNodes() ? 'true' : 'false', 'data-csrf-token' => CsrfToken::generate() ], $this->renderBp($bp) @@ -42,6 +46,10 @@ class TreeRenderer extends Renderer 'data-action-url', $this->getUrl()->with(['config' => $bp->getName()])->getAbsoluteUrl() ); + + if (version_compare(Version::VERSION, self::NEW_COLLAPSIBLE_IMPLEMENTATION_SINCE, '<')) { + $tree->getAttributes()->add('data-is-root-config', true); + } } else { $nodeName = $this->parent instanceof ImportedNode ? $this->parent->getNodeName() @@ -192,27 +200,35 @@ class TreeRenderer extends Renderer $attributes->add('class', 'node'); } - $div = Html::tag('div'); - $li->add($div); + $details = new HtmlElement('details', Attributes::create(['open' => true])); + $summary = new HtmlElement('summary'); + if (version_compare(Version::VERSION, self::NEW_COLLAPSIBLE_IMPLEMENTATION_SINCE, '>=')) { + $details->getAttributes()->add('class', 'collapsible'); + $summary->getAttributes()->add('class', 'collapsible-control'); // Helps JS, improves performance a bit + } - $div->add($node->getLink()); - $div->add($this->getNodeIcons($node, $path)); + $summary->addHtml( + new Icon('caret-down', ['class' => 'collapse-icon']), + new Icon('caret-right', ['class' => 'expand-icon']) + ); - $div->add(Html::tag('span', null, $node->getAlias())); + $summary->add($this->getNodeIcons($node, $path)); + + $summary->add(Html::tag('span', null, $node->getAlias())); if ($node instanceof BpNode) { - $div->add(Html::tag('span', ['class' => 'op'], $node->operatorHtml())); + $summary->add(Html::tag('span', ['class' => 'op'], $node->operatorHtml())); } if ($node instanceof BpNode && $node->hasInfoUrl()) { - $div->add($this->createInfoAction($node)); + $summary->add($this->createInfoAction($node)); } $differentConfig = $node->getBpConfig()->getName() !== $this->getBusinessProcess()->getName(); if (! $this->isLocked() && !$differentConfig) { - $div->add($this->getActionIcons($bp, $node)); + $summary->add($this->getActionIcons($bp, $node)); } elseif ($differentConfig) { - $div->add($this->actionIcon( + $summary->add($this->actionIcon( 'forward', $this->getSourceUrl($node)->addParams(['mode' => 'tree'])->getAbsoluteUrl(), mt('businessprocess', 'Show this process as part of its original configuration') @@ -240,7 +256,6 @@ class TreeRenderer extends Renderer ]) ->getAbsoluteUrl() ]); - $li->add($ul); $path[] = $differentConfig ? $node->getIdentifier() : $node->getName(); foreach ($node->getChildren() as $name => $child) { @@ -251,6 +266,10 @@ class TreeRenderer extends Renderer } } + $details->addHtml($summary); + $details->addHtml($ul); + $li->addHtml($details); + return $li; } diff --git a/public/css/module.less b/public/css/module.less index 7576834..1c2f57e 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -118,7 +118,7 @@ ul.bp { } } &[data-sortable-disabled="true"] { - li.process > div { + li.process summary { cursor: pointer; } } @@ -143,15 +143,17 @@ ul.bp { // ghost style &.sortable > li.sortable-ghost { - position: relative; - overflow: hidden; - max-height: 30em; - background-color: @gray-lighter; - border: .2em dotted @gray-light; - border-left-width: 0; - border-right-width: 0; + > details { + position: relative; + overflow: hidden; + max-height: 30em; + background-color: @gray-lighter; + border: .2em dotted @gray-light; + border-left-width: 0; + border-right-width: 0; + } - &.process:after { + &.process > .details:after { // TODO: Only apply if content overflows? content: " "; position: absolute; @@ -164,12 +166,14 @@ ul.bp { } // header style - li.process > div { + li.process summary { padding: .291666667em 0; border-bottom: 1px solid @gray-light; + user-select: none; - > a.toggle { - min-width: 1.25em; // So that process icons align with their node's icons + > .icon:nth-child(1), + > .icon:nth-child(2) { + min-width: 1.3em; // So that process icons align with their node's icons color: @gray; } @@ -187,8 +191,23 @@ ul.bp { } } + li.process.sortable-ghost details:not([open]) > summary { + border-bottom: none; + } + + // TODO: Remove once support for Icinga Web 2.10.x is dropped + li.process details:not(.collapsible) { + &[open] > summary .expand-icon { + display: none; + } + + &:not([open]) > summary .collapse-icon { + display: none; + } + } + // subprocess style - li.process > ul { + li.process > details ul { padding-left: 2em; list-style-type: none; @@ -216,7 +235,7 @@ ul.bp { } // horizontal layout - li.process > div, + li.process summary, li:not(.process) { display: flex; align-items: center; @@ -241,42 +260,23 @@ ul.bp { } // collapse handling - li.process { - // toggle, default - > div > a.toggle > i:before { - -webkit-transition: -webkit-transform 0.3s; - -moz-transition: -moz-transform 0.3s; - -o-transition: -o-transform 0.3s; - transition: transform 0.3s; - } + li.process details:not([open]) { + margin-bottom: (@vertical-tree-item-gap * 2); - // toggle, collapsed - &.collapsed > div > a.toggle > i:before { - -moz-transform:rotate(-90deg); - -ms-transform:rotate(-90deg); - -o-transform:rotate(-90deg); - -webkit-transform:rotate(-90deg); - transform:rotate(-90deg); - } - - &.collapsed { - margin-bottom: (@vertical-tree-item-gap * 2); - - > ul.bp { - display: none; - } + > ul.bp { + display: none; } } // hover style - li.process:hover > div { + li.process:hover summary { background-color: @tr-active-color; } li:not(.process):hover { background-color: @tr-active-color; } - li.process > div > .state-ball, + li.process summary > .state-ball, li:not(.process) > .state-ball { border: .15em solid @body-bg-color; diff --git a/public/js/module.js b/public/js/module.js index ca9e238..8bc6223 100644 --- a/public/js/module.js +++ b/public/js/module.js @@ -25,8 +25,7 @@ this.module.on('focus', 'form input, form textarea, form select', this.formElementFocus); - this.module.on('click', 'li.process a.toggle', this.processToggleClick); - this.module.on('click', 'li.process > div', this.processHeaderClick); + this.module.on('click', 'li.process summary:not(.collapsible-control)', this.processHeaderClick); this.module.on('end', 'ul.sortable', this.rowDropped); this.module.on('click', 'div.tiles > div', this.tileClick); @@ -42,42 +41,41 @@ onRendered: function (event) { var $container = $(event.currentTarget); this.fixFullscreen($container); - this.restoreCollapsedBps($container); + this.restoreCollapsedBps(event.target); this.highlightFormErrors($container); this.hideInactiveFormDescriptions($container); this.fixTileLinksOnDashboard($container); }, - processToggleClick: function (event) { + // TODO: Remove once support for Icinga Web 2.10.x is dropped + processHeaderClick: function (event) { event.stopPropagation(); + event.preventDefault(); - var $li = $(event.currentTarget).closest('li.process'); - $li.toggleClass('collapsed'); + let details = event.currentTarget.parentNode; + details.open = ! details.open; - var $bpUl = $(event.currentTarget).closest('.content > ul.bp'); - if (! $bpUl.length || !$bpUl.data('isRootConfig')) { + let bpUl = event.currentTarget.closest('.content > ul.bp'); + if (! bpUl || ! ('isRootConfig' in bpUl.dataset)) { return; } - var bpName = $bpUl.attr('id'); + let bpName = bpUl.id; if (typeof this.idCache[bpName] === 'undefined') { this.idCache[bpName] = []; } - var index = this.idCache[bpName].indexOf($li.attr('id')); - if ($li.is('.collapsed')) { + let li = details.parentNode; + let index = this.idCache[bpName].indexOf(li.id); + if (! details.open) { if (index === -1) { - this.idCache[bpName].push($li.attr('id')); + this.idCache[bpName].push(li.id); } } else if (index !== -1) { this.idCache[bpName].splice(index, 1); } }, - processHeaderClick: function (event) { - this.processToggleClick(event); - }, - hideInactiveFormDescriptions: function($container) { $container.find('dd').not('.active').find('p.description').hide(); }, @@ -226,23 +224,23 @@ } }, - restoreCollapsedBps: function($container) { - var $bpUl = $container.find('.content > ul.bp'); - if (! $bpUl.length || !$bpUl.data('isRootConfig')) { + // TODO: Remove once support for Icinga Web 2.10.x is dropped + restoreCollapsedBps: function(container) { + let bpUl = container.querySelector('.content > ul.bp'); + if (! bpUl || ! ('isRootConfig' in bpUl.dataset)) { return; } - var bpName = $bpUl.attr('id'); + let bpName = bpUl.id; if (typeof this.idCache[bpName] === 'undefined') { return; } - var _this = this; - $bpUl.find('li.process') - .filter(function () { - return _this.idCache[bpName].indexOf(this.id) !== -1; - }) - .addClass('collapsed'); + bpUl.querySelectorAll('li.process').forEach(li => { + if (this.idCache[bpName].indexOf(li.id) !== -1) { + li.querySelector(':scope > details').open = false; + } + }); }, /** BEGIN Form handling, borrowed from Director **/ From 1aba349be538a50be51d3ca145e92059499f44e8 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Thu, 20 Jul 2023 10:58:38 +0200 Subject: [PATCH 013/105] NodeRemoveAction: Remove stateoverrides of node while removing node --- .../Modification/NodeRemoveAction.php | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/library/Businessprocess/Modification/NodeRemoveAction.php b/library/Businessprocess/Modification/NodeRemoveAction.php index 3090ee6..05a2a92 100644 --- a/library/Businessprocess/Modification/NodeRemoveAction.php +++ b/library/Businessprocess/Modification/NodeRemoveAction.php @@ -3,6 +3,8 @@ namespace Icinga\Module\Businessprocess\Modification; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\BpNode; +use Icinga\Module\Businessprocess\Node; /** * NodeRemoveAction @@ -64,6 +66,13 @@ class NodeRemoveAction extends NodeAction { $name = $this->getNodeName(); $parentName = $this->getParentName(); + $node = $config->getNode($name); + + $this->updateStateOverrides( + $node, + $parentName ? $config->getNode($parentName) : null + ); + if ($parentName === null) { if (! $config->hasBpNode($name)) { $config->removeNode($name); @@ -82,7 +91,6 @@ class NodeRemoveAction extends NodeAction } } } else { - $node = $config->getNode($name); $parent = $config->getBpNode($parentName); $parent->removeChild($name); $node->removeParent($parentName); @@ -91,4 +99,28 @@ class NodeRemoveAction extends NodeAction } } } + + /** + * Update state overrides + * + * @param Node $node + * @param BpNode|null $nodeParent + * + * @return void + */ + private function updateStateOverrides(Node $node, ?BpNode $nodeParent): void + { + $parents = []; + if ($nodeParent !== null) { + $parents = [$nodeParent]; + } else { + $parents = $node->getParents(); + } + + foreach ($parents as $parent) { + $parentStateOverrides = $parent->getStateOverrides(); + unset($parentStateOverrides[$node->getName()]); + $parent->setStateOverrides($parentStateOverrides); + } + } } From 21c1949b07d01e99b60b58a27229c699791969f2 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 27 Sep 2022 15:53:51 +0200 Subject: [PATCH 014/105] Introduce `CleanupNodeForm` action This helps to clean orphaned (missing) nodes --- application/controllers/ProcessController.php | 25 ++++- application/forms/CleanupNodeForm.php | 93 +++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 application/forms/CleanupNodeForm.php diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 475826f..404b8f4 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -120,7 +120,7 @@ class ProcessController extends Controller $missing = array_slice($missing, 0, 10); $missing[] = '...'; } - $bp->addError('There are %d missing nodes: %s', $count, implode(', ', $missing)); + $bp->addError('There are %d missing nodes: %s ', $count, implode(', ', $missing)); } $this->content()->add($this->showHints($bp)); $this->content()->add($this->showWarnings($bp)); @@ -232,6 +232,12 @@ class ProcessController extends Controller ->setParentNode($node) ->setSession($this->session()) ->handleRequest(); + } elseif ($action === 'cleanup' && $canEdit) { + $form = $this->loadForm('CleanupNode') + ->setSuccessUrl(Url::fromRequest()->without('action')) + ->setProcess($bp) + ->setSession($this->session()) + ->handleRequest(); } elseif ($action === 'editmonitored' && $canEdit) { $form = $this->loadForm('EditNode') ->setSuccessUrl(Url::fromRequest()->without('action')) @@ -324,6 +330,23 @@ class ProcessController extends Controller { $ul = Html::tag('ul', ['class' => 'error']); foreach ($bp->getErrors() as $error) { + if (strpos($error, 'missing nodes')) { + $error = [ + $error, + Html::tag( + 'a', + [ + 'href' => Url::fromPath('businessprocess/process/show') + ->setParams( + $this->getRequest()->getUrl()->getParams() + ->add('action', 'cleanup') + ) + ], + $this->translate('Cleanup') + ) + ]; + } + $ul->add(Html::tag('li')->setContent($error)); } if ($bp->hasChanges()) { diff --git a/application/forms/CleanupNodeForm.php b/application/forms/CleanupNodeForm.php new file mode 100644 index 0000000..22c5c50 --- /dev/null +++ b/application/forms/CleanupNodeForm.php @@ -0,0 +1,93 @@ +addHtml(Html::tag('h2', $this->translate('Cleanup missing nodes'))); + + $this->addElement('checkbox', 'cleanup_all', [ + 'class' => 'autosubmit', + 'label' => $this->translate('Cleanup all missing nodes'), + 'description' => $this->translate('Remove all missing nodes from config') + ]); + + if ($this->getSentValue('cleanup_all') !== '1') { + $this->addElement('multiselect', 'nodes', [ + 'label' => $this->translate('Select nodes to cleanup'), + 'required' => true, + 'size' => 8, + 'multiOptions' => $this->bp->getMissingChildren() + ]); + } + } + + /** + * @param MonitoringBackend|IcingaDbConnection $backend + * @return $this + */ + public function setBackend($backend) + { + $this->backend = $backend; + return $this; + } + + /** + * @param BpConfig $process + * @return $this + */ + public function setProcess(BpConfig $process) + { + $this->bp = $process; + $this->setBackend($process->getBackend()); + return $this; + } + + /** + * @param SessionNamespace $session + * @return $this + */ + public function setSession(SessionNamespace $session) + { + $this->session = $session; + return $this; + } + + public function onSuccess() + { + $changes = ProcessChanges::construct($this->bp, $this->session); + + $nodesToCleanup = $this->getValue('cleanup_all') === '1' + ? array_keys($this->bp->getMissingChildren()) + : $this->getValue('nodes'); + + foreach ($nodesToCleanup as $nodeName) { + $node = $this->bp->getNode($nodeName); + $changes->deleteNode($node); + } + + unset($changes); + + parent::onSuccess(); + } +} From b053a78a131cf39bc4ac085d0328928177d242ba Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 28 Sep 2022 17:55:02 +0200 Subject: [PATCH 015/105] ProcessController: Add `Show` link for missing linked nodes --- application/controllers/ProcessController.php | 92 +++++++++++++------ 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 404b8f4..ef525c6 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -27,7 +27,10 @@ use Icinga\Web\Url; use Icinga\Web\Widget\Tabextension\DashboardAction; use Icinga\Web\Widget\Tabextension\OutputFormat; use ipl\Html\Html; +use ipl\Html\HtmlElement; use ipl\Html\HtmlString; +use ipl\Html\TemplateString; +use ipl\Web\Widget\Link; class ProcessController extends Controller { @@ -114,14 +117,6 @@ class ProcessController extends Controller $this->tabs()->extend(new OutputFormat()); - $missing = $bp->getMissingChildren(); - if (! empty($missing)) { - if (($count = count($missing)) > 10) { - $missing = array_slice($missing, 0, 10); - $missing[] = '...'; - } - $bp->addError('There are %d missing nodes: %s ', $count, implode(', ', $missing)); - } $this->content()->add($this->showHints($bp)); $this->content()->add($this->showWarnings($bp)); $this->content()->add($this->showErrors($bp)); @@ -329,26 +324,11 @@ class ProcessController extends Controller protected function showHints(BpConfig $bp) { $ul = Html::tag('ul', ['class' => 'error']); + $this->prepareMissingNodeLinks($ul); foreach ($bp->getErrors() as $error) { - if (strpos($error, 'missing nodes')) { - $error = [ - $error, - Html::tag( - 'a', - [ - 'href' => Url::fromPath('businessprocess/process/show') - ->setParams( - $this->getRequest()->getUrl()->getParams() - ->add('action', 'cleanup') - ) - ], - $this->translate('Cleanup') - ) - ]; - } - - $ul->add(Html::tag('li')->setContent($error)); + $ul->addHtml(Html::tag('li', $error)); } + if ($bp->hasChanges()) { $li = Html::tag('li')->setSeparator(' '); $li->add(sprintf( @@ -389,6 +369,66 @@ class ProcessController extends Controller } } + protected function prepareMissingNodeLinks(HtmlElement $ul): void + { + $missing = $this->bp->getMissingChildren(); + if (! empty($missing)) { + $missingLinkedNodes = null; + foreach ($this->bp->getImportedNodes() as $process) { + if ($process->hasMissingChildren()) { + $missingLinkedNodes = array_keys($process->getMissingChildren()); + $link = Url::fromPath('businessprocess/process/show') + ->addParams(['config' => $process->getConfigName()]); + + $ul->addHtml(Html::tag( + 'li', + [ + TemplateString::create( + tp( + 'Linked node %s has one missing child node: {{#link}}Show{{/link}}', + 'Linked node %s has %d missing child nodes: {{#link}}Show{{/link}}', + count($missingLinkedNodes) + ), + $process->getAlias(), + count($missingLinkedNodes), + ['link' => new Link(null, (string) $link)] + ) + ] + )); + } + } + + if (! empty($missingLinkedNodes)) { + return; + } + + $count = count($missing); + if ($count > 10) { + $missing = array_slice($missing, 0, 10); + $missing[] = '...'; + } + + $link = Url::fromPath('businessprocess/process/show') + ->addParams(['config' => $this->bp->getName(), 'action' => 'cleanup']); + + $ul->addHtml(Html::tag( + 'li', + [ + TemplateString::create( + tp( + '{{#link}}Cleanup{{/link}} one missing node: %2$s', + '{{#link}}Cleanup{{/link}} %d missing nodes: %s', + count($missing) + ), + ['link' => new Link(null, (string) $link)], + $count, + implode(', ', $missing) + ) + ] + )); + } + } + /** * Show the source code for a process */ From 5fcd8246b8b6528c8b6dda049883ff29bfcf16c5 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Thu, 29 Sep 2022 12:21:40 +0200 Subject: [PATCH 016/105] Add cli command `Cleanup` --- application/clicommands/CleanupCommand.php | 106 +++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 application/clicommands/CleanupCommand.php diff --git a/application/clicommands/CleanupCommand.php b/application/clicommands/CleanupCommand.php new file mode 100644 index 0000000..04fc781 --- /dev/null +++ b/application/clicommands/CleanupCommand.php @@ -0,0 +1,106 @@ +storage = LegacyStorage::getInstance(); + } + + /** + * Cleanup all missing monitoring nodes from the specified config name + * If no config name is specified, the missing nodes are cleaned from all available configs. + * Invalid config files and file names are ignored + * + * USAGE + * + * icingacli businessprocess cleanup [] + * + * OPTIONS + * + * + */ + public function cleanupAction(): void + { + $configNames = (array) $this->params->shift() ?: $this->storage->listAllProcessNames(); + $foundMissingNode = false; + foreach ($configNames as $configName) { + if (! $this->storage->hasProcess($configName)) { + continue; + } + + try { + $bp = $this->storage->loadProcess($configName); + } catch (Exception $e) { + Logger::error( + 'Failed to scan the %s.conf file for missing nodes. Invalid config found.', + $configName + ); + + continue; + } + + if (Module::exists('icingadb') + && (! $bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend()) + ) { + IcingaDbState::apply($bp); + } else { + MonitoringState::apply($bp); + } + + $removedNodes = []; + foreach (array_keys($bp->getMissingChildren()) as $missingNode) { + $node = $bp->getNode($missingNode); + $remove = new NodeRemoveAction($node); + + try { + if ($remove->appliesTo($bp)) { + $remove->applyTo($bp); + $removedNodes[] = $node->getName(); + $this->storage->storeProcess($bp); + $bp->clearAppliedChanges(); + + $foundMissingNode = true; + } + } catch (Exception $e) { + Logger::error(sprintf('(%s.conf) %s', $configName, $e->getMessage())); + + continue; + } + } + + if (! empty($removedNodes)) { + echo sprintf( + 'Removed following %d missing node(s) from %s.conf successfully:', + count($removedNodes), + $configName + ); + + echo "\n" . implode("\n", $removedNodes) . "\n\n"; + } + } + + if (! $foundMissingNode) { + echo "No missing node found.\n"; + } + } +} From 6b4a3cbc0cb088cee2632c505966deee140c99ed Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Fri, 9 Jun 2023 10:33:22 +0200 Subject: [PATCH 017/105] Do not break overview page if existing `business-process` has invalid config - Add icon and config file name to broken `business-process` - Use font-awesome icon --- .../Web/Component/BpDashboardTile.php | 10 ++++------ .../Businessprocess/Web/Component/Dashboard.php | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/library/Businessprocess/Web/Component/BpDashboardTile.php b/library/Businessprocess/Web/Component/BpDashboardTile.php index 17d3a0c..9a4a0f6 100644 --- a/library/Businessprocess/Web/Component/BpDashboardTile.php +++ b/library/Businessprocess/Web/Component/BpDashboardTile.php @@ -3,10 +3,12 @@ namespace Icinga\Module\Businessprocess\Web\Component; use Icinga\Module\Businessprocess\BpConfig; -use Icinga\Web\Url; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Html\Text; +use ipl\Web\Url; +use ipl\Web\Widget\Icon; +use ipl\Web\Widget\Link; class BpDashboardTile extends BaseHtmlElement { @@ -16,14 +18,10 @@ class BpDashboardTile extends BaseHtmlElement public function __construct(BpConfig $bp, $title, $description, $icon, $url, $urlParams = null, $attributes = null) { - if (! isset($attributes['href'])) { - $attributes['href'] = Url::fromPath($url, $urlParams ?: []); - } - $this->add(Html::tag( 'div', ['class' => 'bp-link', 'data-base-target' => '_main'], - Html::tag('a', $attributes, Html::tag('i', ['class' => 'icon icon-' . $icon])) + (new Link(new Icon($icon), Url::fromPath($url, $urlParams ?: []), $attributes)) ->add(Html::tag('span', ['class' => 'header'], $title)) ->add($description) )); diff --git a/library/Businessprocess/Web/Component/Dashboard.php b/library/Businessprocess/Web/Component/Dashboard.php index 3423b2f..e78c46c 100644 --- a/library/Businessprocess/Web/Component/Dashboard.php +++ b/library/Businessprocess/Web/Component/Dashboard.php @@ -2,8 +2,10 @@ namespace Icinga\Module\Businessprocess\Web\Component; +use Exception; use Icinga\Application\Modules\Module; use Icinga\Authentication\Auth; +use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Businessprocess\State\IcingaDbState; use Icinga\Module\Businessprocess\State\MonitoringState; @@ -92,7 +94,20 @@ class Dashboard extends BaseHtmlElement $title = $name; } - $bp = $storage->loadProcess($name); + try { + $bp = $storage->loadProcess($name); + } catch (Exception $e) { + $this->add(new BpDashboardTile( + new BpConfig(), + $title, + sprintf(t('File %s has invalid config'), $name . '.conf'), + 'file-circle-xmark', + 'businessprocess/process/show', + ['config' => $name] + )); + + continue; + } if (Module::exists('icingadb') && (! $bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend()) From 834005f7b4ccf37ede463e9d4b896f596480c093 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 17 Jul 2023 13:38:10 +0200 Subject: [PATCH 018/105] Don't break `impact-action` page if bp has invalid config - Add message for invalid config --- application/controllers/NodeController.php | 38 +++++++++++++++++++++- public/css/module.less | 16 +++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/application/controllers/NodeController.php b/application/controllers/NodeController.php index 8addc07..80e6676 100644 --- a/application/controllers/NodeController.php +++ b/application/controllers/NodeController.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Businessprocess\Controllers; +use Exception; use Icinga\Application\Modules\Module; use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Businessprocess\Renderer\Breadcrumb; @@ -11,6 +12,8 @@ use Icinga\Module\Businessprocess\State\IcingaDbState; use Icinga\Module\Businessprocess\State\MonitoringState; use Icinga\Module\Businessprocess\Web\Controller; use Icinga\Module\Businessprocess\Web\Url; +use ipl\Html\Html; +use ipl\Web\Widget\Link; class NodeController extends Controller { @@ -24,9 +27,16 @@ class NodeController extends Controller $name = $this->params->get('name'); $this->addTitle($this->translate('Business Impact (%s)'), $name); + $brokenFiles = []; $simulation = Simulation::fromSession($this->session()); foreach ($this->storage()->listProcessNames() as $configName) { - $config = $this->storage()->loadProcess($configName); + try { + $config = $this->storage()->loadProcess($configName); + } catch (Exception $e) { + $meta = $this->storage()->loadMetadata($configName); + $brokenFiles[$meta->get('Title')] = $configName; + continue; + } $parents = []; if ($config->hasNode($name)) { @@ -108,5 +118,31 @@ class NodeController extends Controller if ($content->isEmpty()) { $content->add($this->translate('No impact detected. Is this node part of a business process?')); } + + if (! empty($brokenFiles)) { + $elem = Html::tag( + 'ul', + ['class' => 'broken-files'], + tp( + 'The following business process has an invalid config file and therefore cannot be read:', + 'The following business processes have invalid config files and therefore cannot be read:', + count($brokenFiles) + ) + ); + + foreach ($brokenFiles as $bpName => $fileName) { + $elem->addHtml( + Html::tag( + 'li', + new Link( + sprintf('%s (%s.conf)', $bpName, $fileName), + (string) Url::fromPath('businessprocess/process/show', ['config' => $fileName]) + ) + ) + ); + } + + $content->addHtml($elem); + } } } diff --git a/public/css/module.less b/public/css/module.less index 1c2f57e..2d278d3 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -288,6 +288,22 @@ ul.bp { } } +// ** Node inspect broken files **/ +ul.broken-files { + .rounded-corners(); + padding: 1em; + margin: 1em 0; + border: 2px solid @state-warning; + font-size: 1.25em; + list-style: none; + + li { + padding-left: 1em; + font-weight: bold; + } +} +// ** END Node inspect broken files **/ + /** BEGIN Dashboard **/ .overview-dashboard { .header { From da0c72d5786320c2145611c726da5344aedea2f6 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 17 Jul 2023 15:13:19 +0200 Subject: [PATCH 019/105] DashboardAction: Use ipl-web's icon --- library/Businessprocess/Web/Component/DashboardAction.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/Businessprocess/Web/Component/DashboardAction.php b/library/Businessprocess/Web/Component/DashboardAction.php index 5ed1845..9bd3240 100644 --- a/library/Businessprocess/Web/Component/DashboardAction.php +++ b/library/Businessprocess/Web/Component/DashboardAction.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess\Web\Component; use Icinga\Web\Url; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; +use ipl\Web\Widget\Icon; class DashboardAction extends BaseHtmlElement { @@ -19,7 +20,7 @@ class DashboardAction extends BaseHtmlElement } $this->add(Html::tag('a', $attributes) - ->add(Html::tag('i', ['class' => 'icon icon-' . $icon])) + ->add(new Icon($icon)) ->add(Html::tag('span', ['class' => 'header'], $title)) ->add($description)); } From 071f006b7d282524a327d9397b6b53aeb606d137 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 25 Jul 2023 10:01:43 +0200 Subject: [PATCH 020/105] AddNodeForm: Don't throw error while adding existing invalid config file --- application/forms/AddNodeForm.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php index 5ef11c7..448250c 100644 --- a/application/forms/AddNodeForm.php +++ b/application/forms/AddNodeForm.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Businessprocess\Forms; +use Exception; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Common\EnumList; @@ -471,7 +472,13 @@ class AddNodeForm extends QuickForm $bp = $this->bp; if ($differentFile) { - $bp = $this->storage->loadProcess($file); + try { + $bp = $this->storage->loadProcess($file); + } catch (Exception $e) { + $this->addError('Cannot add invalid config file'); + + return $list; + } } foreach ($bp->getNodes() as $node) { From 13330d3a44fea9bb9b5657033f9dd5ccc2c23f71 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 10:55:54 +0200 Subject: [PATCH 021/105] Don't cast url to string if it's internally transformed again Also, the cast encodes the url as well, for use within HTML. This is not required if used in conjunction with ipl-html. --- application/controllers/NodeController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/controllers/NodeController.php b/application/controllers/NodeController.php index 80e6676..e5c657f 100644 --- a/application/controllers/NodeController.php +++ b/application/controllers/NodeController.php @@ -136,7 +136,7 @@ class NodeController extends Controller 'li', new Link( sprintf('%s (%s.conf)', $bpName, $fileName), - (string) Url::fromPath('businessprocess/process/show', ['config' => $fileName]) + \ipl\Web\Url::fromPath('businessprocess/process/show', ['config' => $fileName]) ) ) ); From 174abea6bdf1934019326bcbe68c43c2b2ab4533 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 5 Oct 2022 10:49:58 +0200 Subject: [PATCH 022/105] Add custom message for form's regex validation --- application/forms/BpConfigForm.php | 17 ++++++++++++----- application/forms/BpUploadForm.php | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/application/forms/BpConfigForm.php b/application/forms/BpConfigForm.php index b1847f8..2a65b45 100644 --- a/application/forms/BpConfigForm.php +++ b/application/forms/BpConfigForm.php @@ -23,12 +23,19 @@ class BpConfigForm extends BpConfigBaseForm 'max' => 40 ) ), - array( + [ 'validator' => 'Regex', - 'options' => array( - 'pattern' => '/^[a-zA-Z0-9](?:[a-zA-Z0-9 ._-]*)?[a-zA-Z0-9_]$/' - ) - ) + 'options' => [ + 'pattern' => '/^[a-zA-Z0-9](?:[\w\h._-]*)?\w$/', + 'messages' => [ + 'regexNotMatch' => $this->translate( + 'Id must only consist of alphanumeric characters.' + . ' Underscore at the beginning and space, dot and hyphen at the beginning' + . ' and end are not allowed.' + ) + ] + ] + ] ), 'description' => $this->translate( 'This is the unique identifier of this process' diff --git a/application/forms/BpUploadForm.php b/application/forms/BpUploadForm.php index 5d97860..af4af43 100644 --- a/application/forms/BpUploadForm.php +++ b/application/forms/BpUploadForm.php @@ -49,12 +49,19 @@ class BpUploadForm extends BpConfigBaseForm 'max' => 40 ) ), - array( + [ 'validator' => 'Regex', - 'options' => array( - 'pattern' => '/^[a-zA-Z0-9](?:[a-zA-Z0-9 ._-]*)?[a-zA-Z0-9_]$/' - ) - ) + 'options' => [ + 'pattern' => '/^[a-zA-Z0-9](?:[\w\h._-]*)?\w$/', + 'messages' => [ + 'regexNotMatch' => $this->translate( + 'Id must only consist of alphanumeric characters.' + . ' Underscore at the beginning and space, dot and hyphen at the beginning' + . ' and end are not allowed.' + ) + ] + ] + ] ), )); From 4a3b3e36570c6295e98b0680b398aa82cda0931f Mon Sep 17 00:00:00 2001 From: raviks789 <33730024+raviks789@users.noreply.github.com> Date: Mon, 22 Aug 2022 10:01:10 +0200 Subject: [PATCH 023/105] Show Ack/Downtime icons in the node tiles for the handled nodes In case the hosts/services are acknowleded or have scheduled downtime show Acknowledeged or Downtime icons respectively. --- .../Businessprocess/Renderer/TileRenderer/NodeTile.php | 7 +++++++ public/css/module.less | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index a9d67b7..eb85c4e 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -13,6 +13,7 @@ use Icinga\Module\Businessprocess\ServiceNode; use Icinga\Web\Url; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; +use ipl\Web\Widget\Icon; use ipl\Web\Widget\StateBall; class NodeTile extends BaseHtmlElement @@ -263,6 +264,12 @@ class NodeTile extends BaseHtmlElement )); } } + + if ($node->isAcknowledged()) { + $this->actions()->add(new Icon('check', ['class' => 'handled-icon'])); + } elseif ($node->isInDowntime()) { + $this->actions()->add(new Icon('plug', ['class' => 'handled-icon'])); + } } protected function addActionLinks() diff --git a/public/css/module.less b/public/css/module.less index 2d278d3..18edea8 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -486,7 +486,7 @@ td > a > .state-badges { .actions { opacity: 0.8; - margin: 0.5em 0 0 0.5em; + margin: 0.5em 0.5em 0 0.5em; font-size: 0.75em; height: 1.8em; @@ -498,6 +498,14 @@ td > a > .state-badges { line-height: normal; margin: 0; padding: 0 0 0 0.25em; + + &.handled-icon { + display: inline-block; + margin-top: 0.15em; + float: right; + width: 1.5em; + height: 1.5em; + } } a { margin: 0; From 654ba0474d913013eb3c8fce56328008a20ba3c3 Mon Sep 17 00:00:00 2001 From: raviks789 <33730024+raviks789@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:01:48 +0200 Subject: [PATCH 024/105] Show `Ack` icon in tree view for nodes with both downtime and acknowledgement (#352) Acknowledgement takes priority in handled nodes and hence it is sufficient to show acknowledged icons in case the handled node has an acknowledgement and also a downtime is scheduled for it. --- library/Businessprocess/Renderer/TreeRenderer.php | 7 ++++--- public/css/module.less | 8 ++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/library/Businessprocess/Renderer/TreeRenderer.php b/library/Businessprocess/Renderer/TreeRenderer.php index add4334..c5733af 100644 --- a/library/Businessprocess/Renderer/TreeRenderer.php +++ b/library/Businessprocess/Renderer/TreeRenderer.php @@ -133,12 +133,13 @@ class TreeRenderer extends Renderer DateFormatter::timeSince($node->getLastStateChange()) ) ]); - if ($node->isInDowntime()) { - $icons[] = Html::tag('i', ['class' => 'icon icon-plug']); - } + if ($node->isAcknowledged()) { $icons[] = Html::tag('i', ['class' => 'icon icon-ok']); + } elseif ($node->isInDowntime()) { + $icons[] = new Icon('plug'); } + return $icons; } diff --git a/public/css/module.less b/public/css/module.less index 18edea8..95617e5 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -132,12 +132,8 @@ ul.bp { opacity: .8; } - i.icon-ok { - opacity: .8; - } - - i.icon-plug { - opacity: .7; + span.state-ball ~ i:last-of-type { + margin-right: 0; } } From 1ac87cb4ea3c414bda77e2c5ff165d559fc727a5 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 25 Jul 2023 12:58:16 +0200 Subject: [PATCH 025/105] Let all config forms extend `BpConfigBaseForm` They're all too similar. --- application/controllers/ProcessController.php | 2 +- application/forms/AddNodeForm.php | 62 +---------------- application/forms/BpConfigForm.php | 12 ++-- application/forms/BpUploadForm.php | 2 - application/forms/DeleteNodeForm.php | 48 +------------- application/forms/EditNodeForm.php | 48 +------------- application/forms/ProcessForm.php | 48 +------------- application/forms/SimulationForm.php | 4 +- .../Web/Form/BpConfigBaseForm.php | 66 +++++++++++++++++-- 9 files changed, 77 insertions(+), 215 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index ef525c6..6f74be5 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -510,7 +510,7 @@ class ProcessController extends Controller ->setParams($this->getRequest()->getUrl()->getParams()); $this->content()->add( $this->loadForm('bpConfig') - ->setProcessConfig($bp) + ->setProcess($bp) ->setStorage($this->storage()) ->setSuccessUrl($url) ->handleRequest() diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php index 448250c..2f72c6b 100644 --- a/application/forms/AddNodeForm.php +++ b/application/forms/AddNodeForm.php @@ -4,31 +4,17 @@ namespace Icinga\Module\Businessprocess\Forms; use Exception; use Icinga\Module\Businessprocess\BpNode; -use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Common\EnumList; use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Node; -use Icinga\Module\Businessprocess\Storage\Storage; -use Icinga\Module\Businessprocess\Web\Form\QuickForm; +use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator; -use Icinga\Module\Monitoring\Backend\MonitoringBackend; -use Icinga\Web\Session\SessionNamespace; -use ipl\Sql\Connection as IcingaDbConnection; -class AddNodeForm extends QuickForm +class AddNodeForm extends BpConfigBaseForm { use EnumList; - /** @var MonitoringBackend|IcingaDbConnection*/ - protected $backend; - - /** @var Storage */ - protected $storage; - - /** @var BpConfig */ - protected $bp; - /** @var BpNode */ protected $parent; @@ -36,9 +22,6 @@ class AddNodeForm extends QuickForm protected $processList = array(); - /** @var SessionNamespace */ - protected $session; - public function setup() { $view = $this->getView(); @@ -389,37 +372,6 @@ class AddNodeForm extends QuickForm } } - /** - * @param MonitoringBackend|IcingaDbConnection $backend - * @return $this - */ - public function setBackend($backend) - { - $this->backend = $backend; - return $this; - } - - /** - * @param Storage $storage - * @return $this - */ - public function setStorage(Storage $storage) - { - $this->storage = $storage; - return $this; - } - - /** - * @param BpConfig $process - * @return $this - */ - public function setProcess(BpConfig $process) - { - $this->bp = $process; - $this->setBackend($process->getBackend()); - return $this; - } - /** * @param BpNode|null $node * @return $this @@ -438,16 +390,6 @@ class AddNodeForm extends QuickForm return $this->parent !== null; } - /** - * @param SessionNamespace $session - * @return $this - */ - public function setSession(SessionNamespace $session) - { - $this->session = $session; - return $this; - } - protected function hasProcesses() { return count($this->enumProcesses()) > 0; diff --git a/application/forms/BpConfigForm.php b/application/forms/BpConfigForm.php index 2a65b45..8a0bc95 100644 --- a/application/forms/BpConfigForm.php +++ b/application/forms/BpConfigForm.php @@ -116,12 +116,12 @@ class BpConfigForm extends BpConfigBaseForm ), )); - if ($this->config === null) { + if ($this->bp === null) { $this->setSubmitLabel( $this->translate('Add') ); } else { - $config = $this->config; + $config = $this->bp; $meta = $config->getMetadata(); foreach ($meta->getProperties() as $k => $v) { @@ -156,13 +156,13 @@ class BpConfigForm extends BpConfigBaseForm $name = $this->getValue('name'); if ($this->shouldBeDeleted()) { - if ($this->config->isReferenced()) { + if ($this->bp->isReferenced()) { $this->addError(sprintf( $this->translate('Process "%s" cannot be deleted as it has been referenced in other processes'), $name )); } else { - $this->config->clearAppliedChanges(); + $this->bp->clearAppliedChanges(); $this->storage->deleteProcess($name); $this->setSuccessUrl('businessprocess'); $this->redirectOnSuccess(sprintf('Process %s has been deleted', $name)); @@ -174,7 +174,7 @@ class BpConfigForm extends BpConfigBaseForm { $name = $this->getValue('name'); - if ($this->config === null) { + if ($this->bp === null) { if ($this->storage->hasProcess($name)) { $this->addError(sprintf( $this->translate('A process named "%s" already exists'), @@ -199,7 +199,7 @@ class BpConfigForm extends BpConfigBaseForm ); $this->setSuccessMessage(sprintf('Process %s has been created', $name)); } else { - $config = $this->config; + $config = $this->bp; $this->setSuccessMessage(sprintf('Process %s has been stored', $name)); } $meta = $config->getMetadata(); diff --git a/application/forms/BpUploadForm.php b/application/forms/BpUploadForm.php index af4af43..ee3faf3 100644 --- a/application/forms/BpUploadForm.php +++ b/application/forms/BpUploadForm.php @@ -10,8 +10,6 @@ use Icinga\Web\Notification; class BpUploadForm extends BpConfigBaseForm { - protected $backend; - protected $node; protected $objectList = array(); diff --git a/application/forms/DeleteNodeForm.php b/application/forms/DeleteNodeForm.php index 67635bb..30fcdd4 100644 --- a/application/forms/DeleteNodeForm.php +++ b/application/forms/DeleteNodeForm.php @@ -3,31 +3,18 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Module\Businessprocess\BpNode; -use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Node; -use Icinga\Module\Businessprocess\Web\Form\QuickForm; -use Icinga\Module\Monitoring\Backend\MonitoringBackend; -use Icinga\Web\Session\SessionNamespace; -use ipl\Sql\Connection as IcingaDbConnection; +use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; -class DeleteNodeForm extends QuickForm +class DeleteNodeForm extends BpConfigBaseForm { - /** @var MonitoringBackend|IcingaDbConnection */ - protected $backend; - - /** @var BpConfig */ - protected $bp; - /** @var Node */ protected $node; /** @var BpNode */ protected $parentNode; - /** @var SessionNamespace */ - protected $session; - public function setup() { $node = $this->node; @@ -80,27 +67,6 @@ class DeleteNodeForm extends QuickForm )); } - /** - * @param MonitoringBackend|IcingaDbConnection $backend - * @return $this - */ - public function setBackend($backend) - { - $this->backend = $backend; - return $this; - } - - /** - * @param BpConfig $process - * @return $this - */ - public function setProcess(BpConfig $process) - { - $this->bp = $process; - $this->setBackend($process->getBackend()); - return $this; - } - /** * @param Node $node * @return $this @@ -121,16 +87,6 @@ class DeleteNodeForm extends QuickForm return $this; } - /** - * @param SessionNamespace $session - * @return $this - */ - public function setSession(SessionNamespace $session) - { - $this->session = $session; - return $this; - } - public function onSuccess() { $changes = ProcessChanges::construct($this->bp, $this->session); diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php index b22117e..6b73044 100644 --- a/application/forms/EditNodeForm.php +++ b/application/forms/EditNodeForm.php @@ -3,26 +3,16 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Module\Businessprocess\BpNode; -use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Common\EnumList; use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Node; -use Icinga\Module\Businessprocess\Web\Form\QuickForm; +use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator; -use Icinga\Module\Monitoring\Backend\MonitoringBackend; -use Icinga\Web\Session\SessionNamespace; -use ipl\Sql\Connection as IcingaDbConnection; -class EditNodeForm extends QuickForm +class EditNodeForm extends BpConfigBaseForm { use EnumList; - /** @var MonitoringBackend|IcingaDbConnection */ - protected $backend; - - /** @var BpConfig */ - protected $bp; - /** @var Node */ protected $node; @@ -37,9 +27,6 @@ class EditNodeForm extends QuickForm protected $host; - /** @var SessionNamespace */ - protected $session; - public function setup() { $this->host = substr($this->getNode()->getName(), 0, strpos($this->getNode()->getName(), ';')); @@ -283,27 +270,6 @@ class EditNodeForm extends QuickForm )); } - /** - * @param MonitoringBackend|IcingaDbConnection $backend - * @return $this - */ - public function setBackend($backend) - { - $this->backend = $backend; - return $this; - } - - /** - * @param BpConfig $process - * @return $this - */ - public function setProcess(BpConfig $process) - { - $this->bp = $process; - $this->setBackend($process->getBackend()); - return $this; - } - /** * @param BpNode|null $node * @return $this @@ -322,16 +288,6 @@ class EditNodeForm extends QuickForm return $this->parent !== null; } - /** - * @param SessionNamespace $session - * @return $this - */ - public function setSession(SessionNamespace $session) - { - $this->session = $session; - return $this; - } - protected function hasProcesses() { return count($this->enumProcesses()) > 0; diff --git a/application/forms/ProcessForm.php b/application/forms/ProcessForm.php index cbc4466..69ab1a6 100644 --- a/application/forms/ProcessForm.php +++ b/application/forms/ProcessForm.php @@ -3,29 +3,16 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Module\Businessprocess\BpNode; -use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Node; -use Icinga\Module\Businessprocess\Web\Form\QuickForm; -use Icinga\Module\Monitoring\Backend\MonitoringBackend; +use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; use Icinga\Web\Notification; -use Icinga\Web\Session\SessionNamespace; -use ipl\Sql\Connection as IcingaDbConnection; -class ProcessForm extends QuickForm +class ProcessForm extends BpConfigBaseForm { - /** @var MonitoringBackend|IcingaDbConnection */ - protected $backend; - - /** @var BpConfig */ - protected $bp; - /** @var BpNode */ protected $node; - /** @var SessionNamespace */ - protected $session; - public function setup() { if ($this->node !== null) { @@ -94,27 +81,6 @@ class ProcessForm extends QuickForm } } - /** - * @param MonitoringBackend|IcingaDbConnection $backend - * @return $this - */ - public function setBackend($backend) - { - $this->backend = $backend; - return $this; - } - - /** - * @param BpConfig $process - * @return $this - */ - public function setProcess(BpConfig $process) - { - $this->bp = $process; - $this->setBackend($process->getBackend()); - return $this; - } - /** * @param BpNode $node * @return $this @@ -125,16 +91,6 @@ class ProcessForm extends QuickForm return $this; } - /** - * @param SessionNamespace $session - * @return $this - */ - public function setSession(SessionNamespace $session) - { - $this->session = $session; - return $this; - } - public function onSuccess() { $changes = ProcessChanges::construct($this->bp, $this->session); diff --git a/application/forms/SimulationForm.php b/application/forms/SimulationForm.php index 47c9f52..3d43e3a 100644 --- a/application/forms/SimulationForm.php +++ b/application/forms/SimulationForm.php @@ -4,9 +4,9 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Module\Businessprocess\MonitoredNode; use Icinga\Module\Businessprocess\Simulation; -use Icinga\Module\Businessprocess\Web\Form\QuickForm; +use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; -class SimulationForm extends QuickForm +class SimulationForm extends BpConfigBaseForm { /** @var MonitoredNode */ protected $node; diff --git a/library/Businessprocess/Web/Form/BpConfigBaseForm.php b/library/Businessprocess/Web/Form/BpConfigBaseForm.php index ddfc851..5d7e2cd 100644 --- a/library/Businessprocess/Web/Form/BpConfigBaseForm.php +++ b/library/Businessprocess/Web/Form/BpConfigBaseForm.php @@ -5,16 +5,25 @@ namespace Icinga\Module\Businessprocess\Web\Form; use Icinga\Application\Config; use Icinga\Application\Icinga; use Icinga\Authentication\Auth; -use Icinga\Module\Businessprocess\Storage\LegacyStorage; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\Storage\Storage; +use Icinga\Module\Monitoring\Backend\MonitoringBackend; +use Icinga\Web\Session\SessionNamespace; +use ipl\Sql\Connection as IcingaDbConnection; abstract class BpConfigBaseForm extends QuickForm { - /** @var LegacyStorage */ + /** @var Storage */ protected $storage; /** @var BpConfig */ - protected $config; + protected $bp; + + /** @var MonitoringBackend|IcingaDbConnection*/ + protected $backend; + + /** @var SessionNamespace */ + protected $session; protected function listAvailableBackends() { @@ -28,15 +37,60 @@ abstract class BpConfigBaseForm extends QuickForm return $keys; } - public function setStorage(LegacyStorage $storage) + /** + * Set the storage to use + * + * @param Storage $storage + * + * @return $this + */ + public function setStorage(Storage $storage): self { $this->storage = $storage; + return $this; } - public function setProcessConfig(BpConfig $config) + /** + * Set the config to use + * + * @param BpConfig $config + * + * @return $this + */ + public function setProcess(BpConfig $config): self { - $this->config = $config; + $this->bp = $config; + $this->setBackend($config->getBackend()); + + return $this; + } + + /** + * Set the backend to use + * + * @param MonitoringBackend|IcingaDbConnection $backend + * + * @return $this + */ + public function setBackend($backend): self + { + $this->backend = $backend; + + return $this; + } + + /** + * Set the session namespace to use + * + * @param SessionNamespace $session + * + * @return $this + */ + public function setSession(SessionNamespace $session): self + { + $this->session = $session; + return $this; } From 926ac14bd9e123cd01c0f11878251be871aec220 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 25 Jul 2023 13:05:38 +0200 Subject: [PATCH 026/105] css: Apply form specific rules only to `form.bp-form` --- .../Web/Form/BpConfigBaseForm.php | 9 + public/css/module.less | 321 +++++++++--------- 2 files changed, 170 insertions(+), 160 deletions(-) diff --git a/library/Businessprocess/Web/Form/BpConfigBaseForm.php b/library/Businessprocess/Web/Form/BpConfigBaseForm.php index 5d7e2cd..5ccdf06 100644 --- a/library/Businessprocess/Web/Form/BpConfigBaseForm.php +++ b/library/Businessprocess/Web/Form/BpConfigBaseForm.php @@ -123,4 +123,13 @@ abstract class BpConfigBaseForm extends QuickForm return true; } + + protected function setPreferredDecorators() + { + parent::setPreferredDecorators(); + + $this->setAttrib('class', $this->getAttrib('class') . ' bp-form'); + + return $this; + } } diff --git a/public/css/module.less b/public/css/module.less index 95617e5..deb9e3a 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -790,177 +790,178 @@ table.sourcecode { left: -100%; } -form input[type=file] { - padding-right: 1em; -} - -form input[type=submit]:first-of-type { - border-width: 2px; -} - -form p.description { - padding: 1em 1em; - margin: 0; - font-style: italic; - width: 100%; -} - -form ul.form-errors { - margin-bottom: 0.5em; - - ul.errors li { - background: @color-critical; - font-weight: bold; - padding: 0.5em 1em; - color: @text-color-on-icinga-blue; - } -} - -input[type=text], input[type=password], input[type=file], textarea, select { - max-width: 36em; - min-width: 20em; - width: 100%; -} - -label { - line-height: 2em; -} - -form dl { - margin: 0; - padding: 0; -} - -select option { - padding-left: 0.5em; -} - -form dt label { - width: auto; - font-weight: normal; - font-size: inherit; - - &.required { - &::after { - content: '*' - } +form.bp-form { + input[type=file] { + padding-right: 1em; } - &:hover { - text-decoration: underline; - cursor: pointer; + input[type=submit]:first-of-type { + border-width: 2px; } -} -#stateOverrides-element { - display: inline-table; - table-layout: fixed; - border-spacing: .5em; - padding: 0; - - label { - display: table-row; - - span, select { - display: table-cell; - } - - span { - width: 10em; - } - - select { - width: 26em; - } - } -} - -form fieldset { - min-width: 36em; -} - -form dd input.related-action[type='submit'] { - display: none; -} - -form dd.active li.active input.related-action[type='submit'] { - display: inline-block; -} - -form dd.active { p.description { - color: inherit; - font-style: normal; - } -} - -form dd { - padding: 0.3em 0.5em; - margin: 0; -} - -form dt { - padding: 0.5em 0.5em; - margin: 0; -} - -form dt.active, form dd.active { - background-color: @tr-active-color; -} - -form dt { - display: inline-block; - vertical-align: top; - min-width: 12em; - min-height: 2.5em; - width: 30%; - &.errors label { - color: @color-critical; - } -} - -form .errors label { - color: @color-critical; -} - -form dd { - display: inline-block; - width: 63%; - min-height: 2.5em; - vertical-align: top; - margin: 0; - &.errors { - input[type=text], select { - border-color: @color-critical; - } - } - - &.full-width { - padding: 0.5em; + padding: 1em 1em; + margin: 0; + font-style: italic; width: 100%; } -} -form dd:after { - display: block; - content: ''; -} + ul.form-errors { + margin-bottom: 0.5em; -form textarea { - height: auto; -} - -form dd ul.errors { - list-style-type: none; - padding-left: 0.3em; - - li { - color: @color-critical; - padding: 0.3em; + ul.errors li { + background: @color-critical; + font-weight: bold; + padding: 0.5em 1em; + color: @text-color-on-icinga-blue; + } } -} -form { + input[type=text], input[type=password], input[type=file], textarea, select { + max-width: 36em; + min-width: 20em; + width: 100%; + } + + label { + line-height: 2em; + } + + dl { + margin: 0; + padding: 0; + } + + select option { + padding-left: 0.5em; + } + + dt label { + width: auto; + font-weight: normal; + font-size: inherit; + + &.required { + &::after { + content: '*' + } + } + + &:hover { + text-decoration: underline; + cursor: pointer; + } + } + + #stateOverrides-element { + display: inline-table; + table-layout: fixed; + border-spacing: .5em; + padding: 0; + + label { + display: table-row; + + span, select { + display: table-cell; + } + + span { + width: 10em; + } + + select { + width: 26em; + } + } + } + + fieldset { + min-width: 36em; + } + + dd input.related-action[type='submit'] { + display: none; + } + + dd.active li.active input.related-action[type='submit'] { + display: inline-block; + } + + dd.active { + p.description { + color: inherit; + font-style: normal; + } + } + + dd { + padding: 0.3em 0.5em; + margin: 0; + } + + dt { + padding: 0.5em 0.5em; + margin: 0; + } + + dt.active, dd.active { + background-color: @tr-active-color; + } + + dt { + display: inline-block; + vertical-align: top; + min-width: 12em; + min-height: 2.5em; + width: 30%; + &.errors label { + color: @color-critical; + } + } + + .errors label { + color: @color-critical; + } + + dd { + display: inline-block; + width: 63%; + min-height: 2.5em; + vertical-align: top; + margin: 0; + &.errors { + input[type=text], select { + border-color: @color-critical; + } + } + + &.full-width { + padding: 0.5em; + width: 100%; + } + } + + dd:after { + display: block; + content: ''; + } + + textarea { + height: auto; + } + + dd ul.errors { + list-style-type: none; + padding-left: 0.3em; + + li { + color: @color-critical; + padding: 0.3em; + } + } + + #_FAKE_SUBMIT { position: absolute; left: -100%; From 8b2bac4e85865978e52dc1dbb497cd3c762fafb5 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 26 Jul 2023 16:55:09 +0200 Subject: [PATCH 027/105] MoveNodeForm: Instruct JS to refresh the target container instead of letting JS refresh it on its own --- application/controllers/ProcessController.php | 7 +++++++ application/forms/MoveNodeForm.php | 6 +++++- public/js/module.js | 12 ++---------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 6f74be5..915aa6b 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -263,7 +263,14 @@ class ProcessController extends Controller ->setSimulation(Simulation::fromSession($this->session())) ->handleRequest(); } elseif ($action === 'move') { + $successUrl = $this->url()->without(['action', 'movenode']); + if ($this->params->get('mode') === 'tree') { + // If the user moves a node from a subtree, the `node` param exists + $successUrl->getParams()->remove('node'); + } + $form = $this->loadForm('MoveNode') + ->setSuccessUrl($successUrl) ->setProcess($bp) ->setParentNode($node) ->setSession($this->session()) diff --git a/application/forms/MoveNodeForm.php b/application/forms/MoveNodeForm.php index 8e77f87..7396277 100644 --- a/application/forms/MoveNodeForm.php +++ b/application/forms/MoveNodeForm.php @@ -171,7 +171,11 @@ class MoveNodeForm extends QuickForm $this->notifySuccess($this->getSuccessMessage($this->translate('Node order updated'))); $response = $this->getRequest()->getResponse() - ->setHeader('X-Icinga-Container', 'ignore'); + ->setHeader('X-Icinga-Container', 'ignore') + ->setHeader('X-Icinga-Extra-Updates', implode(';', [ + $this->getRequest()->getHeader('X-Icinga-Container'), + $this->getSuccessUrl()->getAbsoluteUrl() + ])); Session::getSession()->write(); $response->sendResponse(); diff --git a/public/js/module.js b/public/js/module.js index 8bc6223..4855c9c 100644 --- a/public/js/module.js +++ b/public/js/module.js @@ -122,11 +122,7 @@ ].join('&'); var $container = $source.closest('.container'); - var req = icinga.loader.loadUrl(actionUrl, $container, data, 'POST'); - req.always(function() { - icinga.loader.loadUrl( - $container.data('icingaUrl'), $container, undefined, undefined, undefined, true); - }); + icinga.loader.loadUrl(actionUrl, $container, data, 'POST'); } }, @@ -159,11 +155,7 @@ ].join('&'); var $container = $target.closest('.container'); - var req = icinga.loader.loadUrl(actionUrl, $container, data, 'POST'); - req.always(function() { - icinga.loader.loadUrl( - $container.data('icingaUrl'), $container, undefined, undefined, undefined, true); - }); + icinga.loader.loadUrl(actionUrl, $container, data, 'POST'); event.stopPropagation(); } }, From 96f94f995939ef4b3f20fe919ff0ed0e53446e43 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 26 Jul 2023 16:56:39 +0200 Subject: [PATCH 028/105] Controller: Extend `ipl\Web\Compat\CompatController` --- library/Businessprocess/Web/Controller.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/library/Businessprocess/Web/Controller.php b/library/Businessprocess/Web/Controller.php index e9719e4..4f618b2 100644 --- a/library/Businessprocess/Web/Controller.php +++ b/library/Businessprocess/Web/Controller.php @@ -12,12 +12,12 @@ use Icinga\Module\Businessprocess\Web\Component\Controls; use Icinga\Module\Businessprocess\Web\Component\Content; use Icinga\Module\Businessprocess\Web\Component\Tabs; use Icinga\Module\Businessprocess\Web\Form\FormLoader; -use Icinga\Web\Controller as ModuleController; use Icinga\Web\Notification; use Icinga\Web\View; use ipl\Html\Html; +use ipl\Web\Compat\CompatController; -class Controller extends ModuleController +class Controller extends CompatController { /** @var View */ public $view; @@ -173,14 +173,6 @@ class Controller extends ModuleController return $this; } - protected function setTitle($title) - { - $args = func_get_args(); - array_shift($args); - $this->view->title = vsprintf($title, $args); - return $this; - } - protected function addTitle($title) { $args = func_get_args(); From c3d09fd6015a4041d191a62f4ce5f5011784a5e7 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 26 Jul 2023 17:04:50 +0200 Subject: [PATCH 029/105] Introduce `Icinga\Module\Businessprocess\Common\Sort` --- library/Businessprocess/Common/Sort.php | 154 ++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 library/Businessprocess/Common/Sort.php diff --git a/library/Businessprocess/Common/Sort.php b/library/Businessprocess/Common/Sort.php new file mode 100644 index 0000000..3b0f6d4 --- /dev/null +++ b/library/Businessprocess/Common/Sort.php @@ -0,0 +1,154 @@ +sort; + } + + /** + * Set the sort specification + * + * @param string $sort + * + * @return $this + * + * @throws InvalidArgumentException When sorting according to the specified specification is not possible + */ + public function setSort(string $sort): self + { + list($sortBy, $direction) = Str::symmetricSplit($sort, ' ', 2, 'asc'); + + switch ($sortBy) { + case 'manual': + if ($direction === 'asc') { + $this->sortFn = function (array &$nodes) { + $firstNode = reset($nodes); + if ($firstNode instanceof BpNode && $firstNode->getDisplay() > 0) { + $nodes = self::applyManualSorting($nodes); + } + + // Child nodes don't need to be ordered in this case, their implicit order is significant + }; + } else { + $this->sortFn = function (array &$nodes) { + $firstNode = reset($nodes); + if ($firstNode instanceof BpNode && $firstNode->getDisplay() > 0) { + uasort($nodes, function (BpNode $a, BpNode $b) { + return $b->getDisplay() <=> $a->getDisplay(); + }); + } else { + $nodes = array_reverse($nodes); + } + }; + } + + break; + case 'display_name': + if ($direction === 'asc') { + $this->sortFn = function (array &$nodes) { + uasort($nodes, function (Node $a, Node $b) { + return strnatcasecmp( + $a->getAlias() ?? $a->getName(), + $b->getAlias() ?? $b->getName() + ); + }); + }; + } else { + $this->sortFn = function (array &$nodes) { + uasort($nodes, function (Node $a, Node $b) { + return strnatcasecmp( + $b->getAlias() ?? $b->getName(), + $a->getAlias() ?? $a->getName() + ); + }); + }; + } + + break; + case 'state': + if ($direction === 'asc') { + $this->sortFn = function (array &$nodes) { + uasort($nodes, function (Node $a, Node $b) { + return $a->getSortingState() <=> $b->getSortingState(); + }); + }; + } else { + $this->sortFn = function (array &$nodes) { + uasort($nodes, function (Node $a, Node $b) { + return $b->getSortingState() <=> $a->getSortingState(); + }); + }; + } + + break; + default: + throw new InvalidArgumentException(sprintf( + "Can't sort by %s. It's only possible to sort by manual order, display_name or state", + $sortBy + )); + } + + $this->sort = $sort; + + return $this; + } + + /** + * Sort the given nodes as specified by {@see setSort()} + * + * If {@see setSort()} has not been called yet, the default sort specification is used + * + * @param array $nodes + * + * @return array + */ + public function sort(array $nodes): array + { + if (empty($nodes)) { + return $nodes; + } + + if ($this->sortFn !== null) { + call_user_func_array($this->sortFn, [&$nodes]); + } + + return $nodes; + } + + /** + * Apply manual sort order on the given process nodes + * + * @param array $bpNodes + * + * @return array + */ + public static function applyManualSorting(array $bpNodes): array + { + uasort($bpNodes, function (BpNode $a, BpNode $b) { + return $a->getDisplay() <=> $b->getDisplay(); + }); + + return $bpNodes; + } +} From 52c150c56b0dcbc5339cc1da3d92024d3278f21b Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 26 Jul 2023 17:15:26 +0200 Subject: [PATCH 030/105] Use the new `Sort` trait where applicable Moves the entire order processing to the renderers as that's where it's mostly relevant. The only cases where nodes are still ordered outside the rendering is where changes are applied based on user input, which happened based on what's been previously rendered. --- application/forms/AddNodeForm.php | 9 +++-- application/forms/EditNodeForm.php | 3 -- library/Businessprocess/BpConfig.php | 33 +------------------ library/Businessprocess/BpNode.php | 26 --------------- .../NodeApplyManualOrderAction.php | 8 ++++- .../Modification/NodeCopyAction.php | 13 ++++++-- .../Modification/NodeMoveAction.php | 25 +++++++++++--- library/Businessprocess/Renderer/Renderer.php | 31 +++++++++++++++++ .../Businessprocess/Renderer/TileRenderer.php | 8 ++--- .../Businessprocess/Renderer/TreeRenderer.php | 18 ++++++---- .../Businessprocess/Storage/LegacyStorage.php | 2 -- 11 files changed, 89 insertions(+), 87 deletions(-) diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php index 2f72c6b..bab26bb 100644 --- a/application/forms/AddNodeForm.php +++ b/application/forms/AddNodeForm.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess\Forms; use Exception; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\Common\EnumList; +use Icinga\Module\Businessprocess\Common\Sort; use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Node; @@ -14,6 +15,7 @@ use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidato class AddNodeForm extends BpConfigBaseForm { use EnumList; + use Sort; /** @var BpNode */ protected $parent; @@ -102,8 +104,8 @@ class AddNodeForm extends BpConfigBaseForm )); $display = 1; - if ($this->bp->getMetadata()->isManuallyOrdered() && !$this->bp->isEmpty()) { - $rootNodes = $this->bp->getRootNodes(); + if ($this->bp->getMetadata()->isManuallyOrdered() && ! $this->bp->isEmpty()) { + $rootNodes = self::applyManualSorting($this->bp->getRootNodes()); $display = end($rootNodes)->getDisplay() + 1; } $this->addElement('select', 'display', array( @@ -434,9 +436,6 @@ class AddNodeForm extends BpConfigBaseForm } } - if (! $this->bp->getMetadata()->isManuallyOrdered()) { - natcasesort($list); - } return $list; } diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php index 6b73044..aea064a 100644 --- a/application/forms/EditNodeForm.php +++ b/application/forms/EditNodeForm.php @@ -310,9 +310,6 @@ class EditNodeForm extends BpConfigBaseForm } } - if (! $this->bp->getMetadata()->isManuallyOrdered()) { - natcasesort($list); - } return $list; } diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index 43e8f5b..977186a 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -432,33 +432,12 @@ class BpConfig */ public function getRootNodes() { - if ($this->getMetadata()->isManuallyOrdered()) { - uasort($this->root_nodes, function (BpNode $a, BpNode $b) { - $a = $a->getDisplay(); - $b = $b->getDisplay(); - return $a > $b ? 1 : ($a < $b ? -1 : 0); - }); - } else { - ksort($this->root_nodes, SORT_NATURAL | SORT_FLAG_CASE); - } - return $this->root_nodes; } public function listRootNodes() { - $names = array_keys($this->root_nodes); - if ($this->getMetadata()->isManuallyOrdered()) { - uasort($names, function ($a, $b) { - $a = $this->root_nodes[$a]->getDisplay(); - $b = $this->root_nodes[$b]->getDisplay(); - return $a > $b ? 1 : ($a < $b ? -1 : 0); - }); - } else { - natcasesort($names); - } - - return $names; + return array_keys($this->root_nodes); } public function getNodes() @@ -826,16 +805,6 @@ class BpConfig $nodes[$name] = $name === $alias ? $name : sprintf('%s (%s)', $alias, $node); } - if ($this->getMetadata()->isManuallyOrdered()) { - uasort($nodes, function ($a, $b) { - $a = $this->nodes[$a]->getDisplay(); - $b = $this->nodes[$b]->getDisplay(); - return $a > $b ? 1 : ($a < $b ? -1 : 0); - }); - } else { - natcasesort($nodes); - } - return $nodes; } diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index c729c7c..ec248c2 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -135,7 +135,6 @@ class BpNode extends Node $this->children[$name] = $node; $this->childNames[] = $name; - $this->reorderChildren(); $node->addParent($this); return $this; } @@ -549,7 +548,6 @@ class BpNode extends Node { $this->childNames = $names; $this->children = null; - $this->reorderChildren(); return $this; } @@ -568,7 +566,6 @@ class BpNode extends Node { if ($this->children === null) { $this->children = []; - $this->reorderChildren(); foreach ($this->getChildNames() as $name) { $this->children[$name] = $this->getBpConfig()->getNode($name); $this->children[$name]->addParent($this); @@ -578,29 +575,6 @@ class BpNode extends Node return $this->children; } - /** - * Reorder this node's children, in case manual order is not applied - */ - protected function reorderChildren() - { - if ($this->getBpConfig()->getMetadata()->isManuallyOrdered()) { - return; - } - - $childNames = $this->getChildNames(); - natcasesort($childNames); - $this->childNames = array_values($childNames); - - if (! empty($this->children)) { - $children = []; - foreach ($this->childNames as $name) { - $children[$name] = $this->children[$name]; - } - - $this->children = $children; - } - } - /** * return BpNode[] */ diff --git a/library/Businessprocess/Modification/NodeApplyManualOrderAction.php b/library/Businessprocess/Modification/NodeApplyManualOrderAction.php index 9be77e9..4ad53e0 100644 --- a/library/Businessprocess/Modification/NodeApplyManualOrderAction.php +++ b/library/Businessprocess/Modification/NodeApplyManualOrderAction.php @@ -3,9 +3,12 @@ namespace Icinga\Module\Businessprocess\Modification; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\Common\Sort; class NodeApplyManualOrderAction extends NodeAction { + use Sort; + public function appliesTo(BpConfig $config) { return $config->getMetadata()->get('ManualOrder') !== 'yes'; @@ -20,7 +23,10 @@ class NodeApplyManualOrderAction extends NodeAction } if ($node->hasChildren()) { - $node->setChildNames($node->getChildNames()); + $node->setChildNames(array_keys( + $this->setSort('display_name asc') + ->sort($node->getChildren()) + )); } } diff --git a/library/Businessprocess/Modification/NodeCopyAction.php b/library/Businessprocess/Modification/NodeCopyAction.php index 609d704..80d781b 100644 --- a/library/Businessprocess/Modification/NodeCopyAction.php +++ b/library/Businessprocess/Modification/NodeCopyAction.php @@ -3,9 +3,12 @@ namespace Icinga\Module\Businessprocess\Modification; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\Common\Sort; class NodeCopyAction extends NodeAction { + use Sort; + /** * @param BpConfig $config * @return bool @@ -31,9 +34,15 @@ class NodeCopyAction extends NodeAction public function applyTo(BpConfig $config) { $name = $this->getNodeName(); - $rootNodes = $config->getRootNodes(); + + $display = 1; + if ($config->getMetadata()->isManuallyOrdered()) { + $rootNodes = self::applyManualSorting($config->getRootNodes()); + $display = end($rootNodes)->getDisplay() + 1; + } + $config->addRootNode($name) ->getBpNode($name) - ->setDisplay(end($rootNodes)->getDisplay() + 1); + ->setDisplay($display); } } diff --git a/library/Businessprocess/Modification/NodeMoveAction.php b/library/Businessprocess/Modification/NodeMoveAction.php index 5754717..4c4305d 100644 --- a/library/Businessprocess/Modification/NodeMoveAction.php +++ b/library/Businessprocess/Modification/NodeMoveAction.php @@ -4,9 +4,12 @@ namespace Icinga\Module\Businessprocess\Modification; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; +use Icinga\Module\Businessprocess\Common\Sort; class NodeMoveAction extends NodeAction { + use Sort; + /** * @var string */ @@ -87,16 +90,28 @@ class NodeMoveAction extends NodeAction $nodes = $parent->getChildNames(); if (! isset($nodes[$this->from]) || $nodes[$this->from] !== $name) { - $this->error('Node "%s" not found at position %d', $name, $this->from); + $reversedNodes = array_reverse($nodes); // The user may have reversed the sort direction + if (! isset($reversedNodes[$this->from]) || $reversedNodes[$this->from] !== $name) { + $this->error('Node "%s" not found at position %d', $name, $this->from); + } else { + $this->from = array_search($reversedNodes[$this->from], $nodes, true); + $this->to = array_search($reversedNodes[$this->to], $nodes, true); + } } } else { if (! $config->hasRootNode($name)) { $this->error('Toplevel process "%s" not found', $name); } - $nodes = $config->listRootNodes(); + $nodes = array_keys(self::applyManualSorting($config->getRootNodes())); if (! isset($nodes[$this->from]) || $nodes[$this->from] !== $name) { - $this->error('Toplevel process "%s" not found at position %d', $name, $this->from); + $reversedNodes = array_reverse($nodes); // The user may have reversed the sort direction + if (! isset($reversedNodes[$this->from]) || $reversedNodes[$this->from] !== $name) { + $this->error('Toplevel process "%s" not found at position %d', $name, $this->from); + } else { + $this->from = array_search($reversedNodes[$this->from], $nodes, true); + $this->to = array_search($reversedNodes[$this->to], $nodes, true); + } } } @@ -144,7 +159,7 @@ class NodeMoveAction extends NodeAction if ($this->parent !== null) { $nodes = $config->getBpNode($this->parent)->getChildren(); } else { - $nodes = $config->getRootNodes(); + $nodes = self::applyManualSorting($config->getRootNodes()); } $node = $nodes[$name]; @@ -162,7 +177,7 @@ class NodeMoveAction extends NodeAction if ($this->newParent !== null) { $newNodes = $config->getBpNode($this->newParent)->getChildren(); } else { - $newNodes = $config->getRootNodes(); + $newNodes = self::applyManualSorting($config->getRootNodes()); } $newNodes = array_merge( diff --git a/library/Businessprocess/Renderer/Renderer.php b/library/Businessprocess/Renderer/Renderer.php index 94a9667..6e68da4 100644 --- a/library/Businessprocess/Renderer/Renderer.php +++ b/library/Businessprocess/Renderer/Renderer.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess\Renderer; use Icinga\Exception\ProgrammingError; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\Common\Sort; use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\MonitoredNode; use Icinga\Module\Businessprocess\Node; @@ -12,10 +13,13 @@ use Icinga\Module\Businessprocess\Web\Url; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Html\HtmlDocument; +use ipl\Stdlib\Str; use ipl\Web\Widget\StateBadge; abstract class Renderer extends HtmlDocument { + use Sort; + /** @var BpConfig */ protected $config; @@ -120,6 +124,33 @@ abstract class Renderer extends HtmlDocument } } + /** + * Get the default sort specification + * + * @return string + */ + public function getDefaultSort(): string + { + if ($this->config->getMetadata()->isManuallyOrdered()) { + return 'manual asc'; + } + + return 'display_name asc'; + } + + /** + * Get whether a custom sort order is applied + * + * @return bool + */ + public function appliesCustomSorting(): bool + { + list($sortBy, $_) = Str::symmetricSplit($this->getSort(), ' ', 2); + list($defaultSortBy, $_) = Str::symmetricSplit($this->getDefaultSort(), ' ', 2); + + return $sortBy !== $defaultSortBy; + } + /** * @return int */ diff --git a/library/Businessprocess/Renderer/TileRenderer.php b/library/Businessprocess/Renderer/TileRenderer.php index df53989..21c2f6a 100644 --- a/library/Businessprocess/Renderer/TileRenderer.php +++ b/library/Businessprocess/Renderer/TileRenderer.php @@ -17,7 +17,9 @@ class TileRenderer extends Renderer [ 'class' => ['sortable', 'tiles', $this->howMany()], 'data-base-target' => '_self', - 'data-sortable-disabled' => $this->isLocked() ? 'true' : 'false', + 'data-sortable-disabled' => $this->isLocked() || $this->appliesCustomSorting() + ? 'true' + : 'false', 'data-sortable-data-id-attr' => 'id', 'data-sortable-direction' => 'horizontal', // Otherwise movement is buggy on small lists 'data-csrf-token' => CsrfToken::generate() @@ -43,10 +45,8 @@ class TileRenderer extends Renderer ->getAbsoluteUrl()); } - $nodes = $this->getChildNodes(); - $path = $this->getCurrentPath(); - foreach ($nodes as $name => $node) { + foreach ($this->sort($this->getChildNodes()) as $name => $node) { $this->add(new NodeTile($this, $node, $path)); } diff --git a/library/Businessprocess/Renderer/TreeRenderer.php b/library/Businessprocess/Renderer/TreeRenderer.php index c5733af..c9dd218 100644 --- a/library/Businessprocess/Renderer/TreeRenderer.php +++ b/library/Businessprocess/Renderer/TreeRenderer.php @@ -29,7 +29,9 @@ class TreeRenderer extends Renderer [ 'id' => $htmlId, 'class' => ['bp', 'sortable', $this->wantsRootNodes() ? '' : 'process'], - 'data-sortable-disabled' => $this->isLocked() ? 'true' : 'false', + 'data-sortable-disabled' => $this->isLocked() || $this->appliesCustomSorting() + ? 'true' + : 'false', 'data-sortable-data-id-attr' => 'id', 'data-sortable-direction' => 'vertical', 'data-sortable-group' => json_encode([ @@ -69,18 +71,18 @@ class TreeRenderer extends Renderer /** * @param BpConfig $bp - * @return string + * @return array */ public function renderBp(BpConfig $bp) { - $html = array(); + $html = []; if ($this->wantsRootNodes()) { - $nodes = $bp->getChildren(); + $nodes = $bp->getRootNodes(); } else { $nodes = $this->parent->getChildren(); } - foreach ($nodes as $name => $node) { + foreach ($this->sort($nodes) as $name => $node) { if ($node instanceof BpNode) { $html[] = $this->renderNode($bp, $node); } else { @@ -238,7 +240,9 @@ class TreeRenderer extends Renderer $ul = Html::tag('ul', [ 'class' => ['bp', 'sortable'], - 'data-sortable-disabled' => ($this->isLocked() || $differentConfig) ? 'true' : 'false', + 'data-sortable-disabled' => ($this->isLocked() || $differentConfig || $this->appliesCustomSorting()) + ? 'true' + : 'false', 'data-sortable-invert-swap' => 'true', 'data-sortable-data-id-attr' => 'id', 'data-sortable-draggable' => '.movable', @@ -259,7 +263,7 @@ class TreeRenderer extends Renderer ]); $path[] = $differentConfig ? $node->getIdentifier() : $node->getName(); - foreach ($node->getChildren() as $name => $child) { + foreach ($this->sort($node->getChildren()) as $name => $child) { if ($child instanceof BpNode) { $ul->add($this->renderNode($bp, $child, $path)); } else { diff --git a/library/Businessprocess/Storage/LegacyStorage.php b/library/Businessprocess/Storage/LegacyStorage.php index 6582ebd..f6cf1e5 100644 --- a/library/Businessprocess/Storage/LegacyStorage.php +++ b/library/Businessprocess/Storage/LegacyStorage.php @@ -73,7 +73,6 @@ class LegacyStorage extends Storage $files[$name] = $meta->getExtendedTitle(); } - natcasesort($files); return $files; } @@ -93,7 +92,6 @@ class LegacyStorage extends Storage $files[$name] = $name; } - natcasesort($files); return $files; } From 2acf6118123a98289480696e707df48dad45b2a9 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 26 Jul 2023 17:23:40 +0200 Subject: [PATCH 031/105] process/show: Allow to adjust the order of nodes Nodes can be ordered as usually by display name, but now also in descending order. They can now also be ordered by state. This also applies to manually ordered processes. Though, changes to the manual order can only happen if the default order is active. If that's not the case, a note is shown and a way to reset the sort order. --- application/controllers/ProcessController.php | 76 ++++++++++++++++++- public/css/module.less | 8 +- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 915aa6b..75a1b86 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -26,10 +26,13 @@ use Icinga\Web\Notification; use Icinga\Web\Url; use Icinga\Web\Widget\Tabextension\DashboardAction; use Icinga\Web\Widget\Tabextension\OutputFormat; +use ipl\Html\Form; use ipl\Html\Html; use ipl\Html\HtmlElement; use ipl\Html\HtmlString; use ipl\Html\TemplateString; +use ipl\Html\Text; +use ipl\Web\Control\SortControl; use ipl\Web\Widget\Link; class ProcessController extends Controller @@ -117,7 +120,7 @@ class ProcessController extends Controller $this->tabs()->extend(new OutputFormat()); - $this->content()->add($this->showHints($bp)); + $this->content()->add($this->showHints($bp, $renderer)); $this->content()->add($this->showWarnings($bp)); $this->content()->add($this->showErrors($bp)); $this->content()->add($renderer); @@ -125,6 +128,50 @@ class ProcessController extends Controller $this->setDynamicAutorefresh(); } + /** + * Create a sort control and apply its sort specification to the given renderer + * + * @param Renderer $renderer + * @param BpConfig $config + * + * @return SortControl + */ + protected function createBpSortControl(Renderer $renderer, BpConfig $config): SortControl + { + $defaultSort = $this->session()->get('sort.default', $renderer->getDefaultSort()); + $options = [ + 'display_name asc' => $this->translate('Name'), + 'state desc' => $this->translate('State') + ]; + if ($config->getMetadata()->isManuallyOrdered()) { + $options['manual asc'] = $this->translate('Manual'); + } elseif ($defaultSort === 'manual desc') { + $defaultSort = $renderer->getDefaultSort(); + } + + $sortControl = SortControl::create($options) + ->setDefault($defaultSort) + ->setMethod('POST') + ->setAttribute('name', 'bp-sort-control') + ->on(Form::ON_SUCCESS, function (SortControl $sortControl) use ($renderer) { + $sort = $sortControl->getSort(); + if ($sort === $renderer->getDefaultSort()) { + $this->session()->delete('sort.default'); + $url = Url::fromRequest()->without($sortControl->getSortParam()); + } else { + $this->session()->set('sort.default', $sort); + $url = Url::fromRequest()->with($sortControl->getSortParam(), $sort); + } + + $this->redirectNow($url); + })->handleRequest($this->getServerRequest()); + + $renderer->setSort($sortControl->getSort()); + $this->params->shift($sortControl->getSortParam()); + + return $sortControl; + } + protected function prepareControls($bp, $renderer) { $controls = $this->controls(); @@ -153,6 +200,8 @@ class ProcessController extends Controller new RenderedProcessActionBar($bp, $renderer, $this->Auth(), $this->url()) ); } + + $controls->addHtml($this->createBpSortControl($renderer, $bp)); } protected function getNode(BpConfig $bp) @@ -269,6 +318,13 @@ class ProcessController extends Controller $successUrl->getParams()->remove('node'); } + if ($this->session()->get('sort.default')) { + // If there's a default sort specification in the session, it can only be `display_name desc`, + // as otherwise the user wouldn't be able to trigger this action. So it's safe to just define + // descending manual order now. + $successUrl->getParams()->add(SortControl::DEFAULT_SORT_PARAM, 'manual desc'); + } + $form = $this->loadForm('MoveNode') ->setSuccessUrl($successUrl) ->setProcess($bp) @@ -328,7 +384,7 @@ class ProcessController extends Controller } } - protected function showHints(BpConfig $bp) + protected function showHints(BpConfig $bp, Renderer $renderer) { $ul = Html::tag('ul', ['class' => 'error']); $this->prepareMissingNodeLinks($ul); @@ -369,6 +425,20 @@ class ProcessController extends Controller $ul->add($li); } + if (! $renderer->isLocked() && $renderer->appliesCustomSorting()) { + $ul->addHtml(Html::tag('li', null, [ + Text::create($this->translate('Drag&Drop disabled. Custom sort order applied.')), + (new Form()) + ->setAttribute('class', 'inline') + ->addElement('submitButton', SortControl::DEFAULT_SORT_PARAM, [ + 'label' => $this->translate('Reset to default'), + 'value' => $renderer->getDefaultSort(), + 'class' => 'link-button' + ]) + ->addElement('hidden', 'uid', ['value' => 'bp-sort-control']) + ])->setSeparator(' ')); + } + if (! $ul->isEmpty()) { return $ul; } else { @@ -654,7 +724,7 @@ class ProcessController extends Controller if (isset($node['since'])) { $data[] = DateFormatter::formatDateTime($node['since']); } - + if (isset($node['in_downtime'])) { $data[] = $node['in_downtime']; } diff --git a/public/css/module.less b/public/css/module.less index deb9e3a..a05299a 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -7,6 +7,7 @@ a:focus { } .action-bar { + float: left; display: flex; align-items: center; font-size: 1.3em; @@ -76,6 +77,10 @@ a:focus { } } +.controls .sort-control { + float: right; +} + form a { color: @icinga-blue; } @@ -742,7 +747,8 @@ ul.error, ul.warning { padding: 0.3em 0.8em; } - li a { + li a, + li .link-button { color: inherit; text-decoration: underline; From 3fe17336dc4bc790ca60f5af4e47918fb7f58361 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 14:40:46 +0200 Subject: [PATCH 032/105] Escape semicolons in node names fixes #312 --- application/forms/AddNodeForm.php | 6 +- application/forms/EditNodeForm.php | 7 +- library/Businessprocess/BpConfig.php | 75 ++++++++++++++++--- library/Businessprocess/BpNode.php | 3 +- library/Businessprocess/Common/EnumList.php | 15 ++-- library/Businessprocess/HostNode.php | 2 +- library/Businessprocess/ImportedNode.php | 8 +- .../Modification/NodeAddChildrenAction.php | 11 ++- .../ProvidedHook/Icingadb/HostActions.php | 3 +- .../ProvidedHook/Icingadb/ServiceActions.php | 5 +- .../ProvidedHook/Monitoring/HostActions.php | 3 +- .../Monitoring/ServiceActions.php | 5 +- library/Businessprocess/ServiceNode.php | 2 +- .../Businessprocess/State/IcingaDbState.php | 4 +- .../Businessprocess/State/MonitoringState.php | 12 +-- .../Storage/LegacyConfigParser.php | 16 ++-- .../processes/also-with-semicolons.conf | 8 ++ .../processes/with-semicolons.conf | 14 ++++ .../library/Businessprocess/BpConfigTest.php | 49 ++++++++++++ .../Storage/LegacyStorageTest.php | 37 +++++++++ 20 files changed, 223 insertions(+), 62 deletions(-) create mode 100644 test/config/modules/businessprocess/processes/also-with-semicolons.conf create mode 100644 test/config/modules/businessprocess/processes/with-semicolons.conf create mode 100644 test/php/library/Businessprocess/BpConfigTest.php diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php index bab26bb..76880b6 100644 --- a/application/forms/AddNodeForm.php +++ b/application/forms/AddNodeForm.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Businessprocess\Forms; use Exception; +use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\Common\EnumList; use Icinga\Module\Businessprocess\Common\Sort; @@ -498,10 +499,13 @@ class AddNodeForm extends BpConfigBaseForm case 'new-process': $properties = $this->getValues(); unset($properties['name']); + if (! $properties['alias']) { + unset($properties['alias']); + } if ($this->hasParentNode()) { $properties['parentName'] = $this->parent->getName(); } - $changes->createNode($this->getValue('name'), $properties); + $changes->createNode(BpConfig::escapeName($this->getValue('name')), $properties); break; } diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php index aea064a..448f24f 100644 --- a/application/forms/EditNodeForm.php +++ b/application/forms/EditNodeForm.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Businessprocess\Forms; +use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\Common\EnumList; use Icinga\Module\Businessprocess\Modification\ProcessChanges; @@ -29,9 +30,9 @@ class EditNodeForm extends BpConfigBaseForm public function setup() { - $this->host = substr($this->getNode()->getName(), 0, strpos($this->getNode()->getName(), ';')); - if ($this->isService()) { - $this->service = substr($this->getNode()->getName(), strpos($this->getNode()->getName(), ';') + 1); + [$this->host, $suffix] = BpConfig::splitNodeName($this->getNode()->getName()); + if ($suffix !== 'Hoststatus') { + $this->service = $suffix; } $view = $this->getView(); diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index 977186a..e99f81c 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -471,7 +471,7 @@ class BpConfig ) ); $node->setBpConfig($this); - $this->nodes[$host . ';' . $service] = $node; + $this->nodes[$node->getName()] = $node; $this->hosts[$host] = true; return $node; } @@ -480,7 +480,7 @@ class BpConfig { $node = new HostNode((object) array('hostname' => $host)); $node->setBpConfig($this); - $this->nodes[$host . ';Hoststatus'] = $node; + $this->nodes[$node->getName()] = $node; $this->hosts[$host] = true; return $node; } @@ -642,15 +642,13 @@ class BpConfig // Fallback: if it is a service, create an empty one: $this->warn(sprintf('The node "%s" doesn\'t exist', $name)); - $pos = strpos($name, ';'); - if ($pos !== false) { - $host = substr($name, 0, $pos); - $service = substr($name, $pos + 1); - // TODO: deactivated, this scares me, test it - if ($service === 'Hoststatus') { - return $this->createHost($host); + + [$name, $suffix] = self::splitNodeName($name); + if ($suffix !== null) { + if ($suffix === 'Hoststatus') { + return $this->createHost($name); } else { - return $this->createService($host, $service); + return $this->createService($name, $suffix); } } @@ -1015,4 +1013,61 @@ class BpConfig return $data; } + + /** + * Escape the given node name + * + * @param string $name + * + * @return string + */ + public static function escapeName(string $name): string + { + return preg_replace('/((?name = $object->name; + $this->name = BpConfig::escapeName($object->name); + $this->alias = BpConfig::unescapeName($object->name); $this->operator = $object->operator; $this->childNames = $object->child_names; } diff --git a/library/Businessprocess/Common/EnumList.php b/library/Businessprocess/Common/EnumList.php index 94747b2..3419505 100644 --- a/library/Businessprocess/Common/EnumList.php +++ b/library/Businessprocess/Common/EnumList.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Businessprocess\Common; use Icinga\Application\Modules\Module; use Icinga\Data\Filter\Filter; +use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\IcingaDbObject; use Icinga\Module\Businessprocess\MonitoringRestrictions; use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; @@ -51,9 +52,8 @@ trait EnumList // fetchPairs doesn't seem to work when using the same column with // different aliases twice $res = array(); - $suffix = ';Hoststatus'; foreach ($names as $name) { - $res[$name . $suffix] = $name; + $res[BpConfig::joinNodeName($name, 'Hoststatus')] = $name; } return $res; @@ -76,7 +76,7 @@ trait EnumList $services = array(); foreach ($names as $name) { - $services[$host . ';' . $name] = $name; + $services[BpConfig::joinNodeName($host, $name)] = $name; } return $services; @@ -100,9 +100,8 @@ trait EnumList // fetchPairs doesn't seem to work when using the same column with // different aliases twice $res = array(); - $suffix = ';Hoststatus'; foreach ($names as $name) { - $res[$name . $suffix] = $name; + $res[BpConfig::joinNodeName($name, 'Hoststatus')] = $name; } return $res; @@ -115,7 +114,8 @@ trait EnumList if ($this->useIcingaDbBackend()) { $objects = (new IcingaDbObject())->fetchServices($filter); foreach ($objects as $object) { - $services[$object->host->name . ';' . $object->name] = $object->host->name . ':' . $object->name; + $services[BpConfig::joinNodeName($object->host->name, $object->name)] + = $object->host->name . ':' . $object->name; } } else { $objects = $this->backend @@ -127,7 +127,8 @@ trait EnumList ->getQuery() ->fetchAll(); foreach ($objects as $object) { - $services[$object->host . ';' . $object->service] = $object->host . ':' . $object->service; + $services[BpConfig::joinNodeName($object->host, $object->service)] + = $object->host . ':' . $object->service; } } diff --git a/library/Businessprocess/HostNode.php b/library/Businessprocess/HostNode.php index b66f66f..ca3f796 100644 --- a/library/Businessprocess/HostNode.php +++ b/library/Businessprocess/HostNode.php @@ -35,7 +35,7 @@ class HostNode extends MonitoredNode public function __construct($object) { - $this->name = $object->hostname . ';Hoststatus'; + $this->name = BpConfig::joinNodeName($object->hostname, 'Hoststatus'); $this->hostname = $object->hostname; if (isset($object->state)) { $this->setState($object->state); diff --git a/library/Businessprocess/ImportedNode.php b/library/Businessprocess/ImportedNode.php index 3f0b460..e20b0a7 100644 --- a/library/Businessprocess/ImportedNode.php +++ b/library/Businessprocess/ImportedNode.php @@ -28,7 +28,7 @@ class ImportedNode extends BpNode { $this->parentBp = $parentBp; $this->configName = $object->configName; - $this->nodeName = $object->node; + $this->nodeName = BpConfig::escapeName($object->node); parent::__construct((object) [ 'name' => '@' . $this->configName . ':' . $this->nodeName, @@ -69,11 +69,7 @@ class ImportedNode extends BpNode public function getAlias() { - if ($this->alias === null) { - $this->alias = $this->importedNode()->getAlias(); - } - - return $this->alias; + return $this->importedNode()->getAlias(); } public function getOperator() diff --git a/library/Businessprocess/Modification/NodeAddChildrenAction.php b/library/Businessprocess/Modification/NodeAddChildrenAction.php index 5d5ab29..162c380 100644 --- a/library/Businessprocess/Modification/NodeAddChildrenAction.php +++ b/library/Businessprocess/Modification/NodeAddChildrenAction.php @@ -33,13 +33,12 @@ class NodeAddChildrenAction extends NodeAction foreach ($this->children as $name) { if (! $config->hasNode($name) || $config->getNode($name)->getBpConfig()->getName() !== $config->getName()) { - if (strpos($name, ';') !== false) { - list($host, $service) = preg_split('/;/', $name, 2); - - if ($service === 'Hoststatus') { - $config->createHost($host); + [$prefix, $suffix] = BpConfig::splitNodeName($name); + if ($suffix !== null) { + if ($suffix === 'Hoststatus') { + $config->createHost($prefix); } else { - $config->createService($host, $service); + $config->createService($prefix, $suffix); } } elseif ($name[0] === '@' && strpos($name, ':') !== false) { list($configName, $nodeName) = preg_split('~:\s*~', substr($name, 1), 2); diff --git a/library/Businessprocess/ProvidedHook/Icingadb/HostActions.php b/library/Businessprocess/ProvidedHook/Icingadb/HostActions.php index 27f4551..ac18959 100644 --- a/library/Businessprocess/ProvidedHook/Icingadb/HostActions.php +++ b/library/Businessprocess/ProvidedHook/Icingadb/HostActions.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Businessprocess\ProvidedHook\Icingadb; +use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Icingadb\Hook\HostActionsHook; use Icinga\Module\Icingadb\Model\Host; use ipl\Web\Widget\Link; @@ -15,7 +16,7 @@ class HostActions extends HostActionsHook new Link( $label, 'businessprocess/node/impact?name=' - . rawurlencode($host->name . ';Hoststatus') + . rawurlencode(BpConfig::joinNodeName($host->name, 'Hoststatus')) ) ); } diff --git a/library/Businessprocess/ProvidedHook/Icingadb/ServiceActions.php b/library/Businessprocess/ProvidedHook/Icingadb/ServiceActions.php index 24e6829..d416d90 100644 --- a/library/Businessprocess/ProvidedHook/Icingadb/ServiceActions.php +++ b/library/Businessprocess/ProvidedHook/Icingadb/ServiceActions.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Businessprocess\ProvidedHook\Icingadb; +use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Icingadb\Hook\ServiceActionsHook; use Icinga\Module\Icingadb\Model\Service; use ipl\Web\Widget\Link; @@ -16,9 +17,7 @@ class ServiceActions extends ServiceActionsHook $label, sprintf( 'businessprocess/node/impact?name=%s', - rawurlencode( - sprintf('%s;%s', $service->host->name, $service->name) - ) + rawurlencode(BpConfig::joinNodeName($service->host->name, $service->name)) ) ) ); diff --git a/library/Businessprocess/ProvidedHook/Monitoring/HostActions.php b/library/Businessprocess/ProvidedHook/Monitoring/HostActions.php index 57ce8f5..e2b9c59 100644 --- a/library/Businessprocess/ProvidedHook/Monitoring/HostActions.php +++ b/library/Businessprocess/ProvidedHook/Monitoring/HostActions.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Businessprocess\ProvidedHook\Monitoring; +use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Monitoring\Hook\HostActionsHook; use Icinga\Module\Monitoring\Object\Host; @@ -12,7 +13,7 @@ class HostActions extends HostActionsHook $label = mt('businessprocess', 'Business Impact'); return array( $label => 'businessprocess/node/impact?name=' - . rawurlencode($host->getName() . ';Hoststatus') + . rawurlencode(BpConfig::joinNodeName($host->getName(), 'Hoststatus')) ); } } diff --git a/library/Businessprocess/ProvidedHook/Monitoring/ServiceActions.php b/library/Businessprocess/ProvidedHook/Monitoring/ServiceActions.php index 69a93ae..ce9fabf 100644 --- a/library/Businessprocess/ProvidedHook/Monitoring/ServiceActions.php +++ b/library/Businessprocess/ProvidedHook/Monitoring/ServiceActions.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Businessprocess\ProvidedHook\Monitoring; use Exception; use Icinga\Application\Config; +use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Monitoring\Hook\ServiceActionsHook; use Icinga\Module\Monitoring\Object\Service; use Icinga\Web\Url; @@ -16,9 +17,7 @@ class ServiceActions extends ServiceActionsHook return array( $label => sprintf( 'businessprocess/node/impact?name=%s', - rawurlencode( - sprintf('%s;%s', $service->getHost()->getName(), $service->getName()) - ) + rawurlencode(BpConfig::joinNodeName($service->getHost()->getName(), $service->getName())) ) ); } diff --git a/library/Businessprocess/ServiceNode.php b/library/Businessprocess/ServiceNode.php index 53cef21..09df484 100644 --- a/library/Businessprocess/ServiceNode.php +++ b/library/Businessprocess/ServiceNode.php @@ -19,7 +19,7 @@ class ServiceNode extends MonitoredNode public function __construct($object) { - $this->name = $object->hostname . ';' . $object->service; + $this->name = BpConfig::joinNodeName($object->hostname, $object->service); $this->hostname = $object->hostname; $this->service = $object->service; if (isset($object->state)) { diff --git a/library/Businessprocess/State/IcingaDbState.php b/library/Businessprocess/State/IcingaDbState.php index 0eb0927..f145395 100644 --- a/library/Businessprocess/State/IcingaDbState.php +++ b/library/Businessprocess/State/IcingaDbState.php @@ -99,9 +99,9 @@ class IcingaDbState protected function handleDbRow($row, BpConfig $config, $objectName) { if ($objectName === 'service') { - $key = $row->host->name . ';' . $row->name; + $key = BpConfig::joinNodeName($row->host->name, $row->name); } else { - $key = $row->name . ';Hoststatus'; + $key = BpConfig::joinNodeName($row->name, 'Hoststatus'); } // We fetch more states than we need, so skip unknown ones diff --git a/library/Businessprocess/State/MonitoringState.php b/library/Businessprocess/State/MonitoringState.php index d317528..b6a2391 100644 --- a/library/Businessprocess/State/MonitoringState.php +++ b/library/Businessprocess/State/MonitoringState.php @@ -115,12 +115,12 @@ class MonitoringState protected function handleDbRow($row, BpConfig $config) { - $key = $row->hostname; - if (property_exists($row, 'service')) { - $key .= ';' . $row->service; - } else { - $key .= ';Hoststatus'; - } + $key = BpConfig::joinNodeName( + $row->hostname, + property_exists($row, 'service') + ? $row->service + : 'Hoststatus' + ); // We fetch more states than we need, so skip unknown ones if (! $config->hasNode($key)) { diff --git a/library/Businessprocess/Storage/LegacyConfigParser.php b/library/Businessprocess/Storage/LegacyConfigParser.php index 68cc1be..83c9240 100644 --- a/library/Businessprocess/Storage/LegacyConfigParser.php +++ b/library/Businessprocess/Storage/LegacyConfigParser.php @@ -230,7 +230,7 @@ class LegacyConfigParser */ protected function parseDisplay(&$line, BpConfig $bp) { - list($display, $name, $desc) = preg_split('~\s*;\s*~', substr($line, 8), 3); + list($display, $name, $desc) = preg_split('~\s*(?getBpNode($name)->setAlias($desc)->setDisplay($display); if ($display > 0) { $bp->addRootNode($name); @@ -239,7 +239,7 @@ class LegacyConfigParser protected function parseInfoUrl(&$line, BpConfig $bp) { - list($name, $url) = preg_split('~\s*;\s*~', substr($line, 9), 2); + list($name, $url) = preg_split('~\s*(?getBpNode($name)->setInfoUrl($url); } @@ -324,10 +324,6 @@ class LegacyConfigParser list($name, $value) = preg_split('~\s*=\s*~', $line, 2); - if (strpos($name, ';') !== false) { - $this->parseError('No semicolon allowed in varname'); - } - $op = '&'; if (preg_match_all('~(?hasNode($val)) { $node->addChild($bp->getNode($val)); } else { - list($host, $service) = preg_split('~;~', $val, 2); + list($host, $service) = preg_split('~(?addChild($bp->createHost($host)); + $node->addChild($bp->createHost(str_replace('\\;', ';', $host))); } else { - $node->addChild($bp->createService($host, $service)); + $node->addChild($bp->createService(str_replace('\\;', ';', $host), $service)); } } } elseif ($val[0] === '@') { diff --git a/test/config/modules/businessprocess/processes/also-with-semicolons.conf b/test/config/modules/businessprocess/processes/also-with-semicolons.conf new file mode 100644 index 0000000..a023aaf --- /dev/null +++ b/test/config/modules/businessprocess/processes/also-with-semicolons.conf @@ -0,0 +1,8 @@ +############################################ +# +# Title: Also With Semicolons +# +############################################ + +b\;ar = +display 1;b\;ar;Bar diff --git a/test/config/modules/businessprocess/processes/with-semicolons.conf b/test/config/modules/businessprocess/processes/with-semicolons.conf new file mode 100644 index 0000000..310d473 --- /dev/null +++ b/test/config/modules/businessprocess/processes/with-semicolons.conf @@ -0,0 +1,14 @@ +############################################ +# +# Title: With Semicolons +# +############################################ + +hostsAnd = host\;1;Hoststatus & host2;Hoststatus +servicesOr = host\;1;pi;ng | host2;ping | host3;ping +singleHost = host\;1;Hoststatus & to\;p & @also-with-semicolons:b\;ar +to\;p = hostsAnd & servicesOr & singleHost +display 1;to\;p;Top Node +info_url to\;p;https://top.example.com/ +no\;alias = +display 1;no\;alias;no;alias diff --git a/test/php/library/Businessprocess/BpConfigTest.php b/test/php/library/Businessprocess/BpConfigTest.php new file mode 100644 index 0000000..f42c58c --- /dev/null +++ b/test/php/library/Businessprocess/BpConfigTest.php @@ -0,0 +1,49 @@ +assertSame( + 'foo;bar', + BpConfig::joinNodeName('foo', 'bar') + ); + $this->assertSame( + 'foo\;bar', + BpConfig::joinNodeName('foo;bar') + ); + $this->assertSame( + 'foo\;bar;baroof', + BpConfig::joinNodeName('foo;bar', 'baroof') + ); + $this->assertSame( + 'foo\;bar;bar;oof', + BpConfig::joinNodeName('foo;bar', 'bar;oof') + ); + } + + public function testSplitNodeName() + { + $this->assertSame( + ['foo', 'bar'], + BpConfig::splitNodeName('foo;bar') + ); + $this->assertSame( + ['foo;bar', null], + BpConfig::splitNodeName('foo\;bar') + ); + $this->assertSame( + ['foo;bar', 'baroof'], + BpConfig::splitNodeName('foo\;bar;baroof') + ); + $this->assertSame( + ['foo;bar', 'bar;oof'], + BpConfig::splitNodeName('foo\;bar;bar;oof') + ); + } +} diff --git a/test/php/library/Businessprocess/Storage/LegacyStorageTest.php b/test/php/library/Businessprocess/Storage/LegacyStorageTest.php index b3be257..75bfcd5 100644 --- a/test/php/library/Businessprocess/Storage/LegacyStorageTest.php +++ b/test/php/library/Businessprocess/Storage/LegacyStorageTest.php @@ -2,6 +2,8 @@ namespace Tests\Icinga\Module\Businessprocess\Storage; +use Icinga\Module\Businessprocess\BpNode; +use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\Test\BaseTestCase; use Icinga\Module\Businessprocess\Storage\LegacyStorage; @@ -31,10 +33,12 @@ class LegacyStorageTest extends BaseTestCase $keys = array_keys($this->makeInstance()->listProcesses()); $this->assertEquals( array( + 'also-with-semicolons', 'broken_wrong-operator', 'combined', 'simple_with-header', 'simple_without-header', + 'with-semicolons' ), $keys ); @@ -45,10 +49,12 @@ class LegacyStorageTest extends BaseTestCase $keys = array_values($this->makeInstance()->listProcesses()); $this->assertEquals( array( + 'Also With Semicolons (also-with-semicolons)', 'broken_wrong-operator', 'combined', 'Simple with header (simple_with-header)', 'simple_without-header', + 'With Semicolons (with-semicolons)' ), $keys ); @@ -135,4 +141,35 @@ class LegacyStorageTest extends BaseTestCase $this->makeInstance()->loadProcess('combined') ); } + + public function testConfigsWithNodesThatHaveSemicolonsInTheirNameCanBeParsed() + { + $bp = $this->makeInstance()->loadProcess('with-semicolons'); + + $this->assertInstanceOf($this->processClass, $bp); + + $this->assertTrue($bp->hasNode('to\\;p')); + $this->assertSame( + 'https://top.example.com/', + $bp->getNode('to\\;p')->getInfoUrl() + ); + + $this->assertTrue($bp->hasNode('host\;1;Hoststatus')); + $this->assertSame('host;1', $bp->getNode('host\;1;Hoststatus')->getHostname()); + + $this->assertTrue($bp->hasNode('host\;1;pi;ng')); + $this->assertSame('host;1', $bp->getNode('host\;1;pi;ng')->getHostname()); + $this->assertSame('pi;ng', $bp->getNode('host\;1;pi;ng')->getServiceDescription()); + + $this->assertTrue($bp->hasNode('singleHost')); + $this->assertTrue($bp->getNode('singleHost')->hasChild('to\\;p')); + $this->assertInstanceOf(BpNode::class, $bp->getNode('to\\;p')); + + $this->assertInstanceOf(BpNode::class, $bp->getNode('no\\;alias')); + $this->assertSame('no;alias', $bp->getNode('no\\;alias')->getAlias()); + + $this->assertTrue($bp->hasNode('@also-with-semicolons:b\;ar')); + $this->assertTrue($bp->getNode('singleHost')->hasChild('@also-with-semicolons:b\;ar')); + $this->assertInstanceOf(ImportedNode::class, $bp->getNode('@also-with-semicolons:b\;ar')); + } } From 1360e1e4a066669cf57258380df001e1fc9a56e3 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 7 Aug 2023 16:35:49 +0200 Subject: [PATCH 033/105] Avoid inline css --- application/controllers/ProcessController.php | 3 +-- application/forms/AddNodeForm.php | 5 ----- application/forms/EditNodeForm.php | 1 - .../Renderer/TileRenderer/NodeTile.php | 9 +++------ public/css/module.less | 14 +++++++++++--- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 75a1b86..aedbd6d 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -182,8 +182,7 @@ class ProcessController extends Controller 'a', [ 'href' => $this->url()->without('showFullscreen')->without('view'), - 'title' => $this->translate('Leave full screen and switch back to normal mode'), - 'style' => 'float: right' + 'title' => $this->translate('Leave full screen and switch back to normal mode') ], Html::tag('i', ['class' => 'icon icon-resize-small']) )); diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php index 76880b6..4759d99 100644 --- a/application/forms/AddNodeForm.php +++ b/application/forms/AddNodeForm.php @@ -177,7 +177,6 @@ class AddNodeForm extends BpConfigBaseForm 'label' => $this->translate('Hosts'), 'required' => true, 'size' => 8, - 'style' => 'width: 25em', 'multiOptions' => $this->enumHostList(), 'description' => $this->translate( 'Hosts that should be part of this business process node' @@ -223,7 +222,6 @@ class AddNodeForm extends BpConfigBaseForm 'label' => $this->translate('Services'), 'required' => true, 'size' => 8, - 'style' => 'width: 25em', 'multiOptions' => $this->enumServiceList($host), 'description' => $this->translate( 'Services that should be part of this business process node' @@ -242,7 +240,6 @@ class AddNodeForm extends BpConfigBaseForm 'label' => $this->translate('Hosts'), 'required' => true, 'size' => 8, - 'style' => 'width: 25em', 'multiOptions' => $this->enumHostListByFilter($filter), 'description' => $this->translate( 'Hosts that should be part of this business process node' @@ -261,7 +258,6 @@ class AddNodeForm extends BpConfigBaseForm 'label' => $this->translate('Services'), 'required' => true, 'size' => 8, - 'style' => 'width: 25em', 'multiOptions' => $this->enumServiceListByFilter($filter), 'description' => $this->translate( 'Services that should be part of this business process node' @@ -363,7 +359,6 @@ class AddNodeForm extends BpConfigBaseForm 'label' => $this->translate('Process nodes'), 'required' => true, 'size' => 8, - 'style' => 'width: 25em', 'multiOptions' => $this->enumProcesses($file), 'description' => $this->translate( 'Other processes that should be part of this business process node' diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php index 448f24f..a4cd919 100644 --- a/application/forms/EditNodeForm.php +++ b/application/forms/EditNodeForm.php @@ -263,7 +263,6 @@ class EditNodeForm extends BpConfigBaseForm 'label' => $this->translate('Process nodes'), 'required' => true, 'size' => 8, - 'style' => 'width: 25em', 'multiOptions' => $this->enumProcesses(), 'description' => $this->translate( 'Other processes that should be part of this business process node' diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index eb85c4e..ec934c0 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -105,12 +105,9 @@ class NodeTile extends BaseHtmlElement $this->add($link); } else { $this->add(Html::tag( - 'a', - Html::tag( - 'span', - ['style' => 'font-size: 75%'], - sprintf('Trying to access a missing business process node "%s"', $node->getNodeName()) - ) + 'span', + ['class' => 'missing-node-msg'], + sprintf('Trying to access a missing business process node "%s"', $node->getNodeName()) )); } diff --git a/public/css/module.less b/public/css/module.less index a05299a..3129db9 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -77,8 +77,11 @@ a:focus { } } -.controls .sort-control { - float: right; +.controls { + &.sort-control, + &.want-fullscreen > a { + float: right; + } } form a { @@ -471,7 +474,8 @@ td > a > .state-badges { border: 1px solid @body-bg-color; } - > a { + > a, + .missing-node-msg { display: block; text-decoration: none; font-size: 0.7em; @@ -481,6 +485,10 @@ td > a > .state-badges { word-wrap: break-word; } + .missing-node-msg { + font-size: 0.5em; + } + &:hover { box-shadow: 0 0 .2em @gray; } From af4b98faeb0643727865cbe959d2da6940da5826 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 7 Aug 2023 13:49:03 +0200 Subject: [PATCH 034/105] Use `fontawesome` icons with `ipl\Web\Widget\Icon` class everywhere --- application/controllers/ProcessController.php | 21 ++++++--- library/Businessprocess/BpNode.php | 3 +- library/Businessprocess/HostNode.php | 2 +- library/Businessprocess/Node.php | 9 ++-- .../Businessprocess/Renderer/Breadcrumb.php | 3 +- .../Renderer/TileRenderer/NodeTile.php | 39 ++++++---------- .../Businessprocess/Renderer/TreeRenderer.php | 15 ++++--- library/Businessprocess/ServiceNode.php | 2 +- .../Component/RenderedProcessActionBar.php | 45 ++++++++++++------- public/css/module.less | 17 ++++--- 10 files changed, 87 insertions(+), 69 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index aedbd6d..c735af2 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -34,6 +34,7 @@ use ipl\Html\TemplateString; use ipl\Html\Text; use ipl\Web\Control\SortControl; use ipl\Web\Widget\Link; +use ipl\Web\Widget\Icon; class ProcessController extends Controller { @@ -184,7 +185,7 @@ class ProcessController extends Controller 'href' => $this->url()->without('showFullscreen')->without('view'), 'title' => $this->translate('Leave full screen and switch back to normal mode') ], - Html::tag('i', ['class' => 'icon icon-resize-small']) + new Icon('down-left-and-up-right-to-center') )); } @@ -603,10 +604,12 @@ class ProcessController extends Controller 'a', [ 'href' => Url::fromPath('businessprocess/process/source', $params), - 'class' => 'icon-doc-text', 'title' => $this->translate('Show source code') ], - $this->translate('Source') + [ + new Icon('file-lines'), + $this->translate('Source'), + ] )); } else { $params = array( @@ -618,10 +621,12 @@ class ProcessController extends Controller 'a', [ 'href' => Url::fromPath('businessprocess/process/source', $params), - 'class' => 'icon-flapping', 'title' => $this->translate('Highlight changes') ], - $this->translate('Diff') + [ + new Icon('shuffle'), + $this->translate('Diff') + ] )); } @@ -629,11 +634,13 @@ class ProcessController extends Controller 'a', [ 'href' => Url::fromPath('businessprocess/process/download', ['config' => $config->getName()]), - 'class' => 'icon-download', 'target' => '_blank', 'title' => $this->translate('Download process configuration') ], - $this->translate('Download') + [ + new Icon('download'), + $this->translate('Download') + ] )); return $actionBar; diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index ca62cf6..67a2602 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotFoundError; use Icinga\Module\Businessprocess\Exception\NestingError; +use ipl\Web\Widget\Icon; class BpNode extends Node { @@ -639,7 +640,7 @@ class BpNode extends Node } } - public function getIcon() + public function getIcon(): Icon { $this->icon = $this->hasParents() ? 'cubes' : 'sitemap'; return parent::getIcon(); diff --git a/library/Businessprocess/HostNode.php b/library/Businessprocess/HostNode.php index ca3f796..df25630 100644 --- a/library/Businessprocess/HostNode.php +++ b/library/Businessprocess/HostNode.php @@ -31,7 +31,7 @@ class HostNode extends MonitoredNode protected $className = 'host'; - protected $icon = 'host'; + protected $icon = 'laptop'; public function __construct($object) { diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index 73236ce..a5af69b 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Businessprocess; use Icinga\Exception\ProgrammingError; use ipl\Html\Html; +use ipl\Web\Widget\Icon; abstract class Node { @@ -463,14 +464,12 @@ abstract class Node public function getLink() { - return Html::tag('a', ['href' => '#', 'class' => 'toggle'], Html::tag('i', [ - 'class' => 'icon icon-down-dir' - ])); + return Html::tag('a', ['href' => '#', 'class' => 'toggle'], new Icon('caret-down')); } - public function getIcon() + public function getIcon(): Icon { - return Html::tag('i', ['class' => 'icon icon-' . ($this->icon ?: 'attention-circled')]); + return new Icon($this->icon ?? 'circle-exclamation'); } public function operatorHtml() diff --git a/library/Businessprocess/Renderer/Breadcrumb.php b/library/Businessprocess/Renderer/Breadcrumb.php index 56c41aa..b0f986b 100644 --- a/library/Businessprocess/Renderer/Breadcrumb.php +++ b/library/Businessprocess/Renderer/Breadcrumb.php @@ -7,6 +7,7 @@ use Icinga\Module\Businessprocess\Renderer\TileRenderer\NodeTile; use Icinga\Module\Businessprocess\Web\Url; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; +use ipl\Web\Widget\Icon; class Breadcrumb extends BaseHtmlElement { @@ -37,7 +38,7 @@ class Breadcrumb extends BaseHtmlElement 'href' => Url::fromPath('businessprocess'), 'title' => mt('businessprocess', 'Show Overview') ], - Html::tag('i', ['class' => 'icon icon-home']) + new Icon('house') ) )); $breadcrumb->add(Html::tag('li')->add( diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index ec934c0..1ca46c7 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -4,12 +4,10 @@ namespace Icinga\Module\Businessprocess\Renderer\TileRenderer; use Icinga\Date\DateFormatter; use Icinga\Module\Businessprocess\BpNode; -use Icinga\Module\Businessprocess\HostNode; use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\MonitoredNode; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Renderer\Renderer; -use Icinga\Module\Businessprocess\ServiceNode; use Icinga\Web\Url; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; @@ -202,14 +200,14 @@ class NodeTile extends BaseHtmlElement 'href' => $url->with('mode', 'tile'), 'title' => mt('businessprocess', 'Show tiles for this subtree') ], - Html::tag('i', ['class' => 'icon icon-dashboard']) + new Icon('grip') ))->add(Html::tag( 'a', [ 'href' => $url->with('mode', 'tree'), 'title' => mt('businessprocess', 'Show this subtree as a tree') ], - Html::tag('i', ['class' => 'icon icon-sitemap']) + new Icon('sitemap') )); if ($node instanceof ImportedNode) { if ($node->getBpConfig()->hasNode($node->getName())) { @@ -223,7 +221,7 @@ class NodeTile extends BaseHtmlElement 'Show this process as part of its original configuration' ) ], - Html::tag('i', ['class' => 'icon icon-forward']) + new Icon('share') )); } } @@ -238,7 +236,7 @@ class NodeTile extends BaseHtmlElement 'class' => 'node-info', 'title' => sprintf('%s: %s', mt('businessprocess', 'More information'), $url) ], - Html::tag('i', ['class' => 'icon icon-info-circled']) + new Icon('info') ); if (preg_match('#^http(?:s)?://#', $url)) { $link->addAttributes(['target' => '_blank']); @@ -246,20 +244,11 @@ class NodeTile extends BaseHtmlElement $this->actions()->add($link); } } else { - // $url = $this->makeMonitoredNodeUrl($node); - if ($node instanceof ServiceNode) { - $this->actions()->add(Html::tag( - 'a', - ['href' => $node->getUrl(), 'data-base-target' => '_next'], - Html::tag('i', ['class' => 'icon icon-service']) - )); - } elseif ($node instanceof HostNode) { - $this->actions()->add(Html::tag( - 'a', - ['href' => $node->getUrl(), 'data-base-target' => '_next'], - Html::tag('i', ['class' => 'icon icon-host']) - )); - } + $this->actions()->add(Html::tag( + 'a', + ['href' => $node->getUrl(), 'data-base-target' => '_next'], + $node->getIcon() + )); } if ($node->isAcknowledged()) { @@ -299,7 +288,7 @@ class NodeTile extends BaseHtmlElement 'Show the business impact of this node by simulating a specific state' ) ], - Html::tag('i', ['class' => 'icon icon-magic']) + new Icon('wand-magic-sparkles') )); $this->actions()->add(Html::tag( @@ -310,7 +299,7 @@ class NodeTile extends BaseHtmlElement ->with('editmonitorednode', $this->node->getName()), 'title' => mt('businessprocess', 'Modify this monitored node') ], - Html::tag('i', ['class' => 'icon icon-edit']) + new Icon('edit') )); } @@ -327,7 +316,7 @@ class NodeTile extends BaseHtmlElement ->with('editnode', $this->node->getName()), 'title' => mt('businessprocess', 'Modify this business process node') ], - Html::tag('i', ['class' => 'icon icon-edit']) + new Icon('edit') )); $addUrl = $baseUrl->with([ @@ -341,7 +330,7 @@ class NodeTile extends BaseHtmlElement 'href' => $addUrl, 'title' => mt('businessprocess', 'Add a new sub-node to this business process') ], - Html::tag('i', ['class' => 'icon icon-plus']) + new Icon('plus') )); } } @@ -358,7 +347,7 @@ class NodeTile extends BaseHtmlElement 'href' => $baseUrl->with($params), 'title' => mt('businessprocess', 'Delete this node') ], - Html::tag('i', ['class' => 'icon icon-cancel']) + new Icon('xmark') )); } } diff --git a/library/Businessprocess/Renderer/TreeRenderer.php b/library/Businessprocess/Renderer/TreeRenderer.php index c9dd218..308d628 100644 --- a/library/Businessprocess/Renderer/TreeRenderer.php +++ b/library/Businessprocess/Renderer/TreeRenderer.php @@ -120,7 +120,7 @@ class TreeRenderer extends Renderer { $icons = []; if (empty($path) && $node instanceof BpNode) { - $icons[] = Html::tag('i', ['class' => 'icon icon-sitemap']); + $icons[] = new Icon('sitemap'); } else { $icons[] = $node->getIcon(); } @@ -137,7 +137,7 @@ class TreeRenderer extends Renderer ]); if ($node->isAcknowledged()) { - $icons[] = Html::tag('i', ['class' => 'icon icon-ok']); + $icons[] = new Icon('check'); } elseif ($node->isInDowntime()) { $icons[] = new Icon('plug'); } @@ -157,7 +157,8 @@ class TreeRenderer extends Renderer ) ]) ); - $overriddenState->add(Html::tag('i', ['class' => 'icon icon-right-small'])); + + $overriddenState->add(new Icon('arrow-right')); $overriddenState->add( (new StateBall(strtolower($node->getStateName($fakeState)), StateBall::SIZE_MEDIUM)) ->addAttributes([ @@ -232,7 +233,7 @@ class TreeRenderer extends Renderer $summary->add($this->getActionIcons($bp, $node)); } elseif ($differentConfig) { $summary->add($this->actionIcon( - 'forward', + 'share', $this->getSourceUrl($node)->addParams(['mode' => 'tree'])->getAbsoluteUrl(), mt('businessprocess', 'Show this process as part of its original configuration') )->addAttributes(['data-base-target' => '_next'])); @@ -331,7 +332,7 @@ class TreeRenderer extends Renderer protected function createSimulationAction(BpConfig $bp, Node $node) { return $this->actionIcon( - 'magic', + 'wand-magic-sparkles', $this->getUrl()->with(array( //'config' => $bp->getName(), 'action' => 'simulation', @@ -345,7 +346,7 @@ class TreeRenderer extends Renderer { $url = $node->getInfoUrl(); return $this->actionIcon( - 'help', + 'question', $url, sprintf('%s: %s', mt('businessprocess', 'More information'), $url) )->addAttributes(['target' => '_blank']); @@ -360,7 +361,7 @@ class TreeRenderer extends Renderer 'title' => $title, 'class' => 'action-link' ], - Html::tag('i', ['class' => 'icon icon-' . $icon]) + new Icon($icon) ); } diff --git a/library/Businessprocess/ServiceNode.php b/library/Businessprocess/ServiceNode.php index 09df484..cba6acf 100644 --- a/library/Businessprocess/ServiceNode.php +++ b/library/Businessprocess/ServiceNode.php @@ -15,7 +15,7 @@ class ServiceNode extends MonitoredNode protected $className = 'service'; - protected $icon = 'service'; + protected $icon = 'gear'; public function __construct($object) { diff --git a/library/Businessprocess/Web/Component/RenderedProcessActionBar.php b/library/Businessprocess/Web/Component/RenderedProcessActionBar.php index 6f192dc..7ad6ad6 100644 --- a/library/Businessprocess/Web/Component/RenderedProcessActionBar.php +++ b/library/Businessprocess/Web/Component/RenderedProcessActionBar.php @@ -8,6 +8,7 @@ use Icinga\Module\Businessprocess\Renderer\Renderer; use Icinga\Module\Businessprocess\Renderer\TreeRenderer; use Icinga\Web\Url; use ipl\Html\Html; +use ipl\Web\Widget\Icon; class RenderedProcessActionBar extends ActionBar { @@ -34,8 +35,8 @@ class RenderedProcessActionBar extends ActionBar } $link->add([ - Html::tag('i', ['class' => 'icon icon-dashboard' . ($renderer instanceof TreeRenderer ? '' : ' active')]), - Html::tag('i', ['class' => 'icon icon-sitemap' . ($renderer instanceof TreeRenderer ? ' active' : '')]) + new Icon('grip', ['class' => $renderer instanceof TreeRenderer ? null : 'active']), + new Icon('sitemap', ['class' => $renderer instanceof TreeRenderer ? 'active' : null]) ]); $this->add( @@ -50,9 +51,11 @@ class RenderedProcessActionBar extends ActionBar 'data-base-target' => '_main', 'href' => $url->with('showFullscreen', true), 'title' => mt('businessprocess', 'Switch to fullscreen mode'), - 'class' => 'icon-resize-full-alt' ], - mt('businessprocess', 'Fullscreen') + [ + new Icon('maximize'), + mt('businessprocess', 'Fullscreen') + ] )); $hasChanges = $config->hasSimulations() || $config->hasBeenChanged(); @@ -66,8 +69,7 @@ class RenderedProcessActionBar extends ActionBar 'Imported processes can only be changed in their original configuration' ) ]); - $span->add(Html::tag('i', ['class' => 'icon icon-lock'])) - ->add(mt('businessprocess', 'Editing Locked')); + $span->add([new Icon('lock'), mt('businessprocess', 'Editing Locked')]); $this->add($span); } else { $this->add(Html::tag( @@ -75,9 +77,11 @@ class RenderedProcessActionBar extends ActionBar [ 'href' => $url->with('unlocked', true), 'title' => mt('businessprocess', 'Click to unlock editing for this process'), - 'class' => 'icon-lock' ], - mt('businessprocess', 'Unlock Editing') + [ + new Icon('lock'), + mt('businessprocess', 'Unlock Editing') + ] )); } } elseif (! $hasChanges) { @@ -86,9 +90,11 @@ class RenderedProcessActionBar extends ActionBar [ 'href' => $url->without('unlocked')->without('action'), 'title' => mt('businessprocess', 'Click to lock editing for this process'), - 'class' => 'icon-lock-open' ], - mt('businessprocess', 'Lock Editing') + [ + new Icon('lock-open'), + mt('businessprocess', 'Lock Editing') + ] )); } @@ -100,9 +106,11 @@ class RenderedProcessActionBar extends ActionBar 'data-base-target' => '_next', 'href' => Url::fromPath('businessprocess/process/config', $this->currentProcessParams($url)), 'title' => mt('businessprocess', 'Modify this process'), - 'class' => 'icon-wrench' ], - mt('businessprocess', 'Config') + [ + new Icon('wrench'), + mt('businessprocess', 'Config') + ] )); } else { $this->add(Html::tag( @@ -113,9 +121,11 @@ class RenderedProcessActionBar extends ActionBar 'editnode' => $url->getParam('node') ])->getAbsoluteUrl(), 'title' => mt('businessprocess', 'Modify this process'), - 'class' => 'icon-wrench' ], - mt('businessprocess', 'Config') + [ + new Icon('wrench'), + mt('businessprocess', 'Config') + ] )); } } @@ -126,9 +136,12 @@ class RenderedProcessActionBar extends ActionBar [ 'href' => $url->with('action', 'add'), 'title' => mt('businessprocess', 'Add a new business process node'), - 'class' => 'icon-plus button-link' + 'class' => 'button-link' ], - mt('businessprocess', 'Add Node') + [ + new Icon('plus'), + mt('businessprocess', 'Add Node') + ] )); } } diff --git a/public/css/module.less b/public/css/module.less index 3129db9..65abdfd 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -132,14 +132,11 @@ ul.bp { } li { - i.icon-service { + > .icon, + summary > .icon { opacity: .75; } - i.icon-sitemap { - opacity: .8; - } - span.state-ball ~ i:last-of-type { margin-right: 0; } @@ -260,6 +257,16 @@ ul.bp { .overridden-state { margin-left: auto; margin-right: 1em; + + i.icon { + font-size: 0.75em; + line-height: 0.08333em; + vertical-align: 0.125em; + + &::before { + margin: 0 .3em; + } + } } } From 78ad4491d2b8c5c17c6df6cfa1f881588ad70553 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 8 Aug 2023 15:18:25 +0200 Subject: [PATCH 035/105] IcingaDbState: Optimize queries There's no need to fetch more data than required. And issuing count queries only for benchmarks.. -.- Also bypasses ipl-orm to fetch results now. fixes #343 --- .../Businessprocess/State/IcingaDbState.php | 96 ++++++++++--------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/library/Businessprocess/State/IcingaDbState.php b/library/Businessprocess/State/IcingaDbState.php index f145395..7943c62 100644 --- a/library/Businessprocess/State/IcingaDbState.php +++ b/library/Businessprocess/State/IcingaDbState.php @@ -52,43 +52,57 @@ class IcingaDbState { $config = $this->config; + $involvedHostNames = $config->listInvolvedHostNames(); + if (empty($involvedHostNames)) { + return $this; + } + Benchmark::measure(sprintf( 'Retrieving states for business process %s using Icinga DB backend', $config->getName() )); - $hosts = $config->listInvolvedHostNames(); - if (empty($hosts)) { - return $this; - } + $hosts = Host::on($this->backend)->columns([ + 'name' => 'host.name', + 'display_name' => 'host.display_name', + 'hard_state' => 'host.state.hard_state', + 'soft_state' => 'host.state.soft_state', + 'last_state_change' => 'host.state.last_state_change', + 'in_downtime' => 'host.state.in_downtime', + 'is_acknowledged' => 'host.state.is_acknowledged' + ])->filter(Filter::equal('host.name', $involvedHostNames)); - $queryHost = Host::on($this->backend)->with('state'); - $queryHost->filter(Filter::equal('host.name', $hosts)); + $services = Service::on($this->backend)->columns([ + 'name' => 'service.name', + 'display_name' => 'service.display_name', + 'host_name' => 'host.name', + 'host_display_name' => 'host.display_name', + 'hard_state' => 'service.state.hard_state', + 'soft_state' => 'service.state.soft_state', + 'last_state_change' => 'service.state.last_state_change', + 'in_downtime' => 'service.state.in_downtime', + 'is_acknowledged' => 'service.state.is_acknowledged' + ])->filter(Filter::equal('host.name', $involvedHostNames)); - $hostObject = $queryHost->getModel()->getTableName(); + // All of this is ipl-sql now, for performance reasons + foreach ($config->listInvolvedConfigs() as $cfg) { + $i = 0; + foreach ($this->backend->yieldAll($services->assembleSelect()) as $row) { + $i++; - Benchmark::measure('Retrieved states for ' . $queryHost->count() . ' hosts in ' . $config->getName()); - - $queryService = Service::on($this->backend) - ->with('state') - ->with('host') - ->with('host.state'); - - $queryService->filter(Filter::equal('host.name', $hosts)); - - Benchmark::measure('Retrieved states for ' . $queryService->count() . ' services in ' . $config->getName()); - - $configs = $config->listInvolvedConfigs(); - - $serviceObject = $queryService->getModel()->getTableName(); - - foreach ($configs as $cfg) { - foreach ($queryService as $row) { - $this->handleDbRow($row, $cfg, $serviceObject); + $this->handleDbRow($row, $cfg, 'service'); } - foreach ($queryHost as $row) { - $this->handleDbRow($row, $cfg, $hostObject); + + Benchmark::measure("Retrieved states for $i services in " . $config->getName()); + + $i = 0; + foreach ($this->backend->yieldAll($hosts->assembleSelect()) as $row) { + $i++; + + $this->handleDbRow($row, $cfg, 'host'); } + + Benchmark::measure("Retrieved states for $i hosts in " . $config->getName()); } Benchmark::measure('Got states for business process ' . $config->getName()); @@ -96,10 +110,10 @@ class IcingaDbState return $this; } - protected function handleDbRow($row, BpConfig $config, $objectName) + protected function handleDbRow($row, BpConfig $config, $type) { - if ($objectName === 'service') { - $key = BpConfig::joinNodeName($row->host->name, $row->name); + if ($type === 'service') { + $key = BpConfig::joinNodeName($row->host_name, $row->name); } else { $key = BpConfig::joinNodeName($row->name, 'Hoststatus'); } @@ -112,29 +126,25 @@ class IcingaDbState $node = $config->getNode($key); if ($this->config->usesHardStates()) { - if ($row->state->hard_state !== null) { - $node->setState($row->state->hard_state)->setMissing(false); + if ($row->hard_state !== null) { + $node->setState($row->hard_state)->setMissing(false); } } else { - if ($row->state->soft_state !== null) { - $node->setState($row->state->soft_state)->setMissing(false); + if ($row->soft_state !== null) { + $node->setState($row->soft_state)->setMissing(false); } } - if ($row->state->last_state_change !== null) { - $node->setLastStateChange($row->state->last_state_change->getTimestamp()); - } - if ($row->state->in_downtime) { - $node->setDowntime(true); - } - if ($row->state->is_acknowledged) { - $node->setAck(true); + if ($row->last_state_change !== null) { + $node->setLastStateChange($row->last_state_change / 1000.0); } + $node->setDowntime($row->in_downtime === 'y'); + $node->setAck($row->is_acknowledged === 'y'); $node->setAlias($row->display_name); if ($node instanceof ServiceNode) { - $node->setHostAlias($row->host->display_name); + $node->setHostAlias($row->host_display_name); } } } From 4d7ea853c114f4cc72372b2fd1149ca7fcbaf0e5 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 9 Aug 2023 10:13:36 +0200 Subject: [PATCH 036/105] (Cleanup/Move)NodeForm extend BpConfigBaseForm --- application/forms/CleanupNodeForm.php | 36 ++------------------------- application/forms/MoveNodeForm.php | 24 ++---------------- 2 files changed, 4 insertions(+), 56 deletions(-) diff --git a/application/forms/CleanupNodeForm.php b/application/forms/CleanupNodeForm.php index 22c5c50..c6e5398 100644 --- a/application/forms/CleanupNodeForm.php +++ b/application/forms/CleanupNodeForm.php @@ -4,14 +4,13 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Modification\ProcessChanges; -use Icinga\Module\Businessprocess\Web\Form\QuickForm; +use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Web\Session\SessionNamespace; -use ipl\Html\FormattedString; use ipl\Html\Html; use ipl\Sql\Connection as IcingaDbConnection; -class CleanupNodeForm extends QuickForm +class CleanupNodeForm extends BpConfigBaseForm { /** @var MonitoringBackend|IcingaDbConnection */ protected $backend; @@ -42,37 +41,6 @@ class CleanupNodeForm extends QuickForm } } - /** - * @param MonitoringBackend|IcingaDbConnection $backend - * @return $this - */ - public function setBackend($backend) - { - $this->backend = $backend; - return $this; - } - - /** - * @param BpConfig $process - * @return $this - */ - public function setProcess(BpConfig $process) - { - $this->bp = $process; - $this->setBackend($process->getBackend()); - return $this; - } - - /** - * @param SessionNamespace $session - * @return $this - */ - public function setSession(SessionNamespace $session) - { - $this->session = $session; - return $this; - } - public function onSuccess() { $changes = ProcessChanges::construct($this->bp, $this->session); diff --git a/application/forms/MoveNodeForm.php b/application/forms/MoveNodeForm.php index 7396277..876ab90 100644 --- a/application/forms/MoveNodeForm.php +++ b/application/forms/MoveNodeForm.php @@ -9,12 +9,12 @@ use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\Exception\ModificationError; use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Node; +use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; use Icinga\Module\Businessprocess\Web\Form\CsrfToken; -use Icinga\Module\Businessprocess\Web\Form\QuickForm; use Icinga\Web\Session; use Icinga\Web\Session\SessionNamespace; -class MoveNodeForm extends QuickForm +class MoveNodeForm extends BpConfigBaseForm { /** @var BpConfig */ protected $bp; @@ -95,16 +95,6 @@ class MoveNodeForm extends QuickForm $this->setSubmitLabel('movenode'); } - /** - * @param BpConfig $process - * @return $this - */ - public function setProcess(BpConfig $process) - { - $this->bp = $process; - return $this; - } - /** * @param Node $node * @return $this @@ -125,16 +115,6 @@ class MoveNodeForm extends QuickForm return $this; } - /** - * @param SessionNamespace $session - * @return $this - */ - public function setSession(SessionNamespace $session) - { - $this->session = $session; - return $this; - } - public function onSuccess() { if (! CsrfToken::isValid($this->getValue('csrfToken'))) { From ffab7edcb3e8c163dc980ed86a5e4f89c2c3b9df Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 9 Aug 2023 10:26:00 +0200 Subject: [PATCH 037/105] IcingaDbState: Apply state data from redis --- .../Businessprocess/State/IcingaDbState.php | 53 ++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/library/Businessprocess/State/IcingaDbState.php b/library/Businessprocess/State/IcingaDbState.php index 7943c62..d44c0f5 100644 --- a/library/Businessprocess/State/IcingaDbState.php +++ b/library/Businessprocess/State/IcingaDbState.php @@ -7,6 +7,7 @@ use Icinga\Application\Benchmark; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\IcingaDbObject; use Icinga\Module\Businessprocess\ServiceNode; +use Icinga\Module\Icingadb\Common\IcingaRedis; use Icinga\Module\Icingadb\Model\Host; use Icinga\Module\Icingadb\Model\Service; use ipl\Sql\Connection as IcingaDbConnection; @@ -63,6 +64,7 @@ class IcingaDbState )); $hosts = Host::on($this->backend)->columns([ + 'id' => 'host.id', 'name' => 'host.name', 'display_name' => 'host.display_name', 'hard_state' => 'host.state.hard_state', @@ -73,6 +75,7 @@ class IcingaDbState ])->filter(Filter::equal('host.name', $involvedHostNames)); $services = Service::on($this->backend)->columns([ + 'id' => 'service.id', 'name' => 'service.name', 'display_name' => 'service.display_name', 'host_name' => 'host.name', @@ -86,23 +89,61 @@ class IcingaDbState // All of this is ipl-sql now, for performance reasons foreach ($config->listInvolvedConfigs() as $cfg) { - $i = 0; + $serviceIds = []; + $serviceResults = []; foreach ($this->backend->yieldAll($services->assembleSelect()) as $row) { - $i++; + $row->hex_id = bin2hex($row->id); + $serviceIds[] = $row->hex_id; + $serviceResults[] = $row; + } + + $redisServiceResults = iterator_to_array(IcingaRedis::fetchServiceState($serviceIds, [ + 'hard_state', + 'soft_state', + 'last_state_change', + 'in_downtime', + 'is_acknowledged' + ])); + foreach ($serviceResults as $row) { + if (isset($redisServiceResults[$row->hex_id])) { + $row = (object) array_merge( + (array) $row, + $redisServiceResults[$row->hex_id] + ); + } $this->handleDbRow($row, $cfg, 'service'); } - Benchmark::measure("Retrieved states for $i services in " . $config->getName()); + Benchmark::measure('Retrieved states for ' . count($serviceIds) . ' services in ' . $config->getName()); - $i = 0; + $hostIds = []; + $hostResults = []; foreach ($this->backend->yieldAll($hosts->assembleSelect()) as $row) { - $i++; + $row->hex_id = bin2hex($row->id); + $hostIds[] = $row->hex_id; + $hostResults[] = $row; + } + + $redisHostResults = iterator_to_array(IcingaRedis::fetchHostState($hostIds, [ + 'hard_state', + 'soft_state', + 'last_state_change', + 'in_downtime', + 'is_acknowledged' + ])); + foreach ($hostResults as $row) { + if (isset($redisHostResults[$row->hex_id])) { + $row = (object) array_merge( + (array) $row, + $redisHostResults[$row->hex_id] + ); + } $this->handleDbRow($row, $cfg, 'host'); } - Benchmark::measure("Retrieved states for $i hosts in " . $config->getName()); + Benchmark::measure('Retrieved states for ' . count($hostIds) . ' hosts in ' . $config->getName()); } Benchmark::measure('Got states for business process ' . $config->getName()); From 1d08c954baeaf4d2fd34d52e1d03d65c7910444d Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 9 Aug 2023 14:10:37 +0200 Subject: [PATCH 038/105] IcingaDbState: Fix postgres support -.- --- library/Businessprocess/State/IcingaDbState.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Businessprocess/State/IcingaDbState.php b/library/Businessprocess/State/IcingaDbState.php index d44c0f5..1a66900 100644 --- a/library/Businessprocess/State/IcingaDbState.php +++ b/library/Businessprocess/State/IcingaDbState.php @@ -92,7 +92,7 @@ class IcingaDbState $serviceIds = []; $serviceResults = []; foreach ($this->backend->yieldAll($services->assembleSelect()) as $row) { - $row->hex_id = bin2hex($row->id); + $row->hex_id = bin2hex(is_resource($row->id) ? stream_get_contents($row->id) : $row->id); $serviceIds[] = $row->hex_id; $serviceResults[] = $row; } @@ -120,7 +120,7 @@ class IcingaDbState $hostIds = []; $hostResults = []; foreach ($this->backend->yieldAll($hosts->assembleSelect()) as $row) { - $row->hex_id = bin2hex($row->id); + $row->hex_id = bin2hex(is_resource($row->id) ? stream_get_contents($row->id) : $row->id); $hostIds[] = $row->hex_id; $hostResults[] = $row; } From 64eb2a7f68e0c493494f9fcaa43337cdde38559f Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 4 Aug 2023 14:30:48 +0200 Subject: [PATCH 039/105] BaseTestCase: Use Icinga Web's base test case --- library/Businessprocess/Test/BaseTestCase.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/Businessprocess/Test/BaseTestCase.php b/library/Businessprocess/Test/BaseTestCase.php index 807905d..daab69c 100644 --- a/library/Businessprocess/Test/BaseTestCase.php +++ b/library/Businessprocess/Test/BaseTestCase.php @@ -7,21 +7,21 @@ use Icinga\Application\ApplicationBootstrap; use Icinga\Application\Icinga; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\Storage\LegacyStorage; -use Icinga\Module\Businessprocess\Web\FakeRequest; -use PHPUnit_Framework_TestCase; -abstract class BaseTestCase extends PHPUnit_Framework_TestCase +abstract class BaseTestCase extends \Icinga\Test\BaseTestCase { /** @var ApplicationBootstrap */ private static $app; - /** - * @inheritdoc - */ - public function setUp() + public function setUp(): void { - $this->app(); - FakeRequest::setConfiguredBaseUrl('/icingaweb2/'); + parent::setUp(); + + $this->getRequestMock()->shouldReceive('getBaseUrl')->andReturn('/icingaweb2/'); + + $this->app() + ->getModuleManager() + ->loadModule('businessprocess'); } protected function emptyConfigSection() From 1b074b523681521a102d947177ddb301c41c66c5 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 4 Aug 2023 14:32:50 +0200 Subject: [PATCH 040/105] php: Add test job --- .github/workflows/php.yml | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 06acb02..45fc836 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -40,3 +40,46 @@ jobs: - name: PHP CodeSniffer if: success() || matrix.allow_failure run: phpcs + + test: + name: Unit tests with php ${{ matrix.php }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + env: + phpunit-version: 8.5 + + strategy: + fail-fast: false + matrix: + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + os: ['ubuntu-latest'] + + steps: + - name: Checkout code base + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: phpunit:${{ matrix.phpunit-version || env.phpunit-version }} + + - name: Setup Icinga Web + run: | + git clone --depth 1 https://github.com/Icinga/icingaweb2.git _icingaweb2 + ln -s `pwd` _icingaweb2/modules/businessprocess + + - name: Setup Libraries + run: | + mkdir _libraries + git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-library.git _libraries/ipl + git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git _libraries/vendor + + - name: Setup dependencies + run: composer require -d _icingaweb2 -n --no-progress mockery/mockery + + - name: PHPUnit + env: + ICINGAWEB_LIBDIR: _libraries + ICINGAWEB_CONFIGDIR: test/config + run: phpunit --verbose --bootstrap _icingaweb2/test/php/bootstrap.php From dc41ded97e428cb95d3aef36903c5c8aeedcc1d2 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 4 Aug 2023 14:35:29 +0200 Subject: [PATCH 041/105] Drop unused integration configs --- .gitlab-ci.yml | 86 -------------------------------------------------- .travis.yml | 31 ------------------ phpunit.xml | 1 - 3 files changed, 118 deletions(-) delete mode 100644 .gitlab-ci.yml delete mode 100644 .travis.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index aed4be7..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,86 +0,0 @@ -stages: -- Coding Standards -- Unit-Tests -- Build Packages - -variables: - BASE_VERSION: "2.0.0" - VERSION_SUFFIX: "-b${CI_BUILD_ID}-${CI_BUILD_REF_SLUG}" - -PSR2 CS Test: - stage: Coding Standards - tags: - - xenial - script: - - phpcs --report-width=auto --report-full --report-gitblame --report-summary -p --standard=PSR2 --extensions=php --encoding=utf-8 -w -s library/Businessprocess/ application/ configuration.php run.php test - -Ubuntu Xenial: - stage: Unit-Tests - tags: - - xenial - - businessprocess - script: - - phpunit --testdox --coverage-html=coverage || phpunit --verbose - artifacts: - expire_in: 1 week - name: code-coverage - paths: - - coverage/* - -Debian Jessie: - stage: Unit-Tests - tags: - - jessie - - businessprocess - script: - - phpunit --testdox || phpunit --verbose - -CentOS 6: - stage: Unit-Tests - tags: - - centos6 - - businessprocess - script: - - phpunit --testdox || phpunit --verbose - -CentOS 7: - stage: Unit-Tests - tags: - - centos7 - - businessprocess - script: - - phpunit --testdox || phpunit --verbose - -Xenial Packages: - stage: Build Packages - tags: - - xenial - - businessprocess - script: - - cp -a packaging/debian debian - - dch --no-conf -U -M --empty -v "${BASE_VERSION}${VERSION_SUFFIX}-${CI_BUILD_REF:0:7}" "Automated build triggered by ${GITLAB_USER_ID} <${GITLAB_USER_EMAIL}>" - - cp LICENSE debian/copyright - - dpkg-buildpackage -us -uc - - mkdir build - - mv ../icingaweb2-module-businessprocess*.deb build/ - artifacts: - expire_in: 1 week - paths: - - build/* - -Jessie Packages: - stage: Build Packages - tags: - - jessie - - businessprocess - script: - - cp -a packaging/debian debian - - dch --no-conf -U -M --empty -v "${BASE_VERSION}${VERSION_SUFFIX}-${CI_BUILD_REF:0:7}" "Automated build triggered by ${GITLAB_USER_ID} <${GITLAB_USER_EMAIL}>" - - cp LICENSE debian/copyright - - dpkg-buildpackage -us -uc - - mkdir build - - mv ../icingaweb2-module-businessprocess*.deb build/ - artifacts: - expire_in: 1 week - paths: - - build/* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 69749bb..0000000 --- a/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -language: php -php: - - '5.4' - - '5.5' - - '5.6' - - '7.0' - - '7.1' - - '7.2' - - nightly - -matrix: - fast_finish: true - allow_failures: - - php: '5.4' - - php: '5.5' - - php: nightly - -cache: - directories: - - vendor - -env: - - ICINGAWEB_VERSION=2.6.2 - - IPL_VERSION=0.1.1 - -before_script: - - ./test/setup_vendor.sh - -script: - - php vendor/phpcs.phar - - php vendor/phpunit.phar --testdox || php vendor/phpunit.phar --verbose diff --git a/phpunit.xml b/phpunit.xml index 064e01c..5eaf639 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -7,7 +7,6 @@ convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" - syntaxCheck="false" bootstrap="test/bootstrap.php" > From 08cae4533641cf8aeb6b8aacad982a4a100acca8 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Tue, 8 Aug 2023 15:22:51 +0200 Subject: [PATCH 042/105] Imported Node: Don't break view if source config file is faulty --- library/Businessprocess/BpConfig.php | 47 +++++++++++++++++-- library/Businessprocess/ImportedNode.php | 14 ++++-- .../Renderer/TileRenderer/NodeTile.php | 14 +++--- .../Businessprocess/Renderer/TreeRenderer.php | 4 +- public/css/module.less | 7 +-- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index e99f81c..3e652e9 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -130,6 +130,9 @@ class BpConfig /** @var ProcessChanges */ protected $appliedChanges; + /** @var bool Whether the config is faulty */ + protected $isFaulty = false; + public function __construct() { } @@ -577,7 +580,13 @@ class BpConfig public function getImportedConfig($name) { if (! isset($this->importedConfigs[$name])) { - $import = $this->storage()->loadProcess($name); + try { + $import = $this->storage()->loadProcess($name); + } catch (Exception $e) { + $import = (new static()) + ->setName($name) + ->setFaulty(); + } if ($this->usesSoftStates()) { $import->useSoftStates(); @@ -687,9 +696,17 @@ class BpConfig { if ($this->hasBpNode($name)) { return $this->nodes[$name]; - } else { - throw new NotFoundError('Trying to access a missing business process node "%s"', $name); } + + $msg = $this->isFaulty() + ? sprintf( + t('Trying to import node "%s" from faulty config file "%s.conf"'), + $name, + $this->getName() + ) + : sprintf(t('Trying to access a missing business process node "%s"'), $name); + + throw new NotFoundError($msg); } /** @@ -1070,4 +1087,28 @@ class BpConfig return array_pad($parts, 2, null); } + + /** + * Set whether the config is faulty + * + * @param bool $isFaulty + * + * @return $this + */ + public function setFaulty(bool $isFaulty = true): self + { + $this->isFaulty = $isFaulty; + + return $this; + } + + /** + * Get whether the config is faulty + * + * @return bool + */ + public function isFaulty(): bool + { + return $this->isFaulty; + } } diff --git a/library/Businessprocess/ImportedNode.php b/library/Businessprocess/ImportedNode.php index e20b0a7..a0eb6b1 100644 --- a/library/Businessprocess/ImportedNode.php +++ b/library/Businessprocess/ImportedNode.php @@ -90,6 +90,15 @@ class ImportedNode extends BpNode return $this->childNames; } + public function isMissing() + { + if ($this->missing === null && $this->getBpConfig()->isFaulty()) { + $this->missing = true; + } + + return parent::isMissing(); + } + /** * @return BpNode */ @@ -121,10 +130,9 @@ class ImportedNode extends BpNode )); $node->setBpConfig($this->getBpConfig()); $node->setState(2); - $node->setMissing(false) + $node->setMissing() ->setDowntime(false) - ->setAck(false) - ->setAlias($e->getMessage()); + ->setAck(false); return $node; } diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index 1ca46c7..652ca0e 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -12,6 +12,7 @@ use Icinga\Web\Url; use ipl\Html\BaseHtmlElement; use ipl\Html\Html; use ipl\Web\Widget\Icon; +use ipl\Web\Widget\Link; use ipl\Web\Widget\StateBall; class NodeTile extends BaseHtmlElement @@ -102,11 +103,7 @@ class NodeTile extends BaseHtmlElement $this->add($link); } else { - $this->add(Html::tag( - 'span', - ['class' => 'missing-node-msg'], - sprintf('Trying to access a missing business process node "%s"', $node->getNodeName()) - )); + $this->add(new Link($node->getAlias(), $this->getMainNodeUrl($node)->getAbsoluteUrl())); } if ($this->renderer->rendersSubNode() @@ -210,12 +207,15 @@ class NodeTile extends BaseHtmlElement new Icon('sitemap') )); if ($node instanceof ImportedNode) { - if ($node->getBpConfig()->hasNode($node->getName())) { + $bpConfig = $node->getBpConfig(); + if ($bpConfig->isFaulty() || $bpConfig->hasNode($node->getName())) { $this->actions()->add(Html::tag( 'a', [ 'data-base-target' => '_next', - 'href' => $this->renderer->getSourceUrl($node)->getAbsoluteUrl(), + 'href' => $bpConfig->isFaulty() + ? $this->renderer->getBaseUrl()->setParam('config', $bpConfig->getName()) + : $this->renderer->getSourceUrl($node)->getAbsoluteUrl(), 'title' => mt( 'businessprocess', 'Show this process as part of its original configuration' diff --git a/library/Businessprocess/Renderer/TreeRenderer.php b/library/Businessprocess/Renderer/TreeRenderer.php index 308d628..097d148 100644 --- a/library/Businessprocess/Renderer/TreeRenderer.php +++ b/library/Businessprocess/Renderer/TreeRenderer.php @@ -234,7 +234,9 @@ class TreeRenderer extends Renderer } elseif ($differentConfig) { $summary->add($this->actionIcon( 'share', - $this->getSourceUrl($node)->addParams(['mode' => 'tree'])->getAbsoluteUrl(), + $node->getBpConfig()->isFaulty() + ? $this->getBaseUrl()->setParam('config', $node->getBpConfig()->getName()) + : $this->getSourceUrl($node)->addParams(['mode' => 'tree'])->getAbsoluteUrl(), mt('businessprocess', 'Show this process as part of its original configuration') )->addAttributes(['data-base-target' => '_next'])); } diff --git a/public/css/module.less b/public/css/module.less index 65abdfd..500a137 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -481,8 +481,7 @@ td > a > .state-badges { border: 1px solid @body-bg-color; } - > a, - .missing-node-msg { + > a { display: block; text-decoration: none; font-size: 0.7em; @@ -492,10 +491,6 @@ td > a > .state-badges { word-wrap: break-word; } - .missing-node-msg { - font-size: 0.5em; - } - &:hover { box-shadow: 0 0 .2em @gray; } From f93873623f11bc3b948a24940a1f505977324b6f Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 9 Aug 2023 09:54:37 +0200 Subject: [PATCH 043/105] Call it `faulty config` intead of `invalid config` --- application/clicommands/CleanupCommand.php | 2 +- library/Businessprocess/Web/Component/Dashboard.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/clicommands/CleanupCommand.php b/application/clicommands/CleanupCommand.php index 04fc781..f0041c8 100644 --- a/application/clicommands/CleanupCommand.php +++ b/application/clicommands/CleanupCommand.php @@ -52,7 +52,7 @@ class CleanupCommand extends Command $bp = $this->storage->loadProcess($configName); } catch (Exception $e) { Logger::error( - 'Failed to scan the %s.conf file for missing nodes. Invalid config found.', + 'Failed to scan the %s.conf file for missing nodes. Faulty config found.', $configName ); diff --git a/library/Businessprocess/Web/Component/Dashboard.php b/library/Businessprocess/Web/Component/Dashboard.php index e78c46c..d211772 100644 --- a/library/Businessprocess/Web/Component/Dashboard.php +++ b/library/Businessprocess/Web/Component/Dashboard.php @@ -100,7 +100,7 @@ class Dashboard extends BaseHtmlElement $this->add(new BpDashboardTile( new BpConfig(), $title, - sprintf(t('File %s has invalid config'), $name . '.conf'), + sprintf(t('File %s has faulty config'), $name . '.conf'), 'file-circle-xmark', 'businessprocess/process/show', ['config' => $name] From 25f37d6575dc47b5957417f376150e8acdedf21c Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 9 Aug 2023 12:29:18 +0200 Subject: [PATCH 044/105] Use unescaped node name for missing children --- application/controllers/ProcessController.php | 2 +- library/Businessprocess/BpConfig.php | 2 +- library/Businessprocess/BpNode.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index c735af2..0cfced2 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -448,7 +448,7 @@ class ProcessController extends Controller protected function prepareMissingNodeLinks(HtmlElement $ul): void { - $missing = $this->bp->getMissingChildren(); + $missing = array_keys($this->bp->getMissingChildren()); if (! empty($missing)) { $missingLinkedNodes = null; foreach ($this->bp->getImportedNodes() as $process) { diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index 3e652e9..e2fd5c9 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -701,7 +701,7 @@ class BpConfig $msg = $this->isFaulty() ? sprintf( t('Trying to import node "%s" from faulty config file "%s.conf"'), - $name, + self::unescapeName($name), $this->getName() ) : sprintf(t('Trying to access a missing business process node "%s"'), $name); diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 67a2602..419f836 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -275,11 +275,11 @@ class BpNode extends Node foreach ($this->getChildren() as $child) { if ($child->isMissing()) { - $missing[$child->getName()] = $child; + $missing[$child->getAlias()] = $child; } foreach ($child->getMissingChildren() as $m) { - $missing[$m->getName()] = $m; + $missing[$m->getAlias()] = $m; } } From 2576fc3dc310558888c64f9895007061ab514f72 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 9 Aug 2023 12:38:28 +0200 Subject: [PATCH 045/105] BpConfig: Don't add same error message multiple times --- library/Businessprocess/BpConfig.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index e2fd5c9..30cdf56 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -929,7 +929,10 @@ class BpConfig throw new IcingaException($msg); } - $this->errors[] = $msg; + if (! in_array($msg, $this->errors)) { + $this->errors[] = $msg; + } + return $this; } From 0fdee96debfb1915b23a90bc57452cd5b8c2222c Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 10:11:41 +0200 Subject: [PATCH 046/105] IDO: Add custom hoststatus and servicestatus queries For autocompletion with custom variable support, it is required to be able to filter for custom variable values if no customvariable name is known. But since the template how custom variables are joined is on a private property, this many classes are required to circumvent/adjust that. --- .../Query/CustomVarJoinTemplateOverride.php | 84 +++++++++++++++++++ .../Backend/Ido/Query/HostStatusQuery.php | 8 ++ .../Backend/Ido/Query/ServiceStatusQuery.php | 8 ++ .../Monitoring/DataView/HostStatus.php | 16 ++++ .../Monitoring/DataView/ServiceStatus.php | 16 ++++ 5 files changed, 132 insertions(+) create mode 100644 library/Businessprocess/Monitoring/Backend/Ido/Query/CustomVarJoinTemplateOverride.php create mode 100644 library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php create mode 100644 library/Businessprocess/Monitoring/Backend/Ido/Query/ServiceStatusQuery.php create mode 100644 library/Businessprocess/Monitoring/DataView/HostStatus.php create mode 100644 library/Businessprocess/Monitoring/DataView/ServiceStatus.php diff --git a/library/Businessprocess/Monitoring/Backend/Ido/Query/CustomVarJoinTemplateOverride.php b/library/Businessprocess/Monitoring/Backend/Ido/Query/CustomVarJoinTemplateOverride.php new file mode 100644 index 0000000..385ca59 --- /dev/null +++ b/library/Businessprocess/Monitoring/Backend/Ido/Query/CustomVarJoinTemplateOverride.php @@ -0,0 +1,84 @@ +customvarNameToTypeName($customvar); + $alias = ($type === 'host' ? 'hcv_' : 'scv_') . preg_replace('~[^a-zA-Z0-9_]~', '_', $name); + + // We're replacing any problematic char with an underscore, which will lead to duplicates, this avoids them + $from = $this->select->getPart(Zend_Db_Select::FROM); + for ($i = 2; array_key_exists($alias, $from); $i++) { + $alias = $alias . '_' . $i; + } + + $this->customVars[strtolower($customvar)] = $alias; + + if ($type === 'host') { + if ($this instanceof ServicecommentQuery + || $this instanceof ServicedowntimeQuery + || $this instanceof ServicecommenthistoryQuery + || $this instanceof ServicedowntimestarthistoryQuery + || $this instanceof ServiceflappingstarthistoryQuery + || $this instanceof ServicegroupQuery + || $this instanceof ServicenotificationQuery + || $this instanceof ServicestatehistoryQuery + || $this instanceof \Icinga\Module\Monitoring\Backend\Ido\Query\ServicestatusQuery + ) { + $this->requireVirtualTable('services'); + $leftcol = 's.host_object_id'; + } else { + $leftcol = 'ho.object_id'; + if (! $this->hasJoinedTable('ho')) { + $this->requireVirtualTable('hosts'); + } + } + } else { // $type === 'service' + $leftcol = 'so.object_id'; + if (! $this->hasJoinedTable('so')) { + $this->requireVirtualTable('services'); + } + } + + $mapped = $this->getMappedField($leftcol); + if ($mapped !== null) { + $this->requireColumn($leftcol); + $leftcol = $mapped; + } + + $joinOn = sprintf( + $this->customVarsJoinTemplate, + $leftcol, + $alias, + $this->db->quote($name) + ); + + $this->select->joinLeft( + array($alias => $this->prefix . 'customvariablestatus'), + $joinOn, + array() + ); + + return $this; + } +} diff --git a/library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php b/library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php new file mode 100644 index 0000000..e6ea238 --- /dev/null +++ b/library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php @@ -0,0 +1,8 @@ +query = new HostStatusQuery($connection->getResource(), $columns); + } +} diff --git a/library/Businessprocess/Monitoring/DataView/ServiceStatus.php b/library/Businessprocess/Monitoring/DataView/ServiceStatus.php new file mode 100644 index 0000000..f3a9c3c --- /dev/null +++ b/library/Businessprocess/Monitoring/DataView/ServiceStatus.php @@ -0,0 +1,16 @@ +query = new ServiceStatusQuery($connection->getResource(), $columns); + } +} From cb83f800b979169ba3faab020ac5bd74deeeb9de Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 10:26:50 +0200 Subject: [PATCH 047/105] Drop class `AddNodeForm` --- application/controllers/ProcessController.php | 10 +- application/forms/AddNodeForm.php | 513 ------------------ 2 files changed, 1 insertion(+), 522 deletions(-) delete mode 100644 application/forms/AddNodeForm.php diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 0cfced2..4a6495e 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -268,15 +268,7 @@ class ProcessController extends Controller $canEdit = $bp->getMetadata()->canModify(); - if ($action === 'add' && $canEdit) { - $form = $this->loadForm('AddNode') - ->setSuccessUrl(Url::fromRequest()->without('action')) - ->setStorage($this->storage()) - ->setProcess($bp) - ->setParentNode($node) - ->setSession($this->session()) - ->handleRequest(); - } elseif ($action === 'cleanup' && $canEdit) { + if ($action === 'cleanup' && $canEdit) { $form = $this->loadForm('CleanupNode') ->setSuccessUrl(Url::fromRequest()->without('action')) ->setProcess($bp) diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php deleted file mode 100644 index 4759d99..0000000 --- a/application/forms/AddNodeForm.php +++ /dev/null @@ -1,513 +0,0 @@ -getView(); - if ($this->hasParentNode()) { - $this->addHtml( - '

' . $view->escape( - sprintf($this->translate('Add a node to %s'), $this->parent->getAlias()) - ) . '

' - ); - } else { - $this->addHtml( - '

' . $this->translate('Add a new root node') . '

' - ); - } - - $type = $this->selectNodeType(); - switch ($type) { - case 'host': - $this->selectHost(); - break; - case 'service': - $this->selectService(); - break; - case 'process': - $this->selectProcess(); - break; - case 'new-process': - $this->addNewProcess(); - break; - case 'hosts_from_filter': - $this->selectHostsFromFilter(); - break; - case 'services_from_filter': - $this->selectServicesFromFilter(); - break; - case null: - $this->setSubmitLabel($this->translate('Next')); - return; - } - } - - protected function addNewProcess() - { - $this->addElement('text', 'name', array( - 'label' => $this->translate('ID'), - 'required' => true, - 'description' => $this->translate( - 'This is the unique identifier of this process' - ), - 'validators' => [ - ['Callback', true, [ - 'callback' => function ($value) { - if ($this->hasParentNode()) { - return ! $this->parent->hasChild($value); - } - - return ! $this->bp->hasRootNode($value); - }, - 'messages' => [ - 'callbackValue' => $this->translate('%value% is already defined in this process') - ] - ]] - ] - )); - - $this->addElement('text', 'alias', array( - 'label' => $this->translate('Display Name'), - 'description' => $this->translate( - 'Usually this name will be shown for this node. Equals ID' - . ' if not given' - ), - )); - - $this->addElement('select', 'operator', array( - 'label' => $this->translate('Operator'), - 'required' => true, - 'multiOptions' => Node::getOperators() - )); - - $display = 1; - if ($this->bp->getMetadata()->isManuallyOrdered() && ! $this->bp->isEmpty()) { - $rootNodes = self::applyManualSorting($this->bp->getRootNodes()); - $display = end($rootNodes)->getDisplay() + 1; - } - $this->addElement('select', 'display', array( - 'label' => $this->translate('Visualization'), - 'required' => true, - 'description' => $this->translate( - 'Where to show this process' - ), - 'value' => $this->hasParentNode() ? '0' : "$display", - 'multiOptions' => array( - "$display" => $this->translate('Toplevel Process'), - '0' => $this->translate('Subprocess only'), - ) - )); - - $this->addElement('text', 'infoUrl', array( - 'label' => $this->translate('Info URL'), - 'description' => $this->translate( - 'URL pointing to more information about this node' - ) - )); - } - - /** - * @return string|null - */ - protected function selectNodeType() - { - $types = array(); - if ($this->hasParentNode()) { - $types['host'] = $this->translate('Host'); - $types['service'] = $this->translate('Service'); - $types['hosts_from_filter'] = $this->translate('Hosts from filter'); - $types['services_from_filter'] = $this->translate('Services from filter'); - } elseif (! $this->hasProcesses()) { - $this->addElement('hidden', 'node_type', array( - 'ignore' => true, - 'decorators' => array('ViewHelper'), - 'value' => 'new-process' - )); - - return 'new-process'; - } - - if ($this->hasProcesses() || ($this->hasParentNode() && $this->hasMoreConfigs())) { - $types['process'] = $this->translate('Existing Process'); - } - - $types['new-process'] = $this->translate('New Process Node'); - - $this->addElement('select', 'node_type', array( - 'label' => $this->translate('Node type'), - 'required' => true, - 'description' => $this->translate( - 'The node type you want to add' - ), - 'ignore' => true, - 'class' => 'autosubmit', - 'multiOptions' => $this->optionalEnum($types) - )); - - return $this->getSentValue('node_type'); - } - - protected function selectHost() - { - $this->addElement('multiselect', 'children', [ - 'label' => $this->translate('Hosts'), - 'required' => true, - 'size' => 8, - 'multiOptions' => $this->enumHostList(), - 'description' => $this->translate( - 'Hosts that should be part of this business process node' - ), - 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] - ]); - - $this->addHostOverrideCheckbox(); - if ($this->getSentValue('host_override') === '1') { - $this->addHostOverrideElement(); - } - } - - protected function selectService() - { - $this->addHostElement(); - if ($host = $this->getSentValue('host')) { - $this->addServicesElement($host); - $this->addServiceOverrideCheckbox(); - - if ($this->getSentValue('service_override') === '1') { - $this->addServiceOverrideElement(); - } - } else { - $this->setSubmitLabel($this->translate('Next')); - } - } - - protected function addHostElement() - { - $this->addElement('select', 'host', array( - 'label' => $this->translate('Host'), - 'required' => true, - 'ignore' => true, - 'class' => 'autosubmit', - 'multiOptions' => $this->optionalEnum($this->enumHostForServiceList()), - )); - } - - protected function addServicesElement($host) - { - $this->addElement('multiselect', 'children', [ - 'label' => $this->translate('Services'), - 'required' => true, - 'size' => 8, - 'multiOptions' => $this->enumServiceList($host), - 'description' => $this->translate( - 'Services that should be part of this business process node' - ), - 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] - ]); - } - - protected function addFilteredHostsElement($filter) - { - $this->addElement('submit', 'refresh', [ - 'label' => $this->translate('Refresh'), - 'class' => 'refresh-filter' - ]); - $this->addElement('multiselect', 'children', [ - 'label' => $this->translate('Hosts'), - 'required' => true, - 'size' => 8, - 'multiOptions' => $this->enumHostListByFilter($filter), - 'description' => $this->translate( - 'Hosts that should be part of this business process node' - ), - 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] - ]); - } - - protected function addFilteredServicesElement($filter) - { - $this->addElement('submit', 'refresh', [ - 'label' => $this->translate('Refresh'), - 'class' => 'refresh-filter' - ]); - $this->addElement('multiselect', 'children', [ - 'label' => $this->translate('Services'), - 'required' => true, - 'size' => 8, - 'multiOptions' => $this->enumServiceListByFilter($filter), - 'description' => $this->translate( - 'Services that should be part of this business process node' - ), - 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] - ]); - } - - protected function addFilterElement() - { - $this->addElement('text', 'filter', array( - 'label' => $this->translate('Filter'), - 'required' => true, - 'ignore' => true - )); - } - - protected function addFileElement() - { - $this->addElement('select', 'file', [ - 'label' => $this->translate('File'), - 'required' => true, - 'ignore' => true, - 'value' => $this->bp->getName(), - 'class' => 'autosubmit', - 'multiOptions' => $this->optionalEnum($this->enumConfigs()), - 'description' => $this->translate( - 'Choose a different configuration file to import its processes' - ) - ]); - } - - protected function addHostOverrideCheckbox() - { - $this->addElement('checkbox', 'host_override', [ - 'ignore' => true, - 'class' => 'autosubmit', - 'label' => $this->translate('Override Host State'), - 'description' => $this->translate('Enable host state overrides') - ]); - } - - protected function addHostOverrideElement() - { - $this->addElement('stateOverrides', 'stateOverrides', [ - 'required' => true, - 'label' => $this->translate('State Overrides'), - 'states' => $this->enumHostStateList() - ]); - } - - protected function addServiceOverrideCheckbox() - { - $this->addElement('checkbox', 'service_override', [ - 'ignore' => true, - 'class' => 'autosubmit', - 'label' => $this->translate('Override Service State'), - 'description' => $this->translate('Enable service state overrides') - ]); - } - - protected function addServiceOverrideElement() - { - $this->addElement('stateOverrides', 'stateOverrides', [ - 'required' => true, - 'label' => $this->translate('State Overrides'), - 'states' => $this->enumServiceStateList() - ]); - } - - protected function selectHostsFromFilter() - { - $this->addFilterElement(); - if ($filter = $this->getSentValue('filter')) { - $this->addFilteredHostsElement($filter); - } else { - $this->setSubmitLabel($this->translate('Next')); - } - } - - protected function selectServicesFromFilter() - { - $this->addFilterElement(); - if ($filter = $this->getSentValue('filter')) { - $this->addFilteredServicesElement($filter); - } else { - $this->setSubmitLabel($this->translate('Next')); - } - } - - protected function selectProcess() - { - if ($this->hasParentNode()) { - $this->addFileElement(); - } - - if (($file = $this->getSentValue('file')) || !$this->hasParentNode()) { - $this->addElement('multiselect', 'children', [ - 'label' => $this->translate('Process nodes'), - 'required' => true, - 'size' => 8, - 'multiOptions' => $this->enumProcesses($file), - 'description' => $this->translate( - 'Other processes that should be part of this business process node' - ), - 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] - ]); - } else { - $this->setSubmitLabel($this->translate('Next')); - } - } - - /** - * @param BpNode|null $node - * @return $this - */ - public function setParentNode(BpNode $node = null) - { - $this->parent = $node; - return $this; - } - - /** - * @return bool - */ - public function hasParentNode() - { - return $this->parent !== null; - } - - protected function hasProcesses() - { - return count($this->enumProcesses()) > 0; - } - - /** - * @param string $file - * @return array - */ - protected function enumProcesses($file = null) - { - $list = array(); - - $parents = array(); - - $differentFile = $file !== null && $file !== $this->bp->getName(); - - if (! $differentFile && $this->hasParentNode()) { - $this->collectAllParents($this->parent, $parents); - $parents[$this->parent->getName()] = $this->parent; - } - - $bp = $this->bp; - if ($differentFile) { - try { - $bp = $this->storage->loadProcess($file); - } catch (Exception $e) { - $this->addError('Cannot add invalid config file'); - - return $list; - } - } - - foreach ($bp->getNodes() as $node) { - if (! $node instanceof ImportedNode && $node instanceof BpNode && ! isset($parents[$node->getName()])) { - $name = $node->getName(); - if ($differentFile) { - $name = '@' . $file . ':' . $name; - } - - $list[$name] = $node->getName(); // display name? - } - } - - return $list; - } - - protected function hasMoreConfigs() - { - $configs = $this->enumConfigs(); - return !empty($configs); - } - - protected function enumConfigs() - { - return $this->storage->listProcesses(); - } - - /** - * Collect the given node's parents recursively into the given array by their names - * - * @param BpNode $node - * @param BpNode[] $parents - */ - protected function collectAllParents(BpNode $node, array &$parents) - { - foreach ($node->getParents() as $parent) { - $parents[$parent->getName()] = $parent; - $this->collectAllParents($parent, $parents); - } - } - - public function onSuccess() - { - $changes = ProcessChanges::construct($this->bp, $this->session); - switch ($this->getValue('node_type')) { - case 'host': - case 'service': - $stateOverrides = $this->getValue('stateOverrides'); - if (! empty($stateOverrides)) { - $childOverrides = []; - foreach ($this->getValue('children') as $service) { - $childOverrides[$service] = $stateOverrides; - } - - $changes->modifyNode($this->parent, [ - 'stateOverrides' => array_merge($this->parent->getStateOverrides(), $childOverrides) - ]); - } - - // Fallthrough - case 'process': - case 'hosts_from_filter': - case 'services_from_filter': - if ($this->hasParentNode()) { - $changes->addChildrenToNode($this->getValue('children'), $this->parent); - } else { - foreach ($this->getValue('children') as $nodeName) { - $changes->copyNode($nodeName); - } - } - - break; - case 'new-process': - $properties = $this->getValues(); - unset($properties['name']); - if (! $properties['alias']) { - unset($properties['alias']); - } - if ($this->hasParentNode()) { - $properties['parentName'] = $this->parent->getName(); - } - $changes->createNode(BpConfig::escapeName($this->getValue('name')), $properties); - break; - } - - // Trigger session destruction to make sure it get's stored. - // TODO: figure out why this is necessary, might be an unclean shutdown on redirect - unset($changes); - - parent::onSuccess(); - } -} From b84405180c502826e5e3c0bdbd587ca40da41cf9 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 10:29:05 +0200 Subject: [PATCH 048/105] Add new endpoint for node suggestions --- .../controllers/SuggestionsController.php | 372 ++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 application/controllers/SuggestionsController.php diff --git a/application/controllers/SuggestionsController.php b/application/controllers/SuggestionsController.php new file mode 100644 index 0000000..9fa0331 --- /dev/null +++ b/application/controllers/SuggestionsController.php @@ -0,0 +1,372 @@ +params->has('config')) { + $forConfig = $this->loadModifiedBpConfig(); + + $parentName = $this->params->get('node'); + if ($parentName) { + $forParent = $forConfig->getBpNode($parentName); + + $collectParents = function ($node) use ($ignoreList, &$collectParents) { + foreach ($node->getParents() as $parent) { + $ignoreList[$parent->getName()] = true; + + if ($parent->hasParents()) { + $collectParents($parent); + } + } + }; + + $ignoreList[$parentName] = true; + if ($forParent->hasParents()) { + $collectParents($forParent); + } + + foreach ($forParent->getChildNames() as $name) { + $ignoreList[$name] = true; + } + } + } + + $suggestions = new TermSuggestions((function () use ($forConfig, $forParent, $ignoreList, &$suggestions) { + foreach ($this->storage()->listProcessNames() as $config) { + $differentConfig = false; + if ($forConfig === null || $config !== $forConfig->getName()) { + if ($forConfig !== null && $forParent === null) { + continue; + } + + try { + $bp = $this->storage()->loadProcess($config); + } catch (Exception $_) { + continue; + } + + $differentConfig = true; + } else { + $bp = $forConfig; + } + + foreach ($bp->getBpNodes() as $bpNode) { + /** @var BpNode $bpNode */ + if ($bpNode instanceof ImportedNode) { + continue; + } + + $search = $bpNode->getName(); + if ($differentConfig) { + $search = "@$config:$search"; + } + + if (in_array($search, $suggestions->getExcludeTerms(), true) + || isset($ignoreList[$search]) + || ($forParent + ? $forParent->hasChild($search) + : ($forConfig && $forConfig->hasRootNode($search)) + ) + ) { + continue; + } + + if ($suggestions->matchSearch($bpNode->getName()) + || (! $bpNode->hasAlias() || $suggestions->matchSearch($bpNode->getAlias())) + || $bpNode->getName() === $suggestions->getOriginalSearchValue() + || $bpNode->getAlias() === $suggestions->getOriginalSearchValue() + ) { + yield [ + 'search' => $search, + 'label' => $bpNode->getAlias() ?? $bpNode->getName(), + 'config' => $config + ]; + } + } + } + })()); + $suggestions->setGroupingCallback(function (array $data) { + return $this->storage()->loadMetadata($data['config'])->getTitle(); + }); + + $this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest())); + } + + public function icingadbHostAction() + { + $excludes = Filter::none(); + $forConfig = null; + if ($this->params->has('config')) { + $forConfig = $this->loadModifiedBpConfig(); + + if ($this->params->has('node')) { + $nodeName = $this->params->get('node'); + $node = $forConfig->getBpNode($nodeName); + + foreach ($node->getChildren() as $child) { + if ($child instanceof HostNode) { + $excludes->add(Filter::equal('host.name', $child->getHostname())); + } + } + } + } + + $suggestions = new TermSuggestions((function () use ($forConfig, $excludes, &$suggestions) { + foreach ($suggestions->getExcludeTerms() as $excludeTerm) { + [$hostName, $_] = BpConfig::splitNodeName($excludeTerm); + $excludes->add(Filter::equal('host.name', $hostName)); + } + + $hosts = Host::on($forConfig->getBackend()) + ->columns(['host.name', 'host.display_name']) + ->limit(50); + IcingaDbObject::applyIcingaDbRestrictions($hosts); + $hosts->filter(Filter::all( + $excludes, + Filter::any( + Filter::like('host.name', $suggestions->getSearchTerm()), + Filter::equal('host.name', $suggestions->getOriginalSearchValue()), + Filter::like('host.display_name', $suggestions->getSearchTerm()), + Filter::equal('host.display_name', $suggestions->getOriginalSearchValue()), + Filter::like('host.address', $suggestions->getSearchTerm()), + Filter::equal('host.address', $suggestions->getOriginalSearchValue()), + Filter::like('host.address6', $suggestions->getSearchTerm()), + Filter::equal('host.address6', $suggestions->getOriginalSearchValue()), + Filter::like('host.customvar_flat.flatvalue', $suggestions->getSearchTerm()), + Filter::equal('host.customvar_flat.flatvalue', $suggestions->getOriginalSearchValue()), + Filter::like('hostgroup.name', $suggestions->getSearchTerm()), + Filter::equal('hostgroup.name', $suggestions->getOriginalSearchValue()) + ) + )); + foreach ($hosts as $host) { + yield [ + 'search' => BpConfig::joinNodeName($host->name, 'Hoststatus'), + 'label' => $host->display_name, + 'class' => 'host' + ]; + } + })()); + + $this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest())); + } + + public function icingadbServiceAction() + { + $excludes = Filter::none(); + $forConfig = null; + if ($this->params->has('config')) { + $forConfig = $this->loadModifiedBpConfig(); + + if ($this->params->has('node')) { + $nodeName = $this->params->get('node'); + $node = $forConfig->getBpNode($nodeName); + + foreach ($node->getChildren() as $child) { + if ($child instanceof ServiceNode) { + $excludes->add(Filter::all( + Filter::equal('host.name', $child->getHostname()), + Filter::equal('service.name', $child->getServiceDescription()) + )); + } + } + } + } + + $suggestions = new TermSuggestions((function () use ($forConfig, $excludes, &$suggestions) { + foreach ($suggestions->getExcludeTerms() as $excludeTerm) { + [$hostName, $serviceName] = BpConfig::splitNodeName($excludeTerm); + if ($serviceName !== null && $serviceName !== 'Hoststatus') { + $excludes->add(Filter::all( + Filter::equal('host.name', $hostName), + Filter::equal('service.name', $serviceName) + )); + } + } + + $services = Service::on($forConfig->getBackend()) + ->columns(['host.name', 'host.display_name', 'service.name', 'service.display_name']) + ->limit(50); + IcingaDbObject::applyIcingaDbRestrictions($services); + $services->filter(Filter::all( + $excludes, + Filter::any( + Filter::like('host.name', $suggestions->getSearchTerm()), + Filter::equal('host.name', $suggestions->getOriginalSearchValue()), + Filter::like('host.display_name', $suggestions->getSearchTerm()), + Filter::equal('host.display_name', $suggestions->getOriginalSearchValue()), + Filter::like('service.name', $suggestions->getSearchTerm()), + Filter::equal('service.name', $suggestions->getOriginalSearchValue()), + Filter::like('service.display_name', $suggestions->getSearchTerm()), + Filter::equal('service.display_name', $suggestions->getOriginalSearchValue()), + Filter::like('service.customvar_flat.flatvalue', $suggestions->getSearchTerm()), + Filter::equal('service.customvar_flat.flatvalue', $suggestions->getOriginalSearchValue()), + Filter::like('servicegroup.name', $suggestions->getSearchTerm()), + Filter::equal('servicegroup.name', $suggestions->getOriginalSearchValue()) + ) + )); + foreach ($services as $service) { + yield [ + 'class' => 'service', + 'search' => BpConfig::joinNodeName($service->host->name, $service->name), + 'label' => sprintf( + $this->translate('%s on %s', ' on '), + $service->display_name, + $service->host->display_name + ) + ]; + } + })()); + + $this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest())); + } + + public function monitoringHostAction() + { + $excludes = LegacyFilter::matchAny(); + $forConfig = null; + if ($this->params->has('config')) { + $forConfig = $this->loadModifiedBpConfig(); + + if ($this->params->has('node')) { + $nodeName = $this->params->get('node'); + $node = $forConfig->getBpNode($nodeName); + + foreach ($node->getChildren() as $child) { + if ($child instanceof HostNode) { + $excludes->addFilter(LegacyFilter::where('host_name', $child->getHostname())); + } + } + } + } + + $suggestions = new TermSuggestions((function () use ($forConfig, $excludes, &$suggestions) { + foreach ($suggestions->getExcludeTerms() as $excludeTerm) { + [$hostName, $_] = BpConfig::splitNodeName($excludeTerm); + $excludes->addFilter(LegacyFilter::where('host_name', $hostName)); + } + + $hosts = (new HostStatus($forConfig->getBackend()->select(), ['host_name', 'host_display_name'])) + ->limit(50) + ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) + ->applyFilter(LegacyFilter::matchAny( + LegacyFilter::where('host_name', $suggestions->getSearchTerm()), + LegacyFilter::where('host_display_name', $suggestions->getSearchTerm()), + LegacyFilter::where('host_address', $suggestions->getSearchTerm()), + LegacyFilter::where('host_address6', $suggestions->getSearchTerm()), + LegacyFilter::where('_host_%', $suggestions->getSearchTerm()), + // This also forces a group by on the query, needed anyway due to the custom var filter + // above, which may return multiple rows because of the wildcard in the name filter. + LegacyFilter::where('hostgroup_name', $suggestions->getSearchTerm()), + LegacyFilter::where('hostgroup_alias', $suggestions->getSearchTerm()) + )); + if (! $excludes->isEmpty()) { + $hosts->applyFilter(LegacyFilter::not($excludes)); + } + + foreach ($hosts as $row) { + yield [ + 'search' => BpConfig::joinNodeName($row->host_name, 'Hoststatus'), + 'label' => $row->host_display_name, + 'class' => 'host' + ]; + } + })()); + + $this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest())); + } + + public function monitoringServiceAction() + { + $excludes = LegacyFilter::matchAny(); + $forConfig = null; + if ($this->params->has('config')) { + $forConfig = $this->loadModifiedBpConfig(); + + if ($this->params->has('node')) { + $nodeName = $this->params->get('node'); + $node = $forConfig->getBpNode($nodeName); + + foreach ($node->getChildren() as $child) { + if ($child instanceof ServiceNode) { + $excludes->addFilter(LegacyFilter::matchAll( + LegacyFilter::where('host_name', $child->getHostname()), + LegacyFilter::where('service_description', $child->getServiceDescription()) + )); + } + } + } + } + + $suggestions = new TermSuggestions((function () use ($forConfig, $excludes, &$suggestions) { + foreach ($suggestions->getExcludeTerms() as $excludeTerm) { + [$hostName, $serviceName] = BpConfig::splitNodeName($excludeTerm); + if ($serviceName !== null && $serviceName !== 'Hoststatus') { + $excludes->addFilter(LegacyFilter::matchAll( + LegacyFilter::where('host_name', $hostName), + LegacyFilter::where('service_description', $serviceName) + )); + } + } + + $services = (new ServiceStatus($forConfig->getBackend()->select(), [ + 'host_name', + 'host_display_name', + 'service_description', + 'service_display_name' + ])) + ->limit(50) + ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) + ->applyFilter(LegacyFilter::matchAny( + LegacyFilter::where('host_name', $suggestions->getSearchTerm()), + LegacyFilter::where('host_display_name', $suggestions->getSearchTerm()), + LegacyFilter::where('service_description', $suggestions->getSearchTerm()), + LegacyFilter::where('service_display_name', $suggestions->getSearchTerm()), + LegacyFilter::where('_service_%', $suggestions->getSearchTerm()), + // This also forces a group by on the query, needed anyway due to the custom var filter + // above, which may return multiple rows because of the wildcard in the name filter. + LegacyFilter::where('servicegroup_name', $suggestions->getSearchTerm()), + LegacyFilter::where('servicegroup_alias', $suggestions->getSearchTerm()) + )); + if (! $excludes->isEmpty()) { + $services->applyFilter(LegacyFilter::not($excludes)); + } + + foreach ($services as $row) { + yield [ + 'class' => 'service', + 'search' => BpConfig::joinNodeName($row->host_name, $row->service_description), + 'label' => sprintf( + $this->translate('%s on %s', ' on '), + $row->service_display_name, + $row->host_display_name + ) + ]; + } + })()); + + $this->getDocument()->addHtml($suggestions->forRequest($this->getServerRequest())); + } +} From 46cce05c0a66e44c0b915c9982d1df562efe0510 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 10:29:37 +0200 Subject: [PATCH 049/105] Add ipl-form compatible implementation of the state override element --- .../Web/Form/Element/IplStateOverrides.php | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 library/Businessprocess/Web/Form/Element/IplStateOverrides.php diff --git a/library/Businessprocess/Web/Form/Element/IplStateOverrides.php b/library/Businessprocess/Web/Form/Element/IplStateOverrides.php new file mode 100644 index 0000000..5b9ea16 --- /dev/null +++ b/library/Businessprocess/Web/Form/Element/IplStateOverrides.php @@ -0,0 +1,75 @@ +options = $options; + + return $this; + } + + /** + * Get the options to show + * + * @return array + */ + public function getOptions(): array + { + return $this->options; + } + + public function getValues() + { + $cleanedValue = parent::getValues(); + + if (! empty($cleanedValue)) { + foreach ($cleanedValue as $from => $to) { + if ((int) $from === (int) $to) { + unset($cleanedValue[$from]); + } + } + } + + return $cleanedValue; + } + + protected function assemble() + { + $states = $this->getOptions(); + foreach ($states as $state => $label) { + if ($state === 0) { + continue; + } + + $this->addElement('select', $state, [ + 'label' => $label, + 'value' => $state, + 'options' => [$state => $this->translate('Keep actual state')] + $states + ]); + } + } + + protected function registerAttributeCallbacks(Attributes $attributes) + { + parent::registerAttributeCallbacks($attributes); + + $this->getAttributes() + ->registerAttributeCallback('options', null, [$this, 'setOptions']); + } +} From 6dd8a51ce56c799b62d421634e8e0c9a0f517dd5 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 4 Aug 2023 14:03:02 +0200 Subject: [PATCH 050/105] Introduce new form validator for host/service terms --- .../Validator/HostServiceTermValidator.php | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php diff --git a/library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php b/library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php new file mode 100644 index 0000000..b141206 --- /dev/null +++ b/library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php @@ -0,0 +1,90 @@ +parent = $parent; + + return $this; + } + + public function isValid($terms) + { + if ($this->parent === null) { + throw new LogicException('Missing parent process. Cannot validate terms.'); + } + + if (! is_array($terms)) { + $terms = [$terms]; + } + + $testConfig = new BpConfig(); + + foreach ($terms as $term) { + /** @var Term $term */ + [$hostName, $serviceName] = BpConfig::splitNodeName($term->getSearchValue()); + if ($serviceName !== null && $serviceName !== 'Hoststatus') { + $node = $testConfig->createService($hostName, $serviceName); + } else { + $node = $testConfig->createHost($hostName); + if ($serviceName === null) { + $term->setSearchValue(BpConfig::joinNodeName($hostName, 'Hoststatus')); + } + } + + if ($this->parent->hasChild($term->getSearchValue())) { + $term->setMessage($this->translate('Already defined in this process')); + } else { + $testConfig->getNode('__unbound__') + ->addChild($node); + } + } + + if ($this->parent->getBpConfig()->getBackend() instanceof MonitoringBackend) { + MonitoringState::apply($testConfig); + } else { + IcingaDbState::apply($testConfig); + } + + foreach ($terms as $term) { + /** @var Term $term */ + $node = $testConfig->getNode($term->getSearchValue()); + if ($node->isMissing()) { + if ($node instanceof ServiceNode) { + $term->setMessage($this->translate('Service not found')); + } else { + $term->setMessage($this->translate('Host not found')); + } + } else { + $term->setLabel($node->getAlias()); + $term->setClass($node->getObjectClassName()); + } + } + } +} From da4edda2b31d292bfb7ee92b211855ae6ef65503 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 10:31:10 +0200 Subject: [PATCH 051/105] Re-introduce class `AddNodeForm` Rewritten from scratch. Now with ipl-form compatibility. --- application/forms/AddNodeForm.php | 410 ++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 application/forms/AddNodeForm.php diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php new file mode 100644 index 0000000..68299b7 --- /dev/null +++ b/application/forms/AddNodeForm.php @@ -0,0 +1,410 @@ +storage = $storage; + + return $this; + } + + /** + * Set the affected configuration + * + * @param BpConfig $bp + * + * @return $this + */ + public function setProcess(BpConfig $bp): self + { + $this->bp = $bp; + + return $this; + } + + /** + * Set the affected sub-process + * + * @param ?BpNode $node + * + * @return $this + */ + public function setParentNode(BpNode $node = null): self + { + $this->parent = $node; + + return $this; + } + + /** + * Set the user's session + * + * @param SessionNamespace $session + * + * @return $this + */ + public function setSession(SessionNamespace $session): self + { + $this->session = $session; + + return $this; + } + + protected function assemble() + { + if ($this->parent !== null) { + $title = sprintf($this->translate('Add a node to %s'), $this->parent->getAlias()); + $nodeTypes = [ + 'host' => $this->translate('Host'), + 'service' => $this->translate('Service'), + 'process' => $this->translate('Existing Process'), + 'new-process' => $this->translate('New Process') + ]; + } else { + $title = $this->translate('Add a new root node'); + if (! $this->bp->isEmpty()) { + $nodeTypes = [ + 'process' => $this->translate('Existing Process'), + 'new-process' => $this->translate('New Process') + ]; + } else { + $nodeTypes = []; + } + } + + $this->addHtml(new HtmlElement('h2', null, Text::create($title))); + + if (! empty($nodeTypes)) { + $this->addElement('select', 'node_type', [ + 'label' => $this->translate('Node type'), + 'options' => array_merge( + ['' => ' - ' . $this->translate('Please choose') . ' - '], + $nodeTypes + ), + 'disabledOptions' => [''], + 'class' => 'autosubmit', + 'required' => true, + 'ignore' => true + ]); + + $nodeType = $this->getPopulatedValue('node_type'); + } else { + $nodeType = 'new-process'; + } + + if ($nodeType === 'new-process') { + $this->assembleNewProcessElements(); + } elseif ($nodeType === 'process') { + $this->assembleExistingProcessElements(); + } elseif ($nodeType === 'host') { + $this->assembleHostElements(); + } elseif ($nodeType === 'service') { + $this->assembleServiceElements(); + } + + $this->addElement('submit', 'submit', [ + 'label' => $this->translate('Add Process') + ]); + } + + protected function assembleNewProcessElements(): void + { + $this->addElement('text', 'name', [ + 'required' => true, + 'ignore' => true, + 'label' => $this->translate('ID'), + 'description' => $this->translate('This is the unique identifier of this process'), + 'validators' => [ + 'callback' => function ($value, $validator) { + if ($this->parent !== null ? $this->parent->hasChild($value) : $this->bp->hasRootNode($value)) { + $validator->addMessage( + sprintf($this->translate('%s is already defined in this process'), $value) + ); + + return false; + } + + return true; + } + ] + ]); + + $this->addElement('text', 'alias', [ + 'label' => $this->translate('Display Name'), + 'description' => $this->translate( + 'Usually this name will be shown for this node. Equals ID if not given' + ), + ]); + + $this->addElement('select', 'operator', [ + 'required' => true, + 'label' => $this->translate('Operator'), + 'multiOptions' => Node::getOperators() + ]); + + $display = 1; + if (! $this->bp->isEmpty() && $this->bp->getMetadata()->isManuallyOrdered()) { + $rootNodes = self::applyManualSorting($this->bp->getRootNodes()); + $display = end($rootNodes)->getDisplay() + 1; + } + $this->addElement('select', 'display', [ + 'required' => true, + 'label' => $this->translate('Visualization'), + 'description' => $this->translate('Where to show this process'), + 'value' => $this->parent !== null ? '0' : "$display", + 'multiOptions' => [ + "$display" => $this->translate('Toplevel Process'), + '0' => $this->translate('Subprocess only'), + ] + ]); + + $this->addElement('text', 'infoUrl', [ + 'label' => $this->translate('Info URL'), + 'description' => $this->translate('URL pointing to more information about this node') + ]); + } + + protected function assembleExistingProcessElements(): void + { + $termValidator = function (array $terms) { + foreach ($terms as $term) { + /** @var TermInput\ValidatedTerm $term */ + $nodeName = $term->getSearchValue(); + if ($nodeName[0] === '@') { + if ($this->parent === null) { + $term->setMessage($this->translate('Imported nodes cannot be used as root nodes')); + } elseif (strpos($nodeName, ':') === false) { + $term->setMessage($this->translate('Missing node name')); + } else { + [$config, $nodeName] = Str::trimSplit(substr($nodeName, 1), ':', 2); + if (! $this->storage->hasProcess($config)) { + $term->setMessage($this->translate('Config does not exist or access has been denied')); + } else { + try { + $bp = $this->storage->loadProcess($config); + } catch (Exception $e) { + $term->setMessage( + sprintf($this->translate('Cannot load config: %s'), $e->getMessage()) + ); + } + + if (isset($bp)) { + if (! $bp->hasNode($nodeName)) { + $term->setMessage($this->translate('No node with this name found in config')); + } else { + $term->setLabel($bp->getNode($nodeName)->getAlias()); + } + } + } + } + } elseif (! $this->bp->hasNode($nodeName)) { + $term->setMessage($this->translate('No node with this name found in config')); + } else { + $term->setLabel($this->bp->getNode($nodeName)->getAlias()); + } + + if ($this->parent !== null && $this->parent->hasChild($term->getSearchValue())) { + $term->setMessage($this->translate('Already defined in this process')); + } + + if ($this->parent !== null && $term->getSearchValue() === $this->parent->getName()) { + $term->setMessage($this->translate('Results in a parent/child loop')); + } + } + }; + + $this->addElement( + (new TermInput('children')) + ->setRequired() + ->setVerticalTermDirection() + ->setLabel($this->translate('Process Nodes')) + ->setSuggestionUrl(Url::fromPath('businessprocess/suggestions/process', [ + 'node' => isset($this->parent) ? $this->parent->getName() : null, + 'config' => $this->bp->getName(), + 'showCompact' => true, + '_disableLayout' => true + ])) + ->on(TermInput::ON_ENRICH, $termValidator) + ->on(TermInput::ON_ADD, $termValidator) + ->on(TermInput::ON_PASTE, $termValidator) + ->on(TermInput::ON_SAVE, $termValidator) + ); + } + + protected function assembleHostElements(): void + { + if ($this->bp->getBackend() instanceof MonitoringBackend) { + $suggestionsPath = 'businessprocess/suggestions/monitoring-host'; + } else { + $suggestionsPath = 'businessprocess/suggestions/icingadb-host'; + } + + $this->addElement($this->createChildrenElementForObjects( + $this->translate('Hosts'), + $suggestionsPath + )); + + $this->addElement('checkbox', 'host_override', [ + 'ignore' => true, + 'class' => 'autosubmit', + 'label' => $this->translate('Override Host State') + ]); + if ($this->getPopulatedValue('host_override') === 'y') { + $this->addElement(new IplStateOverrides('stateOverrides', [ + 'label' => $this->translate('State Overrides'), + 'options' => [ + 0 => $this->translate('UP'), + 1 => $this->translate('DOWN'), + 99 => $this->translate('PENDING') + ] + ])); + } + } + + protected function assembleServiceElements(): void + { + if ($this->bp->getBackend() instanceof MonitoringBackend) { + $suggestionsPath = 'businessprocess/suggestions/monitoring-service'; + } else { + $suggestionsPath = 'businessprocess/suggestions/icingadb-service'; + } + + $this->addElement($this->createChildrenElementForObjects( + $this->translate('Services'), + $suggestionsPath + )); + + $this->addElement('checkbox', 'service_override', [ + 'ignore' => true, + 'class' => 'autosubmit', + 'label' => $this->translate('Override Service State') + ]); + if ($this->getPopulatedValue('service_override') === 'y') { + $this->addElement(new IplStateOverrides('stateOverrides', [ + 'label' => $this->translate('State Overrides'), + 'options' => [ + 0 => $this->translate('OK'), + 1 => $this->translate('WARNING'), + 2 => $this->translate('CRITICAL'), + 3 => $this->translate('UNKNOWN'), + 99 => $this->translate('PENDING'), + ] + ])); + } + } + + protected function createChildrenElementForObjects(string $label, string $suggestionsPath): TermInput + { + $termValidator = function (array $terms) { + (new HostServiceTermValidator()) + ->setParent($this->parent) + ->isValid($terms); + }; + + return (new TermInput('children')) + ->setRequired() + ->setLabel($label) + ->setVerticalTermDirection() + ->setSuggestionUrl(Url::fromPath($suggestionsPath, [ + 'node' => isset($this->parent) ? $this->parent->getName() : null, + 'config' => $this->bp->getName(), + 'showCompact' => true, + '_disableLayout' => true + ])) + ->on(TermInput::ON_ENRICH, $termValidator) + ->on(TermInput::ON_ADD, $termValidator) + ->on(TermInput::ON_PASTE, $termValidator) + ->on(TermInput::ON_SAVE, $termValidator); + } + + protected function onSuccess() + { + $changes = ProcessChanges::construct($this->bp, $this->session); + + $nodeType = $this->getValue('node_type'); + if (! $nodeType || $nodeType === 'new-process') { + $properties = $this->getValues(); + if (! $properties['alias']) { + unset($properties['alias']); + } + + if ($this->parent !== null) { + $properties['parentName'] = $this->parent->getName(); + } + + $changes->createNode(BpConfig::escapeName($this->getValue('name')), $properties); + } else { + $children = array_unique(array_map(function ($term) { + return $term->getSearchValue(); + }, $this->getElement('children')->getTerms())); + + if ($nodeType === 'host' || $nodeType === 'service') { + $stateOverrides = $this->getValue('stateOverrides'); + if (! empty($stateOverrides)) { + $childOverrides = []; + foreach ($children as $nodeName) { + $childOverrides[$nodeName] = $stateOverrides; + } + + $changes->modifyNode($this->parent, [ + 'stateOverrides' => array_merge($this->parent->getStateOverrides(), $childOverrides) + ]); + } + } + + if ($this->parent !== null) { + $changes->addChildrenToNode($children, $this->parent); + } else { + foreach ($children as $nodeName) { + $changes->copyNode($nodeName); + } + } + } + + unset($changes); + } +} From 4aac6580892475ec5ad894e19a208ffb64285b07 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 10:32:03 +0200 Subject: [PATCH 052/105] process/show: Utilize the new `AddNodeForm` --- application/controllers/ProcessController.php | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 4a6495e..f61fb89 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -6,6 +6,7 @@ use Icinga\Application\Modules\Module; use Icinga\Date\DateFormatter; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; +use Icinga\Module\Businessprocess\Forms\AddNodeForm; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Businessprocess\Renderer\Breadcrumb; @@ -268,7 +269,27 @@ class ProcessController extends Controller $canEdit = $bp->getMetadata()->canModify(); - if ($action === 'cleanup' && $canEdit) { + if ($action === 'add' && $canEdit) { + $form = (new AddNodeForm()) + ->setProcess($bp) + ->setParentNode($node) + ->setStorage($this->storage()) + ->setSession($this->session()) + ->on(AddNodeForm::ON_SUCCESS, function () { + $this->redirectNow(Url::fromRequest()->without('action')); + }) + ->handleRequest($this->getServerRequest()); + + if ($form->hasElement('children')) { + foreach ($form->getElement('children')->prepareMultipartUpdate($this->getServerRequest()) as $update) { + if (! is_array($update)) { + $update = [$update]; + } + + $this->addPart(...$update); + } + } + } elseif ($action === 'cleanup' && $canEdit) { $form = $this->loadForm('CleanupNode') ->setSuccessUrl(Url::fromRequest()->without('action')) ->setProcess($bp) @@ -341,8 +362,11 @@ class ProcessController extends Controller return; } - if ($this->params->get('action')) { - $this->setAutorefreshInterval(45); + if ($this->params->has('action')) { + if ($this->params->get('action') !== 'add') { + // The new add form uses the term input, which doesn't support value persistence across refreshes + $this->setAutorefreshInterval(45); + } } else { $this->setAutorefreshInterval(10); } From 1b837c72a3b310778703b1ff77319d8e216a8b13 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 17:54:17 +0200 Subject: [PATCH 053/105] Drop class `EditNodeForm` --- application/controllers/ProcessController.php | 8 - application/forms/EditNodeForm.php | 400 ------------------ 2 files changed, 408 deletions(-) delete mode 100644 application/forms/EditNodeForm.php diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index f61fb89..f9dcf61 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -295,14 +295,6 @@ class ProcessController extends Controller ->setProcess($bp) ->setSession($this->session()) ->handleRequest(); - } elseif ($action === 'editmonitored' && $canEdit) { - $form = $this->loadForm('EditNode') - ->setSuccessUrl(Url::fromRequest()->without('action')) - ->setProcess($bp) - ->setNode($bp->getNode($this->params->get('editmonitorednode'))) - ->setParentNode($node) - ->setSession($this->session()) - ->handleRequest(); } elseif ($action === 'delete' && $canEdit) { $form = $this->loadForm('DeleteNode') ->setSuccessUrl(Url::fromRequest()->without('action')) diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php deleted file mode 100644 index a4cd919..0000000 --- a/application/forms/EditNodeForm.php +++ /dev/null @@ -1,400 +0,0 @@ -host, $suffix] = BpConfig::splitNodeName($this->getNode()->getName()); - if ($suffix !== 'Hoststatus') { - $this->service = $suffix; - } - - $view = $this->getView(); - $nodeName = $this->getNode()->getAlias() ?? $this->getNode()->getName(); - $this->addHtml( - '

' . $view->escape( - sprintf($this->translate('Modify "%s"'), $nodeName) - ) . '

' - ); - - $monitoredNodeType = null; - if ($this->isService()) { - $monitoredNodeType = 'service'; - } else { - $monitoredNodeType = 'host'; - } - - $type = $this->selectNodeType($monitoredNodeType); - switch ($type) { - case 'host': - $this->selectHost(); - break; - case 'service': - $this->selectService(); - break; - case 'process': - $this->selectProcess(); - break; - case 'new-process': - $this->addNewProcess(); - break; - case null: - $this->setSubmitLabel($this->translate('Next')); - return; - } - } - - protected function isService() - { - if (strpos($this->getNode()->getName(), ';Hoststatus')) { - return false; - } - return true; - } - - protected function addNewProcess() - { - $this->addElement('text', 'name', array( - 'label' => $this->translate('ID'), - 'required' => true, - 'disabled' => true, - 'description' => $this->translate( - 'This is the unique identifier of this process' - ), - )); - - $this->addElement('text', 'alias', array( - 'label' => $this->translate('Display Name'), - 'description' => $this->translate( - 'Usually this name will be shown for this node. Equals ID' - . ' if not given' - ), - )); - - $this->addElement('select', 'operator', array( - 'label' => $this->translate('Operator'), - 'required' => true, - 'multiOptions' => Node::getOperators() - )); - - $display = $this->getNode()->getDisplay() ?: 1; - $this->addElement('select', 'display', array( - 'label' => $this->translate('Visualization'), - 'required' => true, - 'description' => $this->translate( - 'Where to show this process' - ), - 'value' => $display, - 'multiOptions' => array( - "$display" => $this->translate('Toplevel Process'), - '0' => $this->translate('Subprocess only'), - ) - )); - - $this->addElement('text', 'infoUrl', array( - 'label' => $this->translate('Info URL'), - 'description' => $this->translate( - 'URL pointing to more information about this node' - ) - )); - } - - /** - * @return string|null - */ - protected function selectNodeType($monitoredNodeType = null) - { - if ($this->hasParentNode()) { - $this->addElement('hidden', 'node_type', [ - 'disabled' => true, - 'decorators' => ['ViewHelper'], - 'value' => $monitoredNodeType - ]); - - return $monitoredNodeType; - } elseif (! $this->hasProcesses()) { - $this->addElement('hidden', 'node_type', array( - 'ignore' => true, - 'decorators' => array('ViewHelper'), - 'value' => 'new-process' - )); - - return 'new-process'; - } - } - - protected function selectHost() - { - $this->addElement('select', 'children', array( - 'required' => true, - 'value' => $this->getNode()->getName(), - 'multiOptions' => $this->enumHostList(), - 'label' => $this->translate('Host'), - 'description' => $this->translate('The host for this business process node'), - 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] - )); - - $this->addHostOverrideCheckbox(); - $hostOverrideSent = $this->getSentValue('host_override'); - if ($hostOverrideSent === '1' - || ($hostOverrideSent === null && $this->getElement('host_override')->isChecked()) - ) { - $this->addHostOverrideElement(); - } - } - - protected function selectService() - { - $this->addHostElement(); - - if ($this->getSentValue('hosts') === null) { - $this->addServicesElement($this->host); - $this->addServiceOverrideCheckbox(); - if ($this->getElement('service_override')->isChecked() || $this->getSentValue('service_override') === '1') { - $this->addServiceOverrideElement(); - } - } elseif ($host = $this->getSentValue('hosts')) { - $this->addServicesElement($host); - $this->addServiceOverrideCheckbox(); - if ($this->getSentValue('service_override') === '1') { - $this->addServiceOverrideElement(); - } - } else { - $this->setSubmitLabel($this->translate('Next')); - } - } - - protected function addHostElement() - { - $this->addElement('select', 'hosts', array( - 'label' => $this->translate('Host'), - 'required' => true, - 'ignore' => true, - 'class' => 'autosubmit', - 'multiOptions' => $this->optionalEnum($this->enumHostForServiceList()), - )); - - $this->getElement('hosts')->setValue($this->host); - } - - protected function addHostOverrideCheckbox() - { - $this->addElement('checkbox', 'host_override', [ - 'ignore' => true, - 'class' => 'autosubmit', - 'value' => ! empty($this->parent->getStateOverrides($this->node->getName())), - 'label' => $this->translate('Override Host State'), - 'description' => $this->translate('Enable host state overrides') - ]); - } - - protected function addHostOverrideElement() - { - $this->addElement('stateOverrides', 'stateOverrides', [ - 'required' => true, - 'states' => $this->enumHostStateList(), - 'value' => $this->parent->getStateOverrides($this->node->getName()), - 'label' => $this->translate('State Overrides') - ]); - } - - protected function addServicesElement($host) - { - $this->addElement('select', 'children', array( - 'required' => true, - 'value' => $this->getNode()->getName(), - 'multiOptions' => $this->enumServiceList($host), - 'label' => $this->translate('Service'), - 'description' => $this->translate('The service for this business process node'), - 'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]] - )); - } - - protected function addServiceOverrideCheckbox() - { - $this->addElement('checkbox', 'service_override', [ - 'ignore' => true, - 'class' => 'autosubmit', - 'value' => ! empty($this->parent->getStateOverrides($this->node->getName())), - 'label' => $this->translate('Override Service State'), - 'description' => $this->translate('Enable service state overrides') - ]); - } - - protected function addServiceOverrideElement() - { - $this->addElement('stateOverrides', 'stateOverrides', [ - 'required' => true, - 'states' => $this->enumServiceStateList(), - 'value' => $this->parent->getStateOverrides($this->node->getName()), - 'label' => $this->translate('State Overrides') - ]); - } - - protected function selectProcess() - { - $this->addElement('multiselect', 'children', array( - 'label' => $this->translate('Process nodes'), - 'required' => true, - 'size' => 8, - 'multiOptions' => $this->enumProcesses(), - 'description' => $this->translate( - 'Other processes that should be part of this business process node' - ) - )); - } - - /** - * @param BpNode|null $node - * @return $this - */ - public function setParentNode(BpNode $node = null) - { - $this->parent = $node; - return $this; - } - - /** - * @return bool - */ - public function hasParentNode() - { - return $this->parent !== null; - } - - protected function hasProcesses() - { - return count($this->enumProcesses()) > 0; - } - - protected function enumProcesses() - { - $list = array(); - - $parents = array(); - - if ($this->hasParentNode()) { - $this->collectAllParents($this->parent, $parents); - $parents[$this->parent->getName()] = $this->parent; - } - - foreach ($this->bp->getNodes() as $node) { - if ($node instanceof BpNode && ! isset($parents[$node->getName()])) { - $list[$node->getName()] = $node->getName(); // display name? - } - } - - return $list; - } - - /** - * Collect the given node's parents recursively into the given array by their names - * - * @param BpNode $node - * @param BpNode[] $parents - */ - protected function collectAllParents(BpNode $node, array &$parents) - { - foreach ($node->getParents() as $parent) { - $parents[$parent->getName()] = $parent; - $this->collectAllParents($parent, $parents); - } - } - - /** - * @param Node $node - * @return $this - */ - public function setNode(Node $node) - { - $this->node = $node; - return $this; - } - - public function getNode() - { - return $this->node; - } - - public function onSuccess() - { - $changes = ProcessChanges::construct($this->bp, $this->session); - - $changes->deleteNode($this->node, $this->parent->getName()); - - switch ($this->getValue('node_type')) { - case 'host': - case 'service': - $stateOverrides = $this->getValue('stateOverrides') ?: []; - if (! empty($stateOverrides)) { - $stateOverrides = array_merge( - $this->parent->getStateOverrides(), - [$this->getValue('children') => $stateOverrides] - ); - } else { - $stateOverrides = $this->parent->getStateOverrides(); - unset($stateOverrides[$this->getValue('children')]); - } - - $changes->modifyNode($this->parent, ['stateOverrides' => $stateOverrides]); - // Fallthrough - case 'process': - $changes->addChildrenToNode($this->getValue('children'), $this->parent); - break; - case 'new-process': - $properties = $this->getValues(); - unset($properties['name']); - if ($this->hasParentNode()) { - $properties['parentName'] = $this->parent->getName(); - } - $changes->createNode($this->getValue('name'), $properties); - break; - } - - // Trigger session destruction to make sure it get's stored. - // TODO: figure out why this is necessary, might be an unclean shutdown on redirect - unset($changes); - - parent::onSuccess(); - } - - public function isValid($data) - { - // Don't allow to override disabled elements. This is probably too harsh - // but also wouldn't be necessary if this would be a Icinga\Web\Form... - foreach ($this->getElements() as $element) { - /** @var \Zend_Form_Element $element */ - if ($element->getAttrib('disabled')) { - $data[$element->getName()] = $element->getValue(); - } - } - - return parent::isValid($data); - } -} From 9c84764157e23d7a8967357d7a9bd22daea9f420 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 17:56:36 +0200 Subject: [PATCH 054/105] BpNode: Re-index childnames upon node removal --- library/Businessprocess/BpNode.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 419f836..4b67622 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -173,6 +173,8 @@ class BpNode extends Node if (! empty($this->children)) { unset($this->children[$name]); } + + $this->childNames = array_values($this->childNames); } return $this; From d9c6debfa9b84aae524184ae83dbb985504d7d7f Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 4 Aug 2023 14:01:54 +0200 Subject: [PATCH 055/105] ServiceNode: Change alias to ` on ` --- library/Businessprocess/ServiceNode.php | 9 ++++++++- test/php/library/Businessprocess/ServiceNodeTest.php | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/library/Businessprocess/ServiceNode.php b/library/Businessprocess/ServiceNode.php index cba6acf..c80b984 100644 --- a/library/Businessprocess/ServiceNode.php +++ b/library/Businessprocess/ServiceNode.php @@ -3,9 +3,12 @@ namespace Icinga\Module\Businessprocess; use Icinga\Module\Businessprocess\Web\Url; +use ipl\I18n\Translation; class ServiceNode extends MonitoredNode { + use Translation; + protected $hostname; /** @var string Alias of the host */ @@ -69,7 +72,11 @@ class ServiceNode extends MonitoredNode return null; } - return $this->getHostAlias() . ': ' . $this->alias; + return sprintf( + $this->translate('%s on %s', ' on '), + $this->alias, + $this->getHostAlias() + ); } public function getUrl() diff --git a/test/php/library/Businessprocess/ServiceNodeTest.php b/test/php/library/Businessprocess/ServiceNodeTest.php index d56529d..62c1605 100644 --- a/test/php/library/Businessprocess/ServiceNodeTest.php +++ b/test/php/library/Businessprocess/ServiceNodeTest.php @@ -27,7 +27,7 @@ class ServiceNodeTest extends BaseTestCase public function testReturnsCorrectAlias() { $this->assertEquals( - 'localhost: ping <> pong', + 'ping <> pong on localhost', $this->pingOnLocalhost()->getAlias() ); } @@ -36,7 +36,7 @@ class ServiceNodeTest extends BaseTestCase { $this->assertEquals( '
' - . 'localhost: ping <> pong', + . 'ping <> pong on localhost', $this->pingOnLocalhost()->getLink()->render() ); } From 890df4be7c3a79c9fd2745b72484c985b88612df Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 3 Aug 2023 17:56:13 +0200 Subject: [PATCH 056/105] Re-introduce class `EditNodeForm` Rewritten from scratch. Now with ipl-form compatibility. --- application/controllers/ProcessController.php | 11 + application/forms/EditNodeForm.php | 315 ++++++++++++++++++ 2 files changed, 326 insertions(+) create mode 100644 application/forms/EditNodeForm.php diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index f9dcf61..06e5bb8 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -7,6 +7,7 @@ use Icinga\Date\DateFormatter; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\Forms\AddNodeForm; +use Icinga\Module\Businessprocess\Forms\EditNodeForm; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Businessprocess\Renderer\Breadcrumb; @@ -295,6 +296,16 @@ class ProcessController extends Controller ->setProcess($bp) ->setSession($this->session()) ->handleRequest(); + } elseif ($action === 'editmonitored' && $canEdit) { + $form = (new EditNodeForm()) + ->setProcess($bp) + ->setNode($bp->getNode($this->params->get('editmonitorednode'))) + ->setParentNode($node) + ->setSession($this->session()) + ->on(EditNodeForm::ON_SUCCESS, function () { + $this->redirectNow(Url::fromRequest()->without(['action', 'editmonitorednode'])); + }) + ->handleRequest($this->getServerRequest()); } elseif ($action === 'delete' && $canEdit) { $form = $this->loadForm('DeleteNode') ->setSuccessUrl(Url::fromRequest()->without('action')) diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php new file mode 100644 index 0000000..bd1592b --- /dev/null +++ b/application/forms/EditNodeForm.php @@ -0,0 +1,315 @@ +bp = $bp; + + return $this; + } + + /** + * Set the affected node + * + * @param Node $node + * + * @return $this + */ + public function setNode(Node $node): self + { + $this->node = $node; + + $this->populate([ + 'node-search' => $node->getName(), + 'node-label' => $node->getAlias() + ]); + + return $this; + } + + /** + * Set the affected sub-process + * + * @param ?BpNode $node + * + * @return $this + */ + public function setParentNode(BpNode $node = null): self + { + $this->parent = $node; + + if ($this->node !== null) { + $stateOverrides = $this->parent->getStateOverrides($this->node->getName()); + if (! empty($stateOverrides)) { + $this->populate([ + 'overrideStates' => 'y', + 'stateOverrides' => $stateOverrides + ]); + } + } + + return $this; + } + + /** + * Set the user's session + * + * @param SessionNamespace $session + * + * @return $this + */ + public function setSession(SessionNamespace $session): self + { + $this->session = $session; + + return $this; + } + + /** + * Identify and return the node the user has chosen + * + * @return Node + */ + protected function identifyChosenNode(): Node + { + $userInput = $this->getPopulatedValue('node'); + $nodeName = $this->getPopulatedValue('node-search'); + $nodeLabel = $this->getPopulatedValue('node-label'); + + if ($nodeName && $userInput === $nodeLabel) { + // User accepted a suggestion and didn't change it manually + $node = $this->bp->getNode($nodeName); + } elseif ($userInput && (! $nodeLabel || $userInput !== $nodeLabel)) { + // User didn't choose a suggestion or changed it manually + $node = $this->bp->getNode(BpConfig::joinNodeName($userInput, 'Hoststatus')); + } else { + // If the search and user input are both empty, it can only be the initial value + $node = $this->node; + } + + return $node; + } + + protected function assemble() + { + $this->addHtml(new HtmlElement('h2', null, FormattedString::create( + $this->translate('Modify "%s"'), + $this->node->getAlias() ?? $this->node->getName() + ))); + + if ($this->node instanceof ServiceNode) { + $this->assembleServiceElements(); + } else { + $this->assembleHostElements(); + } + + $this->addElement('submit', 'btn_submit', [ + 'label' => $this->translate('Save Changes') + ]); + } + + protected function assembleServiceElements(): void + { + if ($this->bp->getBackend() instanceof MonitoringBackend) { + $suggestionsPath = 'businessprocess/suggestions/monitoring-service'; + } else { + $suggestionsPath = 'businessprocess/suggestions/icingadb-service'; + } + + $node = $this->identifyChosenNode(); + + $this->addHtml($this->createSearchInput( + $this->translate('Service'), + $node->getAlias() ?? $node->getName(), + $suggestionsPath + )); + + $this->addElement('checkbox', 'overrideStates', [ + 'ignore' => true, + 'class' => 'autosubmit', + 'label' => $this->translate('Override Service State') + ]); + if ($this->getPopulatedValue('overrideStates') === 'y') { + $this->addElement(new IplStateOverrides('stateOverrides', [ + 'label' => $this->translate('State Overrides'), + 'options' => [ + 0 => $this->translate('OK'), + 1 => $this->translate('WARNING'), + 2 => $this->translate('CRITICAL'), + 3 => $this->translate('UNKNOWN'), + 99 => $this->translate('PENDING'), + ] + ])); + } + } + + protected function assembleHostElements(): void + { + if ($this->bp->getBackend() instanceof MonitoringBackend) { + $suggestionsPath = 'businessprocess/suggestions/monitoring-host'; + } else { + $suggestionsPath = 'businessprocess/suggestions/icingadb-host'; + } + + $node = $this->identifyChosenNode(); + + $this->addHtml($this->createSearchInput( + $this->translate('Host'), + $node->getAlias() ?? $node->getName(), + $suggestionsPath + )); + + $this->addElement('checkbox', 'overrideStates', [ + 'ignore' => true, + 'class' => 'autosubmit', + 'label' => $this->translate('Override Host State') + ]); + if ($this->getPopulatedValue('overrideStates') === 'y') { + $this->addElement(new IplStateOverrides('stateOverrides', [ + 'label' => $this->translate('State Overrides'), + 'options' => [ + 0 => $this->translate('UP'), + 1 => $this->translate('DOWN'), + 99 => $this->translate('PENDING') + ] + ])); + } + } + + protected function createSearchInput(string $label, string $value, string $suggestionsPath): ValidHtml + { + $userInput = $this->createElement('text', 'node', [ + 'ignore' => true, + 'required' => true, + 'autocomplete' => 'off', + 'label' => $label, + 'value' => $value, + 'data-enrichment-type' => 'completion', + 'data-term-suggestions' => '#node-suggestions', + 'data-suggest-url' => Url::fromPath($suggestionsPath, [ + 'node' => isset($this->parent) ? $this->parent->getName() : null, + 'config' => $this->bp->getName(), + 'showCompact' => true, + '_disableLayout' => true + ]), + 'validators' => ['callback' => function ($_, $validator) { + $newName = $this->identifyChosenNode()->getName(); + if ($newName === $this->node->getName()) { + return true; + } + + $term = new ValidatedTerm($newName); + + (new HostServiceTermValidator()) + ->setParent($this->parent) + ->isValid($term); + + if (! $term->isValid()) { + $validator->addMessage($term->getMessage()); + return false; + } + + return true; + }] + ]); + + $fieldset = new HtmlElement('fieldset'); + + $searchInput = $this->createElement('hidden', 'node-search', ['ignore' => true]); + $this->registerElement($searchInput); + $fieldset->addHtml($searchInput); + + $labelInput = $this->createElement('hidden', 'node-label', ['ignore' => true]); + $this->registerElement($labelInput); + $fieldset->addHtml($labelInput); + + $this->registerElement($userInput); + $this->decorate($userInput); + + $fieldset->addHtml( + $userInput, + new HtmlElement('div', Attributes::create([ + 'id' => 'node-suggestions', + 'class' => 'search-suggestions' + ])) + ); + + return $fieldset; + } + + protected function onSuccess() + { + $changes = ProcessChanges::construct($this->bp, $this->session); + + $children = $this->parent->getChildNames(); + $previousPos = array_search($this->node->getName(), $children, true); + $node = $this->identifyChosenNode(); + $nodeName = $node->getName(); + + $changes->deleteNode($this->node, $this->parent->getName()); + $changes->addChildrenToNode([$nodeName], $this->parent); + + $stateOverrides = $this->getValue('stateOverrides'); + if (! empty($stateOverrides)) { + $changes->modifyNode($this->parent, [ + 'stateOverrides' => array_merge($this->parent->getStateOverrides(), [ + $nodeName => $stateOverrides + ]) + ]); + } + + if ($this->bp->getMetadata()->isManuallyOrdered() && ($newPos = count($children) - 1) > $previousPos) { + $changes->moveNode( + $node, + $newPos, + $previousPos, + $this->parent->getName(), + $this->parent->getName() + ); + } + + unset($changes); + } +} From 0ea04f898fcfa12f8ce7179eb920ed5748a6c57d Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 4 Aug 2023 14:06:53 +0200 Subject: [PATCH 057/105] Drop obsolete class `NoDuplicateChildrenValidator` --- .../NoDuplicateChildrenValidator.php | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 library/Businessprocess/Web/Form/Validator/NoDuplicateChildrenValidator.php diff --git a/library/Businessprocess/Web/Form/Validator/NoDuplicateChildrenValidator.php b/library/Businessprocess/Web/Form/Validator/NoDuplicateChildrenValidator.php deleted file mode 100644 index 9676de0..0000000 --- a/library/Businessprocess/Web/Form/Validator/NoDuplicateChildrenValidator.php +++ /dev/null @@ -1,57 +0,0 @@ -form = $form; - $this->bp = $bp; - $this->parent = $parent; - - $this->_messageVariables['label'] = 'label'; - $this->_messageTemplates = [ - self::CHILD_FOUND => mt('businessprocess', '%label% is already defined in this process') - ]; - } - - public function isValid($value) - { - if ($this->parent === null) { - $found = $this->bp->hasRootNode($value); - } elseif ($this->form instanceof EditNodeForm && $this->form->getNode()->getName() === $value) { - $found = false; - } else { - $found = $this->parent->hasChild($value); - } - - if (! $found) { - return true; - } - - $this->label = $this->form->getElement('children')->getMultiOptions()[$value]; - $this->_error(self::CHILD_FOUND); - return false; - } -} From 30d952ae0a12f70f5a9fcf47a76b1bc8732103e2 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 4 Aug 2023 14:08:17 +0200 Subject: [PATCH 058/105] Drop obsolete form element class `StateOverrides` --- .../Web/Form/Element/StateOverrides.php | 55 ------------------- public/css/module.less | 23 -------- 2 files changed, 78 deletions(-) delete mode 100644 library/Businessprocess/Web/Form/Element/StateOverrides.php diff --git a/library/Businessprocess/Web/Form/Element/StateOverrides.php b/library/Businessprocess/Web/Form/Element/StateOverrides.php deleted file mode 100644 index c2216c0..0000000 --- a/library/Businessprocess/Web/Form/Element/StateOverrides.php +++ /dev/null @@ -1,55 +0,0 @@ -states = $states; - - return $this; - } - - /** - * Get the overridable states - * - * @return array - */ - public function getStates() - { - return $this->states; - } - - public function init() - { - $this->setIsArray(true); - } - - public function setValue($value) - { - $cleanedValue = []; - - if (! empty($value)) { - foreach ($value as $from => $to) { - if ((int) $from !== (int) $to) { - $cleanedValue[$from] = $to; - } - } - } - - return parent::setValue($cleanedValue); - } -} diff --git a/public/css/module.less b/public/css/module.less index 500a137..f048863 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -869,29 +869,6 @@ form.bp-form { } } - #stateOverrides-element { - display: inline-table; - table-layout: fixed; - border-spacing: .5em; - padding: 0; - - label { - display: table-row; - - span, select { - display: table-cell; - } - - span { - width: 10em; - } - - select { - width: 26em; - } - } - } - fieldset { min-width: 36em; } From b8d5f0de2be2467861cecb0eea07f6edca61085e Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Fri, 4 Aug 2023 14:11:55 +0200 Subject: [PATCH 059/105] Drop unused trait `EnumList` --- library/Businessprocess/Common/EnumList.php | 170 -------------------- 1 file changed, 170 deletions(-) delete mode 100644 library/Businessprocess/Common/EnumList.php diff --git a/library/Businessprocess/Common/EnumList.php b/library/Businessprocess/Common/EnumList.php deleted file mode 100644 index 3419505..0000000 --- a/library/Businessprocess/Common/EnumList.php +++ /dev/null @@ -1,170 +0,0 @@ -useIcingaDbBackend()) { - $names = (new IcingaDbObject())->yieldHostnames(); - } else { - $names = $this->backend - ->select() - ->from('hostStatus', ['hostname' => 'host_name']) - ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) - ->order('host_name') - ->getQuery() - ->fetchColumn(); - } - - // fetchPairs doesn't seem to work when using the same column with - // different aliases twice - $res = array(); - foreach ($names as $name) { - $res[$name] = $name; - } - - return $res; - } - - protected function enumHostList() - { - if ($this->useIcingaDbBackend()) { - $names = (new IcingaDbObject())->yieldHostnames(); - } else { - $names = $this->backend - ->select() - ->from('hostStatus', ['hostname' => 'host_name']) - ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) - ->order('host_name') - ->getQuery() - ->fetchColumn(); - } - - // fetchPairs doesn't seem to work when using the same column with - // different aliases twice - $res = array(); - foreach ($names as $name) { - $res[BpConfig::joinNodeName($name, 'Hoststatus')] = $name; - } - - return $res; - } - - protected function enumServiceList($host) - { - if ($this->useIcingaDbBackend()) { - $names = (new IcingaDbObject())->yieldServicenames($host); - } else { - $names = $this->backend - ->select() - ->from('serviceStatus', ['service' => 'service_description']) - ->where('host_name', $host) - ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) - ->order('service_description') - ->getQuery() - ->fetchColumn(); - } - - $services = array(); - foreach ($names as $name) { - $services[BpConfig::joinNodeName($host, $name)] = $name; - } - - return $services; - } - - protected function enumHostListByFilter($filter) - { - if ($this->useIcingaDbBackend()) { - $names = (new IcingaDbObject())->yieldHostnames($filter); - } else { - $names = $this->backend - ->select() - ->from('hostStatus', ['hostname' => 'host_name']) - ->applyFilter(Filter::fromQueryString($filter)) - ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) - ->order('host_name') - ->getQuery() - ->fetchColumn(); - } - - // fetchPairs doesn't seem to work when using the same column with - // different aliases twice - $res = array(); - foreach ($names as $name) { - $res[BpConfig::joinNodeName($name, 'Hoststatus')] = $name; - } - - return $res; - } - - protected function enumServiceListByFilter($filter) - { - $services = array(); - - if ($this->useIcingaDbBackend()) { - $objects = (new IcingaDbObject())->fetchServices($filter); - foreach ($objects as $object) { - $services[BpConfig::joinNodeName($object->host->name, $object->name)] - = $object->host->name . ':' . $object->name; - } - } else { - $objects = $this->backend - ->select() - ->from('serviceStatus', ['host' => 'host_name', 'service' => 'service_description']) - ->applyFilter(Filter::fromQueryString($filter)) - ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) - ->order('service_description') - ->getQuery() - ->fetchAll(); - foreach ($objects as $object) { - $services[BpConfig::joinNodeName($object->host, $object->service)] - = $object->host . ':' . $object->service; - } - } - - return $services; - } - - protected function enumHostStateList() - { - $hostStateList = [ - 0 => $this->translate('UP'), - 1 => $this->translate('DOWN'), - 99 => $this->translate('PENDING') - ]; - - return $hostStateList; - } - - protected function enumServiceStateList() - { - $serviceStateList = [ - 0 => $this->translate('OK'), - 1 => $this->translate('WARNING'), - 2 => $this->translate('CRITICAL'), - 3 => $this->translate('UNKNOWN'), - 99 => $this->translate('PENDING'), - ]; - - return $serviceStateList; - } - - protected function useIcingaDbBackend() - { - if (Module::exists('icingadb')) { - return ! $this->bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend(); - } - - return false; - } -} From 892347627732216d88e2e89c6da60431ad3297ca Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Thu, 10 Aug 2023 10:30:06 +0200 Subject: [PATCH 060/105] BpNode::getMissingChildren(): Use child name if alias not given Host/Service alias is optional and null as default --- library/Businessprocess/BpNode.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 4b67622..9133eec 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -277,11 +277,11 @@ class BpNode extends Node foreach ($this->getChildren() as $child) { if ($child->isMissing()) { - $missing[$child->getAlias()] = $child; + $missing[$child->getAlias() ?? $child->getName()] = $child; } foreach ($child->getMissingChildren() as $m) { - $missing[$m->getAlias()] = $m; + $missing[$m->getAlias() ?? $m->getName()] = $m; } } From 661bff8a9b8a1f1422e316d602dd794a529d85e6 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 19 Jun 2023 14:17:52 +0200 Subject: [PATCH 061/105] workflows: Add phpstan --- .github/workflows/php.yml | 14 ++++++++++++-- phpstan.neon | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 phpstan.neon diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 45fc836..eded62d 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - php: ['7.2', '7.3', '7.4', '8.0', '8.1'] + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] os: ['ubuntu-latest'] steps: @@ -31,7 +31,13 @@ jobs: tools: phpcs - name: Setup dependencies - run: composer require -n --no-progress overtrue/phplint + run: | + composer require -n --no-progress overtrue/phplint + git clone --depth 1 https://github.com/Icinga/icingaweb2.git vendor/icingaweb2 + git clone --depth 1 https://github.com/Icinga/icingadb-web.git vendor/icingadb-web + git clone --depth 1 https://github.com/Icinga/icingaweb2-module-director.git vendor/icingaweb2-module-director + git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-library.git vendor/icinga-php-library + git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git vendor/icinga-php-thirdparty - name: PHP Lint if: success() || matrix.allow_failure @@ -41,6 +47,10 @@ jobs: if: success() || matrix.allow_failure run: phpcs + - name: PHPStan + uses: php-actions/phpstan@v3 + if: success() || matrix.allow_failure + test: name: Unit tests with php ${{ matrix.php }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..9698adb --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,21 @@ +parameters: + level: 5 + + checkFunctionNameCase: true + checkInternalClassCaseSensitivity: true + treatPhpDocTypesAsCertain: false + + paths: + - application + - library + + scanDirectories: + - vendor + + ignoreErrors: + - '#Unsafe usage of new static\(\)#' + + universalObjectCratesClasses: + - Icinga\Web\View + - ipl\Orm\Model + - Icinga\Module\Monitoring\Object\MonitoredObject From 9e67b56bca59c6262cb4615b36312233626845ca Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 12 Jul 2023 09:40:03 +0200 Subject: [PATCH 062/105] RenderedProcessActionBar: Remove unused constructor param `$auth` --- application/controllers/ProcessController.php | 2 +- .../Businessprocess/Web/Component/RenderedProcessActionBar.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 06e5bb8..44429df 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -199,7 +199,7 @@ class ProcessController extends Controller $controls->add(Breadcrumb::create(clone $renderer)); if (! $this->showFullscreen && ! $this->view->compact) { $controls->add( - new RenderedProcessActionBar($bp, $renderer, $this->Auth(), $this->url()) + new RenderedProcessActionBar($bp, $renderer, $this->url()) ); } diff --git a/library/Businessprocess/Web/Component/RenderedProcessActionBar.php b/library/Businessprocess/Web/Component/RenderedProcessActionBar.php index 7ad6ad6..41fa0f8 100644 --- a/library/Businessprocess/Web/Component/RenderedProcessActionBar.php +++ b/library/Businessprocess/Web/Component/RenderedProcessActionBar.php @@ -12,7 +12,7 @@ use ipl\Web\Widget\Icon; class RenderedProcessActionBar extends ActionBar { - public function __construct(BpConfig $config, Renderer $renderer, Auth $auth, Url $url) + public function __construct(BpConfig $config, Renderer $renderer, Url $url) { $meta = $config->getMetadata(); From e638fade56a22928c59705f8f5c743aa4135662c Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 12 Jul 2023 10:08:08 +0200 Subject: [PATCH 063/105] Renderer: Fix that `!empty($elements)` is always true --- library/Businessprocess/Renderer/Renderer.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/Businessprocess/Renderer/Renderer.php b/library/Businessprocess/Renderer/Renderer.php index 6e68da4..9917ed6 100644 --- a/library/Businessprocess/Renderer/Renderer.php +++ b/library/Businessprocess/Renderer/Renderer.php @@ -169,8 +169,6 @@ abstract class Renderer extends HtmlDocument */ public function renderStateBadges($summary, $totalChildren) { - $elements = []; - $itemCount = Html::tag( 'span', [ @@ -181,7 +179,7 @@ abstract class Renderer extends HtmlDocument sprintf(mtp('businessprocess', '%u Child', '%u Children', $totalChildren), $totalChildren) ); - $elements[] = array_filter([ + $elements = array_filter([ $this->createBadgeGroup($summary, 'CRITICAL'), $this->createBadgeGroup($summary, 'UNKNOWN'), $this->createBadgeGroup($summary, 'WARNING'), From 92e982bf3d6424be20f2c8d8df782c9720f666c4 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 12 Jul 2023 10:22:14 +0200 Subject: [PATCH 064/105] Remove unused class `Form` and `FormStateOverrides` --- .../views/helpers/FormStateOverrides.php | 40 ------------------- library/Businessprocess/Form.php | 36 ----------------- 2 files changed, 76 deletions(-) delete mode 100644 application/views/helpers/FormStateOverrides.php delete mode 100644 library/Businessprocess/Form.php diff --git a/application/views/helpers/FormStateOverrides.php b/application/views/helpers/FormStateOverrides.php deleted file mode 100644 index 74ed2f4..0000000 --- a/application/views/helpers/FormStateOverrides.php +++ /dev/null @@ -1,40 +0,0 @@ - $label) { - if ($state === 0) { - continue; - } - - $chosen = $state; - if (isset($value[$state])) { - $chosen = $value[$state]; - } - - $options = [$state => t('Keep actual state')] + $states; - - $html .= ''; - } - - return $html; - } -} diff --git a/library/Businessprocess/Form.php b/library/Businessprocess/Form.php deleted file mode 100644 index 3270b38..0000000 --- a/library/Businessprocess/Form.php +++ /dev/null @@ -1,36 +0,0 @@ -setup(); - } - - public function addHidden($name, $value = null) - { - $this->addElement('hidden', $name); - $this->getElement($name)->setDecorators(array('ViewHelper')); - if ($value !== null) { - $this->setDefault($name, $value); - } - return $this; - } - - public function handleRequest(Request $request = null) - { - parent::handleRequest(); - return $this; - } - - public static function construct() - { - return new static; - } -} From 35d151b70df1daa3e9a0d46377c5fcbf0a2d4f57 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Thu, 10 Aug 2023 14:46:04 +0200 Subject: [PATCH 065/105] Sort Trait: Make `$sort` nullable and adjust code accordingly - Update phpDoc --- library/Businessprocess/Common/Sort.php | 12 ++++++++---- library/Businessprocess/Renderer/Renderer.php | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/library/Businessprocess/Common/Sort.php b/library/Businessprocess/Common/Sort.php index 3b0f6d4..4728af3 100644 --- a/library/Businessprocess/Common/Sort.php +++ b/library/Businessprocess/Common/Sort.php @@ -10,10 +10,10 @@ use ipl\Stdlib\Str; trait Sort { - /** @var string Current sort specification */ + /** @var ?string Current sort specification */ protected $sort; - /** @var callable Actual sorting function */ + /** @var ?callable Actual sorting function */ protected $sortFn; /** @@ -29,14 +29,18 @@ trait Sort /** * Set the sort specification * - * @param string $sort + * @param ?string $sort * * @return $this * * @throws InvalidArgumentException When sorting according to the specified specification is not possible */ - public function setSort(string $sort): self + public function setSort(?string $sort): self { + if (empty($sort)) { + return $this; + } + list($sortBy, $direction) = Str::symmetricSplit($sort, ' ', 2, 'asc'); switch ($sortBy) { diff --git a/library/Businessprocess/Renderer/Renderer.php b/library/Businessprocess/Renderer/Renderer.php index 9917ed6..6aa1363 100644 --- a/library/Businessprocess/Renderer/Renderer.php +++ b/library/Businessprocess/Renderer/Renderer.php @@ -145,6 +145,10 @@ abstract class Renderer extends HtmlDocument */ public function appliesCustomSorting(): bool { + if (empty($this->getSort())) { + return false; + } + list($sortBy, $_) = Str::symmetricSplit($this->getSort(), ' ', 2); list($defaultSortBy, $_) = Str::symmetricSplit($this->getDefaultSort(), ' ', 2); From 7346cd1cabff6ff7371eb86cdbabc5e4c6d65ffd Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Fri, 11 Aug 2023 12:00:20 +0200 Subject: [PATCH 066/105] HostServiceTermValidator:isValid(): Add missing `return` statement --- .../Web/Form/Validator/HostServiceTermValidator.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php b/library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php index b141206..58249f7 100644 --- a/library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php +++ b/library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php @@ -44,6 +44,7 @@ class HostServiceTermValidator extends BaseValidator $terms = [$terms]; } + $isValid = true; $testConfig = new BpConfig(); foreach ($terms as $term) { @@ -60,6 +61,7 @@ class HostServiceTermValidator extends BaseValidator if ($this->parent->hasChild($term->getSearchValue())) { $term->setMessage($this->translate('Already defined in this process')); + $isValid = false; } else { $testConfig->getNode('__unbound__') ->addChild($node); @@ -81,10 +83,14 @@ class HostServiceTermValidator extends BaseValidator } else { $term->setMessage($this->translate('Host not found')); } + + $isValid = false; } else { $term->setLabel($node->getAlias()); $term->setClass($node->getObjectClassName()); } } + + return $isValid; } } From 21933d1868e6fb5640c4feb46dc6dab57a2a5e94 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Fri, 11 Aug 2023 15:49:50 +0200 Subject: [PATCH 067/105] NodeAction::create(): Avoid unnecessary variable initialization --- library/Businessprocess/Modification/NodeAction.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Businessprocess/Modification/NodeAction.php b/library/Businessprocess/Modification/NodeAction.php index 369c3a2..357615d 100644 --- a/library/Businessprocess/Modification/NodeAction.php +++ b/library/Businessprocess/Modification/NodeAction.php @@ -111,8 +111,8 @@ abstract class NodeAction public static function create($actionName, $nodeName) { $className = __NAMESPACE__ . '\\Node' . ucfirst($actionName) . 'Action'; - $object = new $className($nodeName); - return $object; + + return new $className($nodeName); } /** From 6306b5306cc040f7ca09e115c80459a7d4b182b0 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 09:50:53 +0200 Subject: [PATCH 068/105] Define variable type when method returns a class object - This helps the IDE to find class methods and resolves the `call to an undefined method` issue --- application/clicommands/ProcessCommand.php | 2 +- application/controllers/HostController.php | 5 ++++- application/controllers/ProcessController.php | 5 ++++- application/controllers/ServiceController.php | 5 ++++- application/forms/BpUploadForm.php | 2 +- application/forms/DeleteNodeForm.php | 3 +++ application/forms/MoveNodeForm.php | 5 ++++- application/forms/ProcessForm.php | 6 +++++- application/forms/SimulationForm.php | 2 ++ .../Businessprocess/Web/Form/QuickForm.php | 20 +++++++++++++------ library/Businessprocess/Web/Url.php | 6 ++++-- 11 files changed, 46 insertions(+), 15 deletions(-) diff --git a/application/clicommands/ProcessCommand.php b/application/clicommands/ProcessCommand.php index 3b470b8..2227ad3 100644 --- a/application/clicommands/ProcessCommand.php +++ b/application/clicommands/ProcessCommand.php @@ -132,8 +132,8 @@ class ProcessCommand extends Command } } - /** @var BpNode $node */ try { + /** @var BpNode $node */ $node = $bp->getNode($nodeName); if (Module::exists('icingadb') && (! $bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend()) diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php index ac724cf..09352d0 100644 --- a/application/controllers/HostController.php +++ b/application/controllers/HostController.php @@ -7,6 +7,7 @@ use Icinga\Module\Businessprocess\IcingaDbObject; use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Icingadb\Model\Host; use Icinga\Module\Monitoring\Controller; +use Icinga\Module\Monitoring\DataView\DataView; use Icinga\Web\Url; use ipl\Stdlib\Filter; @@ -54,7 +55,9 @@ class HostController extends Controller ->from('hoststatus', array('host_name')) ->where('host_name', $hostName); - if ($this->applyRestriction('monitoring/filter/objects', $query)->fetchRow() !== false) { + /** @var DataView $restrictedQuery */ + $restrictedQuery = $this->applyRestriction('monitoring/filter/objects', $query); + if ($restrictedQuery->fetchRow() !== false) { $this->redirectNow(Url::fromPath('monitoring/host/show')->setParams($this->params)); } } diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index 44429df..208c91e 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -35,6 +35,7 @@ use ipl\Html\HtmlString; use ipl\Html\TemplateString; use ipl\Html\Text; use ipl\Web\Control\SortControl; +use ipl\Web\FormElement\TermInput; use ipl\Web\Widget\Link; use ipl\Web\Widget\Icon; @@ -282,7 +283,9 @@ class ProcessController extends Controller ->handleRequest($this->getServerRequest()); if ($form->hasElement('children')) { - foreach ($form->getElement('children')->prepareMultipartUpdate($this->getServerRequest()) as $update) { + /** @var TermInput $childrenElement */ + $childrenElement = $form->getElement('children'); + foreach ($childrenElement->prepareMultipartUpdate($this->getServerRequest()) as $update) { if (! is_array($update)) { $update = [$update]; } diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index 2c0563d..f10c791 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -7,6 +7,7 @@ use Icinga\Module\Businessprocess\IcingaDbObject; use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Icingadb\Model\Service; use Icinga\Module\Monitoring\Controller; +use Icinga\Module\Monitoring\DataView\DataView; use Icinga\Web\Url; use ipl\Stdlib\Filter; @@ -61,7 +62,9 @@ class ServiceController extends Controller ->where('host_name', $hostName) ->where('service_description', $serviceName); - if ($this->applyRestriction('monitoring/filter/objects', $query)->fetchRow() !== false) { + /** @var DataView $restrictedQuery */ + $restrictedQuery = $this->applyRestriction('monitoring/filter/objects', $query); + if ($restrictedQuery->fetchRow() !== false) { $this->redirectNow(Url::fromPath('monitoring/service/show')->setParams($this->params)); } } diff --git a/application/forms/BpUploadForm.php b/application/forms/BpUploadForm.php index ee3faf3..a746740 100644 --- a/application/forms/BpUploadForm.php +++ b/application/forms/BpUploadForm.php @@ -155,7 +155,7 @@ class BpUploadForm extends BpConfigBaseForm protected function processUploadedSource() { - /** @var \Zend_Form_Element_File $el */ + /** @var ?\Zend_Form_Element_File $el */ $el = $this->getElement('uploaded_file'); if ($el && $this->hasBeenSent()) { diff --git a/application/forms/DeleteNodeForm.php b/application/forms/DeleteNodeForm.php index 30fcdd4..ea39817 100644 --- a/application/forms/DeleteNodeForm.php +++ b/application/forms/DeleteNodeForm.php @@ -6,6 +6,7 @@ use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; +use Icinga\Web\View; class DeleteNodeForm extends BpConfigBaseForm { @@ -19,6 +20,8 @@ class DeleteNodeForm extends BpConfigBaseForm { $node = $this->node; $nodeName = $node->getAlias() ?? $node->getName(); + + /** @var View $view */ $view = $this->getView(); $this->addHtml( '

' . $view->escape( diff --git a/application/forms/MoveNodeForm.php b/application/forms/MoveNodeForm.php index 876ab90..81d15c7 100644 --- a/application/forms/MoveNodeForm.php +++ b/application/forms/MoveNodeForm.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Application\Icinga; +use Icinga\Application\Web; use Icinga\Exception\Http\HttpException; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; @@ -136,7 +137,9 @@ class MoveNodeForm extends BpConfigBaseForm ); } catch (ModificationError $e) { $this->notifyError($e->getMessage()); - Icinga::app()->getResponse() + /** @var Web $app */ + $app = Icinga::app(); + $app->getResponse() // Web 2's JS forces a content update for non-200s. Our own JS // can't prevent this, hence we're not making this a 400 :( //->setHttpResponseCode(400) diff --git a/application/forms/ProcessForm.php b/application/forms/ProcessForm.php index 69ab1a6..126fe9b 100644 --- a/application/forms/ProcessForm.php +++ b/application/forms/ProcessForm.php @@ -7,6 +7,7 @@ use Icinga\Module\Businessprocess\Modification\ProcessChanges; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; use Icinga\Web\Notification; +use Icinga\Web\View; class ProcessForm extends BpConfigBaseForm { @@ -16,8 +17,11 @@ class ProcessForm extends BpConfigBaseForm public function setup() { if ($this->node !== null) { + /** @var View $view */ + $view = $this->getView(); + $this->addHtml( - '

' . $this->getView()->escape( + '

' . $view->escape( sprintf($this->translate('Modify "%s"'), $this->node->getAlias()) ) . '

' ); diff --git a/application/forms/SimulationForm.php b/application/forms/SimulationForm.php index 3d43e3a..938ffaf 100644 --- a/application/forms/SimulationForm.php +++ b/application/forms/SimulationForm.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Module\Businessprocess\MonitoredNode; use Icinga\Module\Businessprocess\Simulation; use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm; +use Icinga\Web\View; class SimulationForm extends BpConfigBaseForm { @@ -36,6 +37,7 @@ class SimulationForm extends BpConfigBaseForm $node = $this->node; } + /** @var View $view */ $view = $this->getView(); if ($hasSimulation) { $title = $this->translate('Modify simulation for %s'); diff --git a/library/Businessprocess/Web/Form/QuickForm.php b/library/Businessprocess/Web/Form/QuickForm.php index c39b34b..451c66f 100644 --- a/library/Businessprocess/Web/Form/QuickForm.php +++ b/library/Businessprocess/Web/Form/QuickForm.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Businessprocess\Web\Form; use Icinga\Application\Icinga; +use Icinga\Application\Web; use Icinga\Exception\ProgrammingError; use Icinga\Web\Notification; use Icinga\Web\Request; @@ -428,14 +429,18 @@ abstract class QuickForm extends QuickBaseForm protected function redirectAndExit($url) { + /** @var Web $app */ + $app = Icinga::app(); /** @var Response $response */ - $response = Icinga::app()->getFrontController()->getResponse(); + $response = $app->getFrontController()->getResponse(); $response->redirectAndExit($url); } protected function setHttpResponseCode($code) { - Icinga::app()->getFrontController()->getResponse()->setHttpResponseCode($code); + /** @var Web $app */ + $app = Icinga::app(); + $app->getFrontController()->getResponse()->setHttpResponseCode($code); return $this; } @@ -461,8 +466,10 @@ abstract class QuickForm extends QuickBaseForm public function getRequest() { if ($this->request === null) { + /** @var Web $app */ + $app = Icinga::app(); /** @var Request $request */ - $request = Icinga::app()->getFrontController()->getRequest(); + $request = $app->getFrontController()->getRequest(); $this->setRequest($request); } return $this->request; @@ -471,14 +478,15 @@ abstract class QuickForm extends QuickBaseForm public function hasBeenSent() { if ($this->hasBeenSent === null) { - - /** @var Request $req */ if ($this->request === null) { - $req = Icinga::app()->getFrontController()->getRequest(); + /** @var Web $app */ + $app = Icinga::app(); + $req = $app->getFrontController()->getRequest(); } else { $req = $this->request; } + /** @var Request $req */ if ($req->isPost()) { $post = $req->getPost(); $this->hasBeenSent = array_key_exists(self::ID, $post) && diff --git a/library/Businessprocess/Web/Url.php b/library/Businessprocess/Web/Url.php index 3c036d4..b07b9fb 100644 --- a/library/Businessprocess/Web/Url.php +++ b/library/Businessprocess/Web/Url.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Businessprocess\Web; use Icinga\Application\Icinga; +use Icinga\Application\Web; use Icinga\Web\Url as WebUrl; /** @@ -19,8 +20,9 @@ class Url extends WebUrl $app = Icinga::app(); if ($app->isCli()) { return new FakeRequest(); - } else { - return $app->getRequest(); } + + /** @var Web $app */ + return $app->getRequest(); } } From 5899aa96ef98888b7e2b84f1dce9e41533c084c0 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:02:08 +0200 Subject: [PATCH 069/105] ProcessCommand: Define `$name` in method scope - Fixes variable is probably undefined --- application/clicommands/ProcessCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/clicommands/ProcessCommand.php b/application/clicommands/ProcessCommand.php index 2227ad3..018c1e3 100644 --- a/application/clicommands/ProcessCommand.php +++ b/application/clicommands/ProcessCommand.php @@ -110,8 +110,8 @@ class ProcessCommand extends Command exit(1); } + $name = $this->params->get('config'); try { - $name = $this->params->get('config'); if ($name === null) { $name = $this->getFirstProcessName(); } From 3fffecca3f55703ca885d6393b039b86cb0b6727 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:10:19 +0200 Subject: [PATCH 070/105] DeleteNodeForm: Make property `$parentNode` nullable --- application/forms/DeleteNodeForm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/forms/DeleteNodeForm.php b/application/forms/DeleteNodeForm.php index ea39817..dba0710 100644 --- a/application/forms/DeleteNodeForm.php +++ b/application/forms/DeleteNodeForm.php @@ -13,7 +13,7 @@ class DeleteNodeForm extends BpConfigBaseForm /** @var Node */ protected $node; - /** @var BpNode */ + /** @var ?BpNode */ protected $parentNode; public function setup() From 3643c799d0b4abf58f70d14f0ee5a08f62dcd69e Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:12:34 +0200 Subject: [PATCH 071/105] SimulationForm: Property `$simulatedNode` can be nullable --- application/forms/SimulationForm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/forms/SimulationForm.php b/application/forms/SimulationForm.php index 938ffaf..04a0f56 100644 --- a/application/forms/SimulationForm.php +++ b/application/forms/SimulationForm.php @@ -12,7 +12,7 @@ class SimulationForm extends BpConfigBaseForm /** @var MonitoredNode */ protected $node; - /** @var MonitoredNode */ + /** @var ?MonitoredNode */ protected $simulatedNode; /** @var Simulation */ From ae8e71106facb632e897ff5987a99216729ddc77 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:18:03 +0200 Subject: [PATCH 072/105] BpConfig::hasChanges(): Fix incorrect return type --- library/Businessprocess/BpConfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index 30cdf56..2379cb4 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -226,7 +226,7 @@ class BpConfig /** * Whether changes have been applied to this configuration * - * @return int + * @return bool */ public function hasChanges() { From 598e9a1af04a92e6e976634e88a00c0c55e9fc0c Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:19:01 +0200 Subject: [PATCH 073/105] BpConfig::getNode(): Define exact return types in PhpDoc - This fixes the IDE's issue `Call to an undefined method`, which is caused by the fact that the parent class `Node` does not contain all the methods defined in the child classes. --- library/Businessprocess/BpConfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index 2379cb4..c9e70fd 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -631,7 +631,7 @@ class BpConfig /** * @param string $name - * @return Node + * @return MonitoredNode|BpNode * @throws Exception */ public function getNode($name) From 541ec5da6c6c0d4e5ed1d8dfc8a050e6ce5d5d9c Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:36:23 +0200 Subject: [PATCH 074/105] BpNode: Property `$children` can be null --- library/Businessprocess/BpNode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index 9133eec..df90c67 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -21,7 +21,7 @@ class BpNode extends Node protected $display = 0; - /** @var Node[] */ + /** @var ?Node[] */ protected $children; /** @var array */ From f960d09cc2e912ec78d8c75253063e1bc7b01fd8 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:37:33 +0200 Subject: [PATCH 075/105] BpNode: Remove unreachable `break` statements --- library/Businessprocess/BpNode.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/Businessprocess/BpNode.php b/library/Businessprocess/BpNode.php index df90c67..ab76e3e 100644 --- a/library/Businessprocess/BpNode.php +++ b/library/Businessprocess/BpNode.php @@ -623,18 +623,14 @@ class BpNode extends Node switch ($this->getOperator()) { case self::OP_AND: return 'AND'; - break; case self::OP_OR: return 'OR'; case self::OP_XOR: return 'XOR'; - break; case self::OP_NOT: return 'NOT'; - break; case self::OP_DEGRADED: return 'DEG'; - break; default: // MIN $this->assertNumericOperator(); From ad3cb81dc926cc629094d1de95b026e7b54466b3 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:44:11 +0200 Subject: [PATCH 076/105] NodeAction: `json_decode()` $param#2 expects bool --- library/Businessprocess/Modification/NodeAction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Modification/NodeAction.php b/library/Businessprocess/Modification/NodeAction.php index 357615d..b5baa5d 100644 --- a/library/Businessprocess/Modification/NodeAction.php +++ b/library/Businessprocess/Modification/NodeAction.php @@ -144,7 +144,7 @@ abstract class NodeAction */ public static function unSerialize($string) { - $object = json_decode($string, JSON_FORCE_OBJECT); + $object = json_decode($string, true); $action = self::create($object['actionName'], $object['nodeName']); foreach ($object['properties'] as $key => $val) { From 6934016ef083ea3229104b48b7637cac2a1a532e Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:53:25 +0200 Subject: [PATCH 077/105] Node: `var_export()` param#2 expects bool --- library/Businessprocess/Node.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index a5af69b..836f62b 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -443,7 +443,7 @@ abstract class Node throw new ProgrammingError( 'Got invalid state for node %s: %s', $this->getName(), - var_export($state, 1) . var_export($this->stateToSortStateMap, 1) + var_export($state, true) . var_export($this->stateToSortStateMap, true) ); } From 3544c21056c3eee5d4eedc785ddc83f6bebfdade Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 11:57:59 +0200 Subject: [PATCH 078/105] Node: Property `$state` can be null --- library/Businessprocess/Node.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index 836f62b..0510859 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -74,7 +74,7 @@ abstract class Node /** * Node state * - * @var int + * @var ?int */ protected $state; From ab8fe2aca6371ad9b8dfdde98fdbd55c195519d4 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:00:22 +0200 Subject: [PATCH 079/105] (ServiceDetail/DetailView)Extension: Property `$storage` can be null --- .../ProvidedHook/Icingadb/ServiceDetailExtension.php | 2 +- .../ProvidedHook/Monitoring/DetailviewExtension.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Businessprocess/ProvidedHook/Icingadb/ServiceDetailExtension.php b/library/Businessprocess/ProvidedHook/Icingadb/ServiceDetailExtension.php index d2fb173..6d10af2 100644 --- a/library/Businessprocess/ProvidedHook/Icingadb/ServiceDetailExtension.php +++ b/library/Businessprocess/ProvidedHook/Icingadb/ServiceDetailExtension.php @@ -16,7 +16,7 @@ use ipl\Html\ValidHtml; class ServiceDetailExtension extends ServiceDetailExtensionHook { - /** @var LegacyStorage */ + /** @var ?LegacyStorage */ private $storage; /** @var string */ diff --git a/library/Businessprocess/ProvidedHook/Monitoring/DetailviewExtension.php b/library/Businessprocess/ProvidedHook/Monitoring/DetailviewExtension.php index 9906df9..691acec 100644 --- a/library/Businessprocess/ProvidedHook/Monitoring/DetailviewExtension.php +++ b/library/Businessprocess/ProvidedHook/Monitoring/DetailviewExtension.php @@ -13,7 +13,7 @@ use Icinga\Module\Monitoring\Object\Service; class DetailviewExtension extends DetailviewExtensionHook { - /** @var LegacyStorage */ + /** @var ?LegacyStorage */ private $storage; /** @var string */ From 26b0d921ea2a907e1f0b4dc4302c489885c7a768 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:02:04 +0200 Subject: [PATCH 080/105] Renderer::renderStateBadges(): Return type can be null --- library/Businessprocess/Renderer/Renderer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Renderer/Renderer.php b/library/Businessprocess/Renderer/Renderer.php index 6aa1363..6a5d624 100644 --- a/library/Businessprocess/Renderer/Renderer.php +++ b/library/Businessprocess/Renderer/Renderer.php @@ -169,7 +169,7 @@ abstract class Renderer extends HtmlDocument /** * @param $summary - * @return BaseHtmlElement + * @return ?BaseHtmlElement */ public function renderStateBadges($summary, $totalChildren) { From 6f81fed8e7cf0593c97e35fd8713b908981e7507 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:11:12 +0200 Subject: [PATCH 081/105] NodeTile: Fix incorrect phpDoc --- library/Businessprocess/Renderer/TileRenderer/NodeTile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index 652ca0e..9bc1c2f 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -37,7 +37,7 @@ class NodeTile extends BaseHtmlElement * @param Renderer $renderer * @param $name * @param Node $node - * @param null $path + * @param ?array $path */ public function __construct(Renderer $renderer, Node $node, $path = null) { From 7605d5e007bbdf6e9af05028417c48253b26eea1 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:20:15 +0200 Subject: [PATCH 082/105] LegacyConfigParser: Property `$prevKey` can be null --- library/Businessprocess/Storage/LegacyConfigParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Storage/LegacyConfigParser.php b/library/Businessprocess/Storage/LegacyConfigParser.php index 83c9240..cea02ae 100644 --- a/library/Businessprocess/Storage/LegacyConfigParser.php +++ b/library/Businessprocess/Storage/LegacyConfigParser.php @@ -11,7 +11,7 @@ use Icinga\Module\Businessprocess\Metadata; class LegacyConfigParser { - /** @var string */ + /** @var ?string */ protected static $prevKey; /** @var int */ From 43b391880db9190fba52c2ecbfdc8b2c98c4c357 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:21:45 +0200 Subject: [PATCH 083/105] LegacyConfigRenderer: Don't use dynamic property --- library/Businessprocess/Storage/LegacyConfigRenderer.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/Businessprocess/Storage/LegacyConfigRenderer.php b/library/Businessprocess/Storage/LegacyConfigRenderer.php index 430a7a5..1f7e23b 100644 --- a/library/Businessprocess/Storage/LegacyConfigRenderer.php +++ b/library/Businessprocess/Storage/LegacyConfigRenderer.php @@ -11,6 +11,8 @@ class LegacyConfigRenderer /** @var array */ protected $renderedNodes; + protected $config; + /** * LecagyConfigRenderer constructor * From d0df785bbde24e4d5bc2d0cdec2a254b7e7d32b8 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:24:06 +0200 Subject: [PATCH 084/105] BaseTestCase: Param `$subDir` can be null --- library/Businessprocess/Test/BaseTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Test/BaseTestCase.php b/library/Businessprocess/Test/BaseTestCase.php index daab69c..ba32b7c 100644 --- a/library/Businessprocess/Test/BaseTestCase.php +++ b/library/Businessprocess/Test/BaseTestCase.php @@ -49,7 +49,7 @@ abstract class BaseTestCase extends \Icinga\Test\BaseTestCase } /** - * @param null $subDir + * @param ?string $subDir * @return string */ protected function getTestsBaseDir($subDir = null) From 95776d309beecf72aa8f204313cfd8a2ff7b7acc Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:27:00 +0200 Subject: [PATCH 085/105] Controller::storage(): Only return an instance of `LegacyStorage` --- library/Businessprocess/Web/Controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Web/Controller.php b/library/Businessprocess/Web/Controller.php index 4f618b2..de07e4c 100644 --- a/library/Businessprocess/Web/Controller.php +++ b/library/Businessprocess/Web/Controller.php @@ -248,7 +248,7 @@ class Controller extends CompatController } /** - * @return LegacyStorage|Storage + * @return LegacyStorage */ protected function storage() { From 95504131d16a3df134cc91bda65e18f31accd921 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:31:42 +0200 Subject: [PATCH 086/105] FormLoader: Define var `$file` in method scope - Fixes IDE's message: `varibale $file is probabaly undefined` --- library/Businessprocess/Web/Form/FormLoader.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/Businessprocess/Web/Form/FormLoader.php b/library/Businessprocess/Web/Form/FormLoader.php index 965da4b..0cc5389 100644 --- a/library/Businessprocess/Web/Form/FormLoader.php +++ b/library/Businessprocess/Web/Form/FormLoader.php @@ -17,6 +17,8 @@ class FormLoader $basedir = $module->getFormDir(); $ns = '\\Icinga\\Module\\' . ucfirst($module->getName()) . '\\Forms\\'; } + + $file = null; if (preg_match('~^[a-z0-9/]+$~i', $name)) { $parts = preg_split('~/~', $name); $class = ucfirst(array_pop($parts)) . 'Form'; From 2efe54de1f28a58e811a9ac21457d2f54d1de865 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:39:24 +0200 Subject: [PATCH 087/105] QuickBaseForm: Property `$icingaModule` can be null --- library/Businessprocess/Web/Form/QuickBaseForm.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/Businessprocess/Web/Form/QuickBaseForm.php b/library/Businessprocess/Web/Form/QuickBaseForm.php index 3ef7b66..36d134f 100644 --- a/library/Businessprocess/Web/Form/QuickBaseForm.php +++ b/library/Businessprocess/Web/Form/QuickBaseForm.php @@ -13,7 +13,7 @@ abstract class QuickBaseForm extends Zend_Form implements ValidHtml * The Icinga module this form belongs to. Usually only set if the * form is initialized through the FormLoader * - * @var Module + * @var ?Module */ protected $icingaModule; @@ -123,7 +123,6 @@ abstract class QuickBaseForm extends Zend_Form implements ValidHtml } if (array_key_exists('icingaModule', $options)) { - /** @var Module icingaModule */ $this->icingaModule = $options['icingaModule']; $this->icingaModuleName = $this->icingaModule->getName(); unset($options['icingaModule']); From 52732dc3c7a8bc86e8931ac7bb42f39f6a6190f7 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:41:22 +0200 Subject: [PATCH 088/105] QuickForm: Make property `$successUrl` nullable and add phpDoc to `setAction()` --- library/Businessprocess/Web/Form/QuickForm.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/Businessprocess/Web/Form/QuickForm.php b/library/Businessprocess/Web/Form/QuickForm.php index 451c66f..cb4d287 100644 --- a/library/Businessprocess/Web/Form/QuickForm.php +++ b/library/Businessprocess/Web/Form/QuickForm.php @@ -46,7 +46,7 @@ abstract class QuickForm extends QuickBaseForm protected $request; /** - * @var Url + * @var ?Url */ protected $successUrl; @@ -252,6 +252,10 @@ abstract class QuickForm extends QuickBaseForm { } + /** + * @param $action string|Url + * @return $this + */ public function setAction($action) { if ($action instanceof Url) { From 74c3440ef95c9b2dc981ea57f63ddcf5001c51c1 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:44:27 +0200 Subject: [PATCH 089/105] ProcessProblemsBadge: Fix `variable $count is probably undefined` --- .../Web/Navigation/Renderer/ProcessProblemsBadge.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/Businessprocess/Web/Navigation/Renderer/ProcessProblemsBadge.php b/library/Businessprocess/Web/Navigation/Renderer/ProcessProblemsBadge.php index a31a74b..575dc5e 100644 --- a/library/Businessprocess/Web/Navigation/Renderer/ProcessProblemsBadge.php +++ b/library/Businessprocess/Web/Navigation/Renderer/ProcessProblemsBadge.php @@ -19,12 +19,10 @@ class ProcessProblemsBadge extends BadgeNavigationItemRenderer public function getCount() { + $count = 0; if ($this->count === null) { $storage = LegacyStorage::getInstance(); - $count = 0; $bp = $storage->loadProcess($this->getBpConfigName()); - - foreach ($bp->getRootNodes() as $rootNode) { if (! $rootNode->isEmpty() && $rootNode->getState() !== $rootNode::ICINGA_PENDING From c497c7360ee744424f609b469eb115f0616aad66 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 12:46:49 +0200 Subject: [PATCH 090/105] Url::getRequest(): Add missing return type --- library/Businessprocess/Web/Url.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/Businessprocess/Web/Url.php b/library/Businessprocess/Web/Url.php index b07b9fb..92b1e85 100644 --- a/library/Businessprocess/Web/Url.php +++ b/library/Businessprocess/Web/Url.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Businessprocess\Web; use Icinga\Application\Icinga; use Icinga\Application\Web; +use Icinga\Web\Request; use Icinga\Web\Url as WebUrl; /** @@ -15,6 +16,9 @@ use Icinga\Web\Url as WebUrl; */ class Url extends WebUrl { + /** + * @return FakeRequest|Request + */ protected static function getRequest() { $app = Icinga::app(); From f74a054d8ba2aa66452af3164d3469e2a19590ac Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Mon, 14 Aug 2023 13:06:30 +0200 Subject: [PATCH 091/105] ProcessChanges: Fix incorrect phpDoc --- library/Businessprocess/Modification/ProcessChanges.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/Businessprocess/Modification/ProcessChanges.php b/library/Businessprocess/Modification/ProcessChanges.php index 0ed574c..9257558 100644 --- a/library/Businessprocess/Modification/ProcessChanges.php +++ b/library/Businessprocess/Modification/ProcessChanges.php @@ -100,7 +100,6 @@ class ProcessChanges /** * @param $nodeName - * @param Node|null $parent * @return $this */ public function copyNode($nodeName) @@ -211,7 +210,7 @@ class ProcessChanges /** * Number of stacked changes * - * @return bool + * @return int */ public function count() { From 9aabeb1e1c9531e6324decf548b4b3d1e770655c Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Tue, 22 Aug 2023 09:18:13 +0200 Subject: [PATCH 092/105] Fix call an undefined method `Filterable::fetchRow()` error --- application/controllers/HostController.php | 5 ++--- application/controllers/ServiceController.php | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php index 09352d0..e22edde 100644 --- a/application/controllers/HostController.php +++ b/application/controllers/HostController.php @@ -55,9 +55,8 @@ class HostController extends Controller ->from('hoststatus', array('host_name')) ->where('host_name', $hostName); - /** @var DataView $restrictedQuery */ - $restrictedQuery = $this->applyRestriction('monitoring/filter/objects', $query); - if ($restrictedQuery->fetchRow() !== false) { + $this->applyRestriction('monitoring/filter/objects', $query); + if ($query->fetchRow() !== false) { $this->redirectNow(Url::fromPath('monitoring/host/show')->setParams($this->params)); } } diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index f10c791..671d00c 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -62,9 +62,8 @@ class ServiceController extends Controller ->where('host_name', $hostName) ->where('service_description', $serviceName); - /** @var DataView $restrictedQuery */ - $restrictedQuery = $this->applyRestriction('monitoring/filter/objects', $query); - if ($restrictedQuery->fetchRow() !== false) { + $this->applyRestriction('monitoring/filter/objects', $query); + if ($query->fetchRow() !== false) { $this->redirectNow(Url::fromPath('monitoring/service/show')->setParams($this->params)); } } From b2c25d35f7749ae8762507240c676b8430d447e8 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Thu, 24 Aug 2023 13:12:33 +0200 Subject: [PATCH 093/105] Node: Property $icon can be null --- library/Businessprocess/Node.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index 0510859..c95295b 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -98,7 +98,7 @@ abstract class Node /** * This node's icon * - * @var string + * @var ?string */ protected $icon; From 1c6ad874acc14ee3a92aced0a2eabeb77a236b7b Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Tue, 22 Aug 2023 10:16:32 +0200 Subject: [PATCH 094/105] Add variable type hint & fix argument type hints --- application/forms/AddNodeForm.php | 4 +++- library/Businessprocess/Modification/NodeRemoveAction.php | 7 +++---- library/Businessprocess/Node.php | 4 ++-- library/Businessprocess/Renderer/Breadcrumb.php | 1 + library/Businessprocess/Renderer/TileRenderer/NodeTile.php | 1 - library/Businessprocess/Storage/LegacyConfigParser.php | 1 + library/Businessprocess/Web/Controller.php | 1 + 7 files changed, 11 insertions(+), 8 deletions(-) diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php index 68299b7..3840d8a 100644 --- a/application/forms/AddNodeForm.php +++ b/application/forms/AddNodeForm.php @@ -378,9 +378,11 @@ class AddNodeForm extends CompatForm $changes->createNode(BpConfig::escapeName($this->getValue('name')), $properties); } else { + /** @var TermInput $term */ + $term = $this->getElement('children'); $children = array_unique(array_map(function ($term) { return $term->getSearchValue(); - }, $this->getElement('children')->getTerms())); + }, $term->getTerms())); if ($nodeType === 'host' || $nodeType === 'service') { $stateOverrides = $this->getValue('stateOverrides'); diff --git a/library/Businessprocess/Modification/NodeRemoveAction.php b/library/Businessprocess/Modification/NodeRemoveAction.php index 05a2a92..6100146 100644 --- a/library/Businessprocess/Modification/NodeRemoveAction.php +++ b/library/Businessprocess/Modification/NodeRemoveAction.php @@ -68,10 +68,9 @@ class NodeRemoveAction extends NodeAction $parentName = $this->getParentName(); $node = $config->getNode($name); - $this->updateStateOverrides( - $node, - $parentName ? $config->getNode($parentName) : null - ); + /** @var ?BpNode $parentBpNode */ + $parentBpNode = $parentName ? $config->getNode($parentName) : null; + $this->updateStateOverrides($node, $parentBpNode); if ($parentName === null) { if (! $config->hasBpNode($name)) { diff --git a/library/Businessprocess/Node.php b/library/Businessprocess/Node.php index c95295b..a0c07d2 100644 --- a/library/Businessprocess/Node.php +++ b/library/Businessprocess/Node.php @@ -47,7 +47,7 @@ abstract class Node self::NODE_EMPTY => 0 ); - /** @var string Alias of the node */ + /** @var ?string Alias of the node */ protected $alias; /** @@ -346,7 +346,7 @@ abstract class Node /** * Get the alias of the node * - * @return string + * @return ?string */ public function getAlias() { diff --git a/library/Businessprocess/Renderer/Breadcrumb.php b/library/Businessprocess/Renderer/Breadcrumb.php index b0f986b..4272b76 100644 --- a/library/Businessprocess/Renderer/Breadcrumb.php +++ b/library/Businessprocess/Renderer/Breadcrumb.php @@ -48,6 +48,7 @@ class Breadcrumb extends BaseHtmlElement $parts = array(); while ($nodeName = array_pop($path)) { + /** @var BpNode $node */ $node = $bp->getNode($nodeName); $renderer->setParentNode($node); array_unshift( diff --git a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php index 9bc1c2f..1f32f54 100644 --- a/library/Businessprocess/Renderer/TileRenderer/NodeTile.php +++ b/library/Businessprocess/Renderer/TileRenderer/NodeTile.php @@ -35,7 +35,6 @@ class NodeTile extends BaseHtmlElement /** * NodeTile constructor. * @param Renderer $renderer - * @param $name * @param Node $node * @param ?array $path */ diff --git a/library/Businessprocess/Storage/LegacyConfigParser.php b/library/Businessprocess/Storage/LegacyConfigParser.php index cea02ae..754c7ff 100644 --- a/library/Businessprocess/Storage/LegacyConfigParser.php +++ b/library/Businessprocess/Storage/LegacyConfigParser.php @@ -247,6 +247,7 @@ class LegacyConfigParser { // state_overrides !|n-n[,n-n]!|n-n[,n-n] $segments = preg_split('~\s*!\s*~', substr($line, 16)); + /** @var BpNode $node */ $node = $bp->getNode(array_shift($segments)); foreach ($segments as $overrideDef) { list($childName, $overrides) = preg_split('~\s*\|\s*~', $overrideDef, 2); diff --git a/library/Businessprocess/Web/Controller.php b/library/Businessprocess/Web/Controller.php index de07e4c..43200cc 100644 --- a/library/Businessprocess/Web/Controller.php +++ b/library/Businessprocess/Web/Controller.php @@ -210,6 +210,7 @@ class Controller extends CompatController protected function loadBpConfig() { $name = $this->params->get('config'); + /** @var LegacyStorage $storage */ $storage = $this->storage(); if (! $storage->hasProcess($name)) { From 1f3514ce2b5c4db801ff29e843ff65522baa4dc8 Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Tue, 22 Aug 2023 12:11:51 +0200 Subject: [PATCH 095/105] phpstan: Set level to max and add `baseline` config --- phpstan-baseline.neon | 4536 +++++++++++++++++++++++++++++++++++++++++ phpstan.neon | 5 +- 2 files changed, 4540 insertions(+), 1 deletion(-) create mode 100644 phpstan-baseline.neon diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..b259017 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,4536 @@ +parameters: + ignoreErrors: + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\CheckCommand\\:\\:listActions\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/CheckCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\CheckCommand\\:\\:processAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/CheckCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\CleanupCommand\\:\\:init\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/CleanupCommand.php + + - + message: "#^Parameter \\#1 \\$name of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getNode\\(\\) expects string, int\\|string given\\.$#" + count: 1 + path: application/clicommands/CleanupCommand.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\CleanupCommand\\:\\:\\$defaultActionName has no type specified\\.$#" + count: 1 + path: application/clicommands/CleanupCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:checkAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:getFirstProcessName\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:init\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:listAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:listBpNames\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:listConfigNames\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:listConfigNames\\(\\) has parameter \\$withTitle with no type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:renderProblemTree\\(\\) has no return type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:renderProblemTree\\(\\) has parameter \\$depth with no type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:renderProblemTree\\(\\) has parameter \\$tree with no type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:renderProblemTree\\(\\) has parameter \\$useColors with no type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Parameter \\#1 \\$name of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getNode\\(\\) expects string, mixed given\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Parameter \\#1 \\$rootCause of method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getProblemTreeBlame\\(\\) expects bool, mixed given\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:\\$hostColors has no type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Clicommands\\\\ProcessCommand\\:\\:\\$serviceColors has no type specified\\.$#" + count: 1 + path: application/clicommands/ProcessCommand.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\HostController\\:\\:moduleInit\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/HostController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\HostController\\:\\:showAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/HostController.php + + - + message: "#^Parameter \\#2 \\$value of method Icinga\\\\Web\\\\UrlParams\\:\\:add\\(\\) expects bool\\|string, mixed given\\.$#" + count: 1 + path: application/controllers/HostController.php + + - + message: "#^Parameter \\#2 \\$value of static method ipl\\\\Stdlib\\\\Filter\\:\\:equal\\(\\) expects array\\|bool\\|float\\|int\\|string, mixed given\\.$#" + count: 1 + path: application/controllers/HostController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\IndexController\\:\\:indexAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/IndexController.php + + - + message: "#^Binary operation \"\\+\" between int\\|string and 1 results in an error\\.$#" + count: 1 + path: application/controllers/NodeController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\NodeController\\:\\:impactAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/NodeController.php + + - + message: "#^Parameter \\#1 \\$name of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getNode\\(\\) expects string, mixed given\\.$#" + count: 1 + path: application/controllers/NodeController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:configAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:createAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:createConfigActionBar\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:createConfigActionBar\\(\\) has parameter \\$showDiff with no type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:downloadAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:getNode\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:getProcessTabs\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:handleFormatRequest\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:handleSimulations\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:loadActionForm\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:prepareControls\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:prepareControls\\(\\) has parameter \\$bp with no type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:prepareControls\\(\\) has parameter \\$renderer with no type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:prepareRenderer\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:prepareRenderer\\(\\) has parameter \\$bp with no type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:prepareRenderer\\(\\) has parameter \\$node with no type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:setDynamicAutorefresh\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:showAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:showErrors\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:showHints\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:showWarnings\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:sourceAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:tabsForConfig\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:tabsForShow\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ProcessController\\:\\:uploadAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\$name of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getNode\\(\\) expects string, mixed given\\.$#" + count: 6 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\$node of method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\AddNodeForm\\:\\:setParentNode\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null, Icinga\\\\Module\\\\Businessprocess\\\\Node\\|null given\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\$node of method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\EditNodeForm\\:\\:setParentNode\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null, Icinga\\\\Module\\\\Businessprocess\\\\Node\\|null given\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\$path of method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:setPath\\(\\) expects array, mixed given\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\$stream of function fpassthru expects resource, resource\\|false given\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\$stream of function fputcsv expects resource, resource\\|false given\\.$#" + count: 2 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\$stream of function rewind expects resource, resource\\|false given\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\$string of function strtolower expects string, mixed given\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Parameter \\#1 \\(mixed\\) of echo cannot be converted to string\\.$#" + count: 1 + path: application/controllers/ProcessController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ServiceController\\:\\:moduleInit\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ServiceController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\ServiceController\\:\\:showAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/ServiceController.php + + - + message: "#^Parameter \\#2 \\$value of method Icinga\\\\Web\\\\UrlParams\\:\\:add\\(\\) expects bool\\|string, mixed given\\.$#" + count: 2 + path: application/controllers/ServiceController.php + + - + message: "#^Parameter \\#2 \\$value of static method ipl\\\\Stdlib\\\\Filter\\:\\:equal\\(\\) expects array\\|bool\\|float\\|int\\|string, mixed given\\.$#" + count: 2 + path: application/controllers/ServiceController.php + + - + message: "#^Cannot access property \\$display_name on mixed\\.$#" + count: 2 + path: application/controllers/SuggestionsController.php + + - + message: "#^Cannot access property \\$host on mixed\\.$#" + count: 2 + path: application/controllers/SuggestionsController.php + + - + message: "#^Cannot access property \\$name on mixed\\.$#" + count: 2 + path: application/controllers/SuggestionsController.php + + - + message: "#^Cannot call method getExcludeTerms\\(\\) on ipl\\\\Web\\\\FormElement\\\\TermInput\\\\TermSuggestions\\|null\\.$#" + count: 5 + path: application/controllers/SuggestionsController.php + + - + message: "#^Cannot call method getOriginalSearchValue\\(\\) on ipl\\\\Web\\\\FormElement\\\\TermInput\\\\TermSuggestions\\|null\\.$#" + count: 14 + path: application/controllers/SuggestionsController.php + + - + message: "#^Cannot call method getSearchTerm\\(\\) on ipl\\\\Web\\\\FormElement\\\\TermInput\\\\TermSuggestions\\|null\\.$#" + count: 26 + path: application/controllers/SuggestionsController.php + + - + message: "#^Cannot call method matchSearch\\(\\) on ipl\\\\Web\\\\FormElement\\\\TermInput\\\\TermSuggestions\\|null\\.$#" + count: 2 + path: application/controllers/SuggestionsController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\SuggestionsController\\:\\:icingadbHostAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/SuggestionsController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\SuggestionsController\\:\\:icingadbServiceAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/SuggestionsController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\SuggestionsController\\:\\:monitoringHostAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/SuggestionsController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\SuggestionsController\\:\\:monitoringServiceAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/SuggestionsController.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Controllers\\\\SuggestionsController\\:\\:processAction\\(\\) has no return type specified\\.$#" + count: 1 + path: application/controllers/SuggestionsController.php + + - + message: "#^Parameter \\#1 \\$filter of method Icinga\\\\Module\\\\Monitoring\\\\DataView\\\\DataView\\:\\:applyFilter\\(\\) expects Icinga\\\\Data\\\\Filter\\\\Filter, Icinga\\\\Data\\\\Filter\\\\Filter\\|null given\\.$#" + count: 2 + path: application/controllers/SuggestionsController.php + + - + message: "#^Parameter \\#2 \\$filter of static method Icinga\\\\Data\\\\Filter\\\\Filter\\:\\:where\\(\\) expects string, string\\|null given\\.$#" + count: 14 + path: application/controllers/SuggestionsController.php + + - + message: "#^Parameter \\#2 \\$value of static method ipl\\\\Stdlib\\\\Filter\\:\\:equal\\(\\) expects array\\|bool\\|float\\|int\\|string, string\\|null given\\.$#" + count: 12 + path: application/controllers/SuggestionsController.php + + - + message: "#^Parameter \\#2 \\$value of static method ipl\\\\Stdlib\\\\Filter\\:\\:like\\(\\) expects array\\\\|string, string\\|null given\\.$#" + count: 12 + path: application/controllers/SuggestionsController.php + + - + message: "#^Cannot call method getBackend\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 2 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method getMetadata\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method getName\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 2 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method getNode\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method getRootNodes\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method getStateOverrides\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method hasNode\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method hasRootNode\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method isEmpty\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 2 + path: application/forms/AddNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\AddNodeForm\\:\\:applyManualSorting\\(\\) has parameter \\$bpNodes with no value type specified in iterable type array\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\AddNodeForm\\:\\:applyManualSorting\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\AddNodeForm\\:\\:assemble\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\AddNodeForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\AddNodeForm\\:\\:sort\\(\\) has parameter \\$nodes with no value type specified in iterable type array\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\AddNodeForm\\:\\:sort\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Parameter \\#1 \\$bp of static method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:construct\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\BpConfig, Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null given\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Parameter \\#1 \\$name of static method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:escapeName\\(\\) expects string, mixed given\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Parameter \\#1 \\$node of method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:modifyNode\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\Node, Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null given\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Parameter \\#1 \\$parent of method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\Validator\\\\HostServiceTermValidator\\:\\:setParent\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\BpNode, Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null given\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + count: 1 + path: application/forms/AddNodeForm.php + + - + message: "#^Cannot call method getLabel\\(\\) on Zend_Form_Element\\|null\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Cannot call method setAttrib\\(\\) on Zend_Form_Element\\|null\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Cannot call method setValue\\(\\) on Zend_Form_Element\\|null\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpConfigForm\\:\\:hasDeleteButton\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpConfigForm\\:\\:onRequest\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpConfigForm\\:\\:onSetup\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpConfigForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpConfigForm\\:\\:setup\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpConfigForm\\:\\:shouldBeDeleted\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + count: 5 + path: application/forms/BpConfigForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpConfigForm\\:\\:\\$deleteButtonName has no type specified\\.$#" + count: 1 + path: application/forms/BpConfigForm.php + + - + message: "#^Access to an undefined property Zend_Form_Element_File\\:\\:\\$file\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:getTempDir\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:getUploadedConfig\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:hasSource\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:parseSubmittedSourceCode\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:processUploadedSource\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:setup\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:showDetails\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:showUpload\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 2 + path: application/forms/BpUploadForm.php + + - + message: "#^Parameter \\#2 \\$options of method Zend_Form_Element_File\\:\\:addFilter\\(\\) expects array\\|string\\|null, string\\|false given\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:\\$deleteButtonName has no type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:\\$node has no type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:\\$objectList has no type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:\\$processList has no type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\BpUploadForm\\:\\:\\$sourceCode has no type specified\\.$#" + count: 1 + path: application/forms/BpUploadForm.php + + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: application/forms/CleanupNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\CleanupNodeForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/CleanupNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\CleanupNodeForm\\:\\:setup\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/CleanupNodeForm.php + + - + message: "#^Parameter \\#1 \\$name of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getNode\\(\\) expects string, mixed given\\.$#" + count: 1 + path: application/forms/CleanupNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\DeleteNodeForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/DeleteNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\DeleteNodeForm\\:\\:setup\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/DeleteNodeForm.php + + - + message: "#^Cannot call method getAlias\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\Node\\|null\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Cannot call method getBackend\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 2 + path: application/forms/EditNodeForm.php + + - + message: "#^Cannot call method getChildNames\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Cannot call method getMetadata\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Cannot call method getName\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Cannot call method getName\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null\\.$#" + count: 3 + path: application/forms/EditNodeForm.php + + - + message: "#^Cannot call method getName\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\Node\\|null\\.$#" + count: 3 + path: application/forms/EditNodeForm.php + + - + message: "#^Cannot call method getNode\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null\\.$#" + count: 2 + path: application/forms/EditNodeForm.php + + - + message: "#^Cannot call method getStateOverrides\\(\\) on Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null\\.$#" + count: 2 + path: application/forms/EditNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\EditNodeForm\\:\\:assemble\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\EditNodeForm\\:\\:identifyChosenNode\\(\\) should return Icinga\\\\Module\\\\Businessprocess\\\\Node but returns Icinga\\\\Module\\\\Businessprocess\\\\Node\\|null\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\EditNodeForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Parameter \\#1 \\$bp of static method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:construct\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\BpConfig, Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\|null given\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Parameter \\#1 \\$name of static method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:joinNodeName\\(\\) expects string, mixed given\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Parameter \\#1 \\$node of method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:deleteNode\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\Node, Icinga\\\\Module\\\\Businessprocess\\\\Node\\|null given\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Parameter \\#1 \\$node of method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:modifyNode\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\Node, Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null given\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Parameter \\#1 \\$parent of method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\Validator\\\\HostServiceTermValidator\\:\\:setParent\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\BpNode, Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null given\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Parameter \\#3 \\$to of method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:moveNode\\(\\) expects int, int\\|string\\|false given\\.$#" + count: 1 + path: application/forms/EditNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\MoveNodeForm\\:\\:hasBeenSent\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/MoveNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\MoveNodeForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/MoveNodeForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\MoveNodeForm\\:\\:setup\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/MoveNodeForm.php + + - + message: "#^Parameter \\#1 \\$token of static method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\CsrfToken\\:\\:isValid\\(\\) expects string, mixed given\\.$#" + count: 1 + path: application/forms/MoveNodeForm.php + + - + message: "#^Parameter \\#2 \\$from of method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:moveNode\\(\\) expects int, mixed given\\.$#" + count: 1 + path: application/forms/MoveNodeForm.php + + - + message: "#^Parameter \\#3 \\$to of method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:moveNode\\(\\) expects int, mixed given\\.$#" + count: 1 + path: application/forms/MoveNodeForm.php + + - + message: "#^Parameter \\#4 \\$newParent of method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:moveNode\\(\\) expects string, mixed given\\.$#" + count: 1 + path: application/forms/MoveNodeForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\MoveNodeForm\\:\\:\\$parentNode \\(Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\) does not accept Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null\\.$#" + count: 1 + path: application/forms/MoveNodeForm.php + + - + message: "#^Cannot call method setValue\\(\\) on Zend_Form_Element\\|null\\.$#" + count: 4 + path: application/forms/ProcessForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\ProcessForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/ProcessForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\ProcessForm\\:\\:setup\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/ProcessForm.php + + - + message: "#^Parameter \\#1 \\$nodeName of method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:createNode\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\Node\\|string, mixed given\\.$#" + count: 1 + path: application/forms/ProcessForm.php + + - + message: "#^Cannot access property \\$acknowledged on mixed\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Cannot access property \\$in_downtime on mixed\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Cannot access property \\$state on mixed\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\SimulationForm\\:\\:enumStateNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\SimulationForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\SimulationForm\\:\\:setNode\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\SimulationForm\\:\\:setNode\\(\\) has parameter \\$node with no type specified\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\SimulationForm\\:\\:setSimulation\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Forms\\\\SimulationForm\\:\\:setup\\(\\) has no return type specified\\.$#" + count: 1 + path: application/forms/SimulationForm.php + + - + message: "#^Method Zend_View_Helper_FormSimpleNote\\:\\:formSimpleNote\\(\\) has no return type specified\\.$#" + count: 1 + path: application/views/helpers/FormSimpleNote.php + + - + message: "#^Method Zend_View_Helper_FormSimpleNote\\:\\:formSimpleNote\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: application/views/helpers/FormSimpleNote.php + + - + message: "#^Method Zend_View_Helper_FormSimpleNote\\:\\:formSimpleNote\\(\\) has parameter \\$value with no type specified\\.$#" + count: 1 + path: application/views/helpers/FormSimpleNote.php + + - + message: "#^Method Zend_View_Helper_RenderStateBadges\\:\\:renderStateBadges\\(\\) has no return type specified\\.$#" + count: 1 + path: application/views/helpers/RenderStateBadges.php + + - + message: "#^Method Zend_View_Helper_RenderStateBadges\\:\\:renderStateBadges\\(\\) has parameter \\$summary with no type specified\\.$#" + count: 1 + path: application/views/helpers/RenderStateBadges.php + + - + message: "#^Cannot access offset 0 on array\\\\|false\\.$#" + count: 2 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Cannot use array destructuring on array\\\\|false\\.$#" + count: 2 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:addNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:addRootNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:addRootNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:beginLoopDetection\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:beginLoopDetection\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:calculateAllStates\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:clearAllStates\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:clearAppliedChanges\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:countSimulations\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createHost\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createHost\\(\\) has parameter \\$host with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createImportedNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createImportedNode\\(\\) has parameter \\$config with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createImportedNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createMissingBp\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createMissingBp\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createService\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createService\\(\\) has parameter \\$host with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:createService\\(\\) has parameter \\$service with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:endLoopDetection\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:endLoopDetection\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:escapeName\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getBackend\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getBackendName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getBpNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getErrors\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getImportedConfig\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getImportedConfig\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getImportedNodes\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getMissingChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getNodes\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getStateType\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getTitle\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getWarnings\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasBackend\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasBackendName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasBeenChanged\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasBpNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasRootNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasRootNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasSimulations\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:hasTitle\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:isReferenced\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:isRootNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:isRootNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:listBpNodes\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:listInvolvedConfigs\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:listInvolvedConfigs\\(\\) has parameter \\$configs with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:listInvolvedHostNames\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:listInvolvedHostNames\\(\\) has parameter \\$usedConfigs with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:listRootNodes\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:removeNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:removeNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:removeRootNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:removeRootNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:setBackend\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:setBackend\\(\\) has parameter \\$backend with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:setName\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:setTitle\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:setTitle\\(\\) has parameter \\$title with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:splitNodeName\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:toArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:translate\\(\\) has parameter \\$msg with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:useHardStates\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:useSoftStates\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:usesHardStates\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:usesSoftStates\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:warn\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:warn\\(\\) has parameter \\$msg with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Parameter \\#1 \\$alias of method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setAlias\\(\\) expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Parameter \\#1 \\$format of function sprintf expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Parameter \\#2 \\$values of function vsprintf expects array\\, array\\ given\\.$#" + count: 2 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:\\$changeCount has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:\\$errors type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:\\$hosts type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:\\$loopDetection has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:\\$nodes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:\\$root_nodes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:\\$simulationCount has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:\\$warnings type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpConfig.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:__construct\\(\\) has parameter \\$object with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:assertNumericOperator\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:assertValidOperator\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:assertValidOperator\\(\\) has parameter \\$operator with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:checkForLoops\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getChildBpNodes\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getChildByName\\(\\) has parameter \\$childName with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getChildNames\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getChildren\\(\\) has parameter \\$filter with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getDisplay\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getHtmlId\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getInfoUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getMissingChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getOperator\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getProblemTree\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getProblemTreeBlame\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getProblematicChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getState\\(\\) should return int but returns int\\|null\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getStateOverrides\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getStateOverrides\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:getStateSummary\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:hasChild\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:hasChild\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:hasChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:hasChildren\\(\\) has parameter \\$filter with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:hasInfoUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:hasProblems\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:invertSortingState\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:invertSortingState\\(\\) has parameter \\$state with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:isEmpty\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:isMissing\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:operatorHtml\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:removeChild\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:removeChild\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setChildNames\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setChildNames\\(\\) has parameter \\$names with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setDisplay\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setDisplay\\(\\) has parameter \\$display with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setInfoUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setInfoUrl\\(\\) has parameter \\$url with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setOperator\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setOperator\\(\\) has parameter \\$operator with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setStateOverrides\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setStateOverrides\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:setStateOverrides\\(\\) has parameter \\$overrides with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Parameter \\#2 \\$array of function array_key_exists expects array, array\\\\|null given\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$childNames type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$className has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$counters has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$display has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$empty has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$emptyStateSummary has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$missing has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$missingChildren has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$operator has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$sortStateInversionMap has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$stateOverrides has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\:\\:\\$url has no type specified\\.$#" + count: 1 + path: library/Businessprocess/BpNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Director\\\\ShipConfigFiles\\:\\:fetchFiles\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Director/ShipConfigFiles.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\HostNode\\:\\:__construct\\(\\) has parameter \\$object with no type specified\\.$#" + count: 1 + path: library/Businessprocess/HostNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\HostNode\\:\\:getHostname\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/HostNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\HostNode\\:\\:getUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/HostNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\HostNode\\:\\:\\$className has no type specified\\.$#" + count: 1 + path: library/Businessprocess/HostNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\HostNode\\:\\:\\$hostname has no type specified\\.$#" + count: 1 + path: library/Businessprocess/HostNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\HostNode\\:\\:\\$sortStateToStateMap has no type specified\\.$#" + count: 1 + path: library/Businessprocess/HostNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\HostNode\\:\\:\\$stateNames has no type specified\\.$#" + count: 1 + path: library/Businessprocess/HostNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\HostNode\\:\\:\\$stateToSortStateMap has no type specified\\.$#" + count: 1 + path: library/Businessprocess/HostNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:applyIcingaDbRestrictions\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:applyIcingaDbRestrictions\\(\\) has parameter \\$query with no type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:fetchDb\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:fetchHosts\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:fetchHosts\\(\\) has parameter \\$filter with no type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:fetchServices\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:fetchServices\\(\\) has parameter \\$filter with no type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:yieldHostnames\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:yieldHostnames\\(\\) has parameter \\$filter with no type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:yieldServicenames\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\IcingaDbObject\\:\\:yieldServicenames\\(\\) has parameter \\$host with no type specified\\.$#" + count: 1 + path: library/Businessprocess/IcingaDbObject.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ImportedNode\\:\\:__construct\\(\\) has parameter \\$object with no type specified\\.$#" + count: 1 + path: library/Businessprocess/ImportedNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ImportedNode\\:\\:getBpConfig\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ImportedNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ImportedNode\\:\\:getChildNames\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ImportedNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ImportedNode\\:\\:getIdentifier\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ImportedNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ImportedNode\\:\\:getOperator\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ImportedNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ImportedNode\\:\\:isMissing\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ImportedNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:__construct\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:assertKeyExists\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:assertKeyExists\\(\\) has parameter \\$key with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:canModify\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:canRead\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:get\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:get\\(\\) has parameter \\$default with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:get\\(\\) has parameter \\$key with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:getAuth\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:getExtendedTitle\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:getProperties\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:getTitle\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:has\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:has\\(\\) has parameter \\$key with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:hasKey\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:hasKey\\(\\) has parameter \\$key with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:hasOneOfTheAllowedRoles\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:hasRestrictions\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:isInAllowedUserList\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:isInAllowedUserList\\(\\) has parameter \\$username with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:isManuallyOrdered\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:isMemberOfAllowedGroups\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:isNull\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:isNull\\(\\) has parameter \\$key with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:listAllowedGroups\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:listAllowedRoles\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:listAllowedUsers\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:nameIsPrefixedWithOneOf\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:nameIsPrefixedWithOneOf\\(\\) has parameter \\$prefixes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:ownerIs\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:ownerIs\\(\\) has parameter \\$username with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:set\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:set\\(\\) has parameter \\$key with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:set\\(\\) has parameter \\$value with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:splitCommaSeparated\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:splitCommaSeparated\\(\\) has parameter \\$string with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:userCanRead\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Metadata\\:\\:\\$properties has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Metadata.php + + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Cannot access offset 'actionName' on mixed\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Cannot access offset 'nodeName' on mixed\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Cannot access offset 'properties' on mixed\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\:\\:create\\(\\) should return static\\(Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\) but returns object\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\:\\:error\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\:\\:hasNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\:\\:serialize\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\:\\:unSerialize\\(\\) has parameter \\$string with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^PHPDoc tag @param has invalid value \\(mixed \\.\\.\\.\\)\\: Unexpected token \"\\\\n \\*\", expected variable at offset 100$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Parameter \\#1 \\$actionName of static method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\:\\:create\\(\\) expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Parameter \\#1 \\$string of function ucfirst expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Parameter \\#2 \\$nodeName of static method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\:\\:create\\(\\) expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\:\\:\\$preserveProperties type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAction.php + + - + message: "#^Cannot use array destructuring on array\\\\|false\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAddChildrenAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAddChildrenAction\\:\\:getChildren\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAddChildrenAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAddChildrenAction\\:\\:setChildren\\(\\) has parameter \\$children with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAddChildrenAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAddChildrenAction\\:\\:\\$children has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAddChildrenAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAddChildrenAction\\:\\:\\$preserveProperties type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeAddChildrenAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeApplyManualOrderAction\\:\\:applyManualSorting\\(\\) has parameter \\$bpNodes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeApplyManualOrderAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeApplyManualOrderAction\\:\\:applyManualSorting\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeApplyManualOrderAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeApplyManualOrderAction\\:\\:sort\\(\\) has parameter \\$nodes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeApplyManualOrderAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeApplyManualOrderAction\\:\\:sort\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeApplyManualOrderAction.php + + - + message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeApplyManualOrderAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCopyAction\\:\\:applyManualSorting\\(\\) has parameter \\$bpNodes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCopyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCopyAction\\:\\:applyManualSorting\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCopyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCopyAction\\:\\:sort\\(\\) has parameter \\$nodes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCopyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCopyAction\\:\\:sort\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCopyAction.php + + - + message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCopyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCreateAction\\:\\:getProperties\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCreateAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCreateAction\\:\\:setParent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCreateAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCreateAction\\:\\:setParentName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCreateAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCreateAction\\:\\:setProperties\\(\\) has parameter \\$properties with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCreateAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCreateAction\\:\\:\\$preserveProperties type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCreateAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeCreateAction\\:\\:\\$properties type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeCreateAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeModifyAction\\:\\:getFormerProperties\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeModifyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeModifyAction\\:\\:getProperties\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeModifyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeModifyAction\\:\\:setFormerProperties\\(\\) has parameter \\$properties with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeModifyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeModifyAction\\:\\:setNodeProperties\\(\\) has parameter \\$properties with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeModifyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeModifyAction\\:\\:setProperties\\(\\) has parameter \\$properties with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeModifyAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeModifyAction\\:\\:\\$formerProperties has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeModifyAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeModifyAction\\:\\:\\$preserveProperties type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeModifyAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeModifyAction\\:\\:\\$properties has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeModifyAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:applyManualSorting\\(\\) has parameter \\$bpNodes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:applyManualSorting\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:getFrom\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:getNewParent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:getParent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:getTo\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:setFrom\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:setFrom\\(\\) has parameter \\$from with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:setNewParent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:setNewParent\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:setParent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:setParent\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:setTo\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:setTo\\(\\) has parameter \\$to with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:sort\\(\\) has parameter \\$nodes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:sort\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:\\$from \\(int\\) does not accept int\\|false\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:\\$from \\(int\\) does not accept int\\|string\\|false\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:\\$preserveProperties type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:\\$to \\(int\\) does not accept int\\|false\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeMoveAction\\:\\:\\$to \\(int\\) does not accept int\\|string\\|false\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeMoveAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeRemoveAction\\:\\:setParentName\\(\\) has parameter \\$parentName with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeRemoveAction.php + + - + message: "#^Parameter \\#1 \\$name of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getNode\\(\\) expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeRemoveAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeRemoveAction\\:\\:\\$parentName has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeRemoveAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeRemoveAction\\:\\:\\$preserveProperties type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/NodeRemoveAction.php + + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:addChildrenToNode\\(\\) has parameter \\$children with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:copyNode\\(\\) has parameter \\$nodeName with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:createNode\\(\\) has parameter \\$properties with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:hasBeenModified\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:modifyNode\\(\\) has parameter \\$properties with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:pop\\(\\) should return bool\\|Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction but returns Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\|null\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:serialize\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\ProcessChanges\\:\\:shift\\(\\) should return bool\\|Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction but returns Icinga\\\\Module\\\\Businessprocess\\\\Modification\\\\NodeAction\\|null\\.$#" + count: 1 + path: library/Businessprocess/Modification/ProcessChanges.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\MonitoredNode\\:\\:getLink\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/MonitoredNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\MonitoredNode\\:\\:getUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/MonitoredNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Monitoring\\\\Backend\\\\Ido\\\\Query\\\\HostStatusQuery\\:\\:joinCustomvar\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Monitoring\\\\Backend\\\\Ido\\\\Query\\\\HostStatusQuery\\:\\:joinCustomvar\\(\\) has parameter \\$customvar with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php + + - + message: "#^Parameter \\#2 \\$array of function array_key_exists expects array, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php + + - + message: "#^Parameter \\#4 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Monitoring\\\\Backend\\\\Ido\\\\Query\\\\HostStatusQuery\\:\\:\\$customVarsJoinTemplate has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/HostStatusQuery.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Monitoring\\\\Backend\\\\Ido\\\\Query\\\\ServiceStatusQuery\\:\\:joinCustomvar\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/ServiceStatusQuery.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Monitoring\\\\Backend\\\\Ido\\\\Query\\\\ServiceStatusQuery\\:\\:joinCustomvar\\(\\) has parameter \\$customvar with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/ServiceStatusQuery.php + + - + message: "#^Parameter \\#2 \\$array of function array_key_exists expects array, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/ServiceStatusQuery.php + + - + message: "#^Parameter \\#4 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/ServiceStatusQuery.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Monitoring\\\\Backend\\\\Ido\\\\Query\\\\ServiceStatusQuery\\:\\:\\$customVarsJoinTemplate has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/Backend/Ido/Query/ServiceStatusQuery.php + + - + message: "#^Call to an undefined method Icinga\\\\Data\\\\ConnectionInterface\\:\\:getResource\\(\\)\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/DataView/HostStatus.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Monitoring\\\\DataView\\\\HostStatus\\:\\:__construct\\(\\) has parameter \\$columns with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/DataView/HostStatus.php + + - + message: "#^Call to an undefined method Icinga\\\\Data\\\\ConnectionInterface\\:\\:getResource\\(\\)\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/DataView/ServiceStatus.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Monitoring\\\\DataView\\\\ServiceStatus\\:\\:__construct\\(\\) has parameter \\$columns with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Monitoring/DataView/ServiceStatus.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:addParent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:countChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:countChildren\\(\\) has parameter \\$filter with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:enumStateNames\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getBpConfig\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getChildren\\(\\) has parameter \\$filter with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getDuration\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getIdentifier\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getLastStateChange\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getLink\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getMissingChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getObjectClassName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getOperators\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getPaths\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getSortingState\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getSortingState\\(\\) has parameter \\$state with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getState\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getStateName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:getStateName\\(\\) has parameter \\$state with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasAlias\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasBeenChanged\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasChildren\\(\\) has parameter \\$filter with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasInfoUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasMissingChildren\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasParentName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasParentName\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:hasParents\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:isAcknowledged\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:isEmpty\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:isHandled\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:isInDowntime\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:isMissing\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:isProblem\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:operatorHtml\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:removeParent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:removeParent\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setAck\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setAck\\(\\) has parameter \\$ack with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setAckIsOk\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setBpConfig\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setDowntime\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setDowntime\\(\\) has parameter \\$downtime with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setDowntimeIsOk\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setLastStateChange\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setLastStateChange\\(\\) has parameter \\$timestamp with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setMissing\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setMissing\\(\\) has parameter \\$missing with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setState\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:setState\\(\\) has parameter \\$state with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:sortStateTostate\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:sortStateTostate\\(\\) has parameter \\$sortState with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:stateToSortState\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:stateToSortState\\(\\) has parameter \\$state with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:toArray\\(\\) has parameter \\$parent with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:toArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:\\$className has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:\\$duration has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:\\$empty has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:\\$missing has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:\\$parents type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:\\$sortStateToStateMap has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:\\$stateNames has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Node\\:\\:\\$stateToSortStateMap has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Node.php + + - + message: "#^Parameter \\#1 \\$name of static method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:joinNodeName\\(\\) expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Icingadb/HostActions.php + + - + message: "#^Cannot access property \\$name on mixed\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Icingadb/ServiceActions.php + + - + message: "#^Parameter \\#2 \\$suffix of static method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:joinNodeName\\(\\) expects string\\|null, mixed given\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Icingadb/ServiceActions.php + + - + message: "#^Cannot access offset 'icingacli…' on mixed\\.$#" + count: 2 + path: library/Businessprocess/ProvidedHook/Icingadb/ServiceDetailExtension.php + + - + message: "#^Cannot access offset 'icingaweb…' on mixed\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Icingadb/ServiceDetailExtension.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ProvidedHook\\\\Icingadb\\\\ServiceDetailExtension\\:\\:init\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Icingadb/ServiceDetailExtension.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\ProvidedHook\\\\Icingadb\\\\ServiceDetailExtension\\:\\:\\$commandName \\(string\\) does not accept mixed\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Icingadb/ServiceDetailExtension.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ProvidedHook\\\\Monitoring\\\\DetailviewExtension\\:\\:init\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Monitoring/DetailviewExtension.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\ProvidedHook\\\\Monitoring\\\\DetailviewExtension\\:\\:\\$commandName \\(string\\) does not accept mixed\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Monitoring/DetailviewExtension.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ProvidedHook\\\\Monitoring\\\\HostActions\\:\\:getActionsForHost\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Monitoring/HostActions.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ProvidedHook\\\\Monitoring\\\\ServiceActions\\:\\:getActionsForService\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/ProvidedHook/Monitoring/ServiceActions.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Breadcrumb\\:\\:renderNode\\(\\) has parameter \\$path with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Breadcrumb.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Breadcrumb\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Breadcrumb.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:applyManualSorting\\(\\) has parameter \\$bpNodes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:applyManualSorting\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:createBadge\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:createBadge\\(\\) has parameter \\$state with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:createBadge\\(\\) has parameter \\$summary with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:createBadgeGroup\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:createBadgeGroup\\(\\) has parameter \\$state with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:createBadgeGroup\\(\\) has parameter \\$summary with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:createUnboundParent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:getCurrentPath\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:getId\\(\\) has parameter \\$path with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:getNodeClasses\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:getPath\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:getUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:isBreadcrumb\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:renderStateBadges\\(\\) has parameter \\$summary with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:renderStateBadges\\(\\) has parameter \\$totalChildren with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:rendersImportedNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:setParentNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:setPath\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:setPath\\(\\) has parameter \\$path with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:sort\\(\\) has parameter \\$nodes with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:sort\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:\\$parent \\(Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\) does not accept Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|null\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:\\$path type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/Renderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\:\\:assemble\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:__construct\\(\\) has parameter \\$path with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:actions\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:addActionLinks\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:addActions\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:addDetailsActions\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:buildBaseNodeUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:getMainNodeUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:makeBpUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:\\$name has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:\\$node has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:\\$path has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TileRenderer\\\\NodeTile\\:\\:\\$renderer has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TileRenderer/NodeTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:actionIcon\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:actionIcon\\(\\) has parameter \\$icon with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:actionIcon\\(\\) has parameter \\$title with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:actionIcon\\(\\) has parameter \\$url with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:assemble\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:createEditAction\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:createInfoAction\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:createSimulationAction\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:getActionIcons\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:getNodeIcons\\(\\) has parameter \\$path with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:getOverriddenState\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:getOverriddenState\\(\\) has parameter \\$fakeState with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:getStateClassNames\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:renderAddNewNode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:renderAddNewNode\\(\\) has parameter \\$parent with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:renderBp\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:renderChild\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:renderChild\\(\\) has parameter \\$bp with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:renderChild\\(\\) has parameter \\$path with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:renderNode\\(\\) has parameter \\$path with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Parameter \\#1 \\$node of method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:getSourceUrl\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\BpNode, Icinga\\\\Module\\\\Businessprocess\\\\Node given\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Parameter \\#2 \\$parent of method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\TreeRenderer\\:\\:renderChild\\(\\) expects Icinga\\\\Module\\\\Businessprocess\\\\BpNode, Icinga\\\\Module\\\\Businessprocess\\\\Node given\\.$#" + count: 1 + path: library/Businessprocess/Renderer/TreeRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ServiceNode\\:\\:__construct\\(\\) has parameter \\$object with no type specified\\.$#" + count: 1 + path: library/Businessprocess/ServiceNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ServiceNode\\:\\:getHostname\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ServiceNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ServiceNode\\:\\:getServiceDescription\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ServiceNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\ServiceNode\\:\\:getUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/ServiceNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\ServiceNode\\:\\:\\$className has no type specified\\.$#" + count: 1 + path: library/Businessprocess/ServiceNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\ServiceNode\\:\\:\\$hostname has no type specified\\.$#" + count: 1 + path: library/Businessprocess/ServiceNode.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\ServiceNode\\:\\:\\$service has no type specified\\.$#" + count: 1 + path: library/Businessprocess/ServiceNode.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:__construct\\(\\) has parameter \\$simulations with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:create\\(\\) has parameter \\$simulations with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:getNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:hasNode\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:remove\\(\\) has parameter \\$node with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:set\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:set\\(\\) has parameter \\$node with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:set\\(\\) has parameter \\$properties with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:setSimulations\\(\\) has parameter \\$simulations with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:simulations\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:\\$simulations \\(array\\) does not accept mixed\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Simulation\\:\\:\\$simulations type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Simulation.php + + - + message: "#^Cannot access property \\$hex_id on mixed\\.$#" + count: 8 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Cannot access property \\$id on mixed\\.$#" + count: 6 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\IcingaDbState\\:\\:apply\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\IcingaDbState\\:\\:handleDbRow\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\IcingaDbState\\:\\:handleDbRow\\(\\) has parameter \\$row with no type specified\\.$#" + count: 1 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\IcingaDbState\\:\\:handleDbRow\\(\\) has parameter \\$type with no type specified\\.$#" + count: 1 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\IcingaDbState\\:\\:reallyRetrieveStatesFromBackend\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\IcingaDbState\\:\\:retrieveStatesFromBackend\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Parameter \\#1 \\$msg of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:addError\\(\\) expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Parameter \\#2 \\.\\.\\.\\$arrays of function array_merge expects array, mixed given\\.$#" + count: 2 + path: library/Businessprocess/State/IcingaDbState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\MonitoringState\\:\\:apply\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/State/MonitoringState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\MonitoringState\\:\\:handleDbRow\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/State/MonitoringState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\MonitoringState\\:\\:handleDbRow\\(\\) has parameter \\$row with no type specified\\.$#" + count: 1 + path: library/Businessprocess/State/MonitoringState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\MonitoringState\\:\\:reallyRetrieveStatesFromBackend\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/State/MonitoringState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\State\\\\MonitoringState\\:\\:retrieveStatesFromBackend\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/State/MonitoringState.php + + - + message: "#^Parameter \\#1 \\$msg of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:addError\\(\\) expects string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/State/MonitoringState.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:__construct\\(\\) has parameter \\$a with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:__construct\\(\\) has parameter \\$b with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:create\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:create\\(\\) has parameter \\$a with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:create\\(\\) has parameter \\$b with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:renderHtmlInline\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:renderHtmlSideBySide\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:renderTextContext\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:renderTextUnified\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:\\$a has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:\\$b has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:\\$diff has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\ConfigDiff\\:\\:\\$opcodes has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/ConfigDiff.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 5 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Cannot use array destructuring on array\\\\|false\\.$#" + count: 7 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:__construct\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:emptyHeader\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseDisplay\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseDisplay\\(\\) has parameter \\$line with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseError\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseError\\(\\) has parameter \\$msg with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseExtraLine\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseExtraLine\\(\\) has parameter \\$line with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseExtraLine\\(\\) has parameter \\$typeLength with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseFile\\(\\) has parameter \\$filename with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseFile\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseHeaderLine\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseHeaderLine\\(\\) has parameter \\$line with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseInfoUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseInfoUrl\\(\\) has parameter \\$line with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseLine\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseLine\\(\\) has parameter \\$line with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseStateOverrides\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseStateOverrides\\(\\) has parameter \\$line with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseString\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:parseString\\(\\) has parameter \\$string with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:readHeaderString\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:readHeaderString\\(\\) has parameter \\$string with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:readMetadataFromFileHeader\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:readMetadataFromFileHeader\\(\\) has parameter \\$filename with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:readMetadataFromFileHeader\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:readMetadataFromString\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:readMetadataFromString\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:readMetadataFromString\\(\\) has parameter \\$string with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:reallyParseFile\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:reallyParseFile\\(\\) has parameter \\$filename with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:resolveMissingNodes\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:splitCommaSeparated\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:splitCommaSeparated\\(\\) has parameter \\$string with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Offset 0 does not exist on string\\|null\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Parameter \\#1 \\$array of function array_shift expects array, array\\\\|false given\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|null given\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Parameter \\#1 \\$name of method Icinga\\\\Module\\\\Businessprocess\\\\BpConfig\\:\\:getNode\\(\\) expects string, string\\|null given\\.$#" + count: 2 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Parameter \\#1 \\$stream of function fgets expects resource, resource\\|false given\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|null given\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_split expects string, string\\|null given\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:\\$missingNodes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigParser\\:\\:\\$name has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigParser.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigRenderer\\:\\:renderStateOverrides\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigRenderer.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigRenderer\\:\\:\\$config has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigRenderer.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyConfigRenderer\\:\\:\\$renderedNodes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyConfigRenderer.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:deleteProcess\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:getConfigDir\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:getFilename\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:getFilename\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:getSource\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:getSource\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:hasProcess\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:listAllProcessNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:listProcessNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:listProcesses\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:loadFromString\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:loadFromString\\(\\) has parameter \\$string with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:loadProcess\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\LegacyStorage\\:\\:prepareDefaultConfigDir\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/LegacyStorage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\Storage\\:\\:deleteProcess\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/Storage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\Storage\\:\\:getInstance\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/Storage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\Storage\\:\\:hasProcess\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/Storage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\Storage\\:\\:init\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/Storage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\Storage\\:\\:listAllProcessNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/Storage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\Storage\\:\\:listProcessNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/Storage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\Storage\\:\\:listProcesses\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Storage/Storage.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Storage\\\\Storage\\:\\:loadProcess\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Storage/Storage.php + + - + message: "#^Call to an undefined method Icinga\\\\Web\\\\Request\\:\\:shouldReceive\\(\\)\\.$#" + count: 1 + path: library/Businessprocess/Test/BaseTestCase.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Test\\\\BaseTestCase\\:\\:emptyConfigSection\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Test/BaseTestCase.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Test\\\\BaseTestCase\\:\\:makeLoop\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Test/BaseTestCase.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Test\\\\Bootstrap\\:\\:cli\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Test/Bootstrap.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Test\\\\Bootstrap\\:\\:cli\\(\\) has parameter \\$basedir with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Test/Bootstrap.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\ActionBar\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/ActionBar.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:__construct\\(\\) has parameter \\$attributes with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/BpDashboardTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:__construct\\(\\) has parameter \\$description with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/BpDashboardTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:__construct\\(\\) has parameter \\$icon with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/BpDashboardTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:__construct\\(\\) has parameter \\$title with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/BpDashboardTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:__construct\\(\\) has parameter \\$url with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/BpDashboardTile.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:__construct\\(\\) has parameter \\$urlParams with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/BpDashboardTile.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/BpDashboardTile.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\Content\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/Content.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\Controls\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/Controls.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\Dashboard\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/Dashboard.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:__construct\\(\\) has parameter \\$attributes with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/DashboardAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:__construct\\(\\) has parameter \\$description with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/DashboardAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:__construct\\(\\) has parameter \\$icon with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/DashboardAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:__construct\\(\\) has parameter \\$title with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/DashboardAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:__construct\\(\\) has parameter \\$url with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/DashboardAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:__construct\\(\\) has parameter \\$urlParams with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/DashboardAction.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/DashboardAction.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\RenderedProcessActionBar\\:\\:currentProcessParams\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/RenderedProcessActionBar.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\WtfTabs\\:\\:render\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Component/WtfTabs.php + + - + message: "#^Access to an undefined property Zend_Controller_Action_HelperBroker\\:\\:\\$viewRenderer\\.$#" + count: 3 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Call to an undefined method Zend_Controller_Action_HelperBroker\\:\\:layout\\(\\)\\.$#" + count: 2 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:addTitle\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:addTitle\\(\\) has parameter \\$title with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:doNotRender\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:loadBpConfig\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:loadForm\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:loadForm\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:loadModifiedBpConfig\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:session\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:setViewScript\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:setViewScript\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Controller\\:\\:singleTab\\(\\) has parameter \\$label with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Parameter \\#1 \\$key of function array_key_exists expects int\\|string, mixed given\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Parameter \\#2 \\$values of function vsprintf expects array\\, array\\ given\\.$#" + count: 1 + path: library/Businessprocess/Web/Controller.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\FakeRequest\\:\\:getBaseUrl\\(\\) has parameter \\$raw with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/FakeRequest.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\FakeRequest\\:\\:setConfiguredBaseUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/FakeRequest.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\FakeRequest\\:\\:setConfiguredBaseUrl\\(\\) has parameter \\$url with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/FakeRequest.php + + - + message: "#^Cannot call method addError\\(\\) on Zend_Form_Element\\|null\\.$#" + count: 2 + path: library/Businessprocess/Web/Form/BpConfigBaseForm.php + + - + message: "#^Cannot call method getUsername\\(\\) on Icinga\\\\User\\|null\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/BpConfigBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\BpConfigBaseForm\\:\\:listAvailableBackends\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/BpConfigBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\BpConfigBaseForm\\:\\:prepareMetadata\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/BpConfigBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\BpConfigBaseForm\\:\\:setPreferredDecorators\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/BpConfigBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\CsrfToken\\:\\:getSessionId\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/CsrfToken.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\Element\\\\IplStateOverrides\\:\\:assemble\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/Element/IplStateOverrides.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\Element\\\\IplStateOverrides\\:\\:getOptions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/Element/IplStateOverrides.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\Element\\\\IplStateOverrides\\:\\:getValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/Element/IplStateOverrides.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\Element\\\\IplStateOverrides\\:\\:registerAttributeCallbacks\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/Element/IplStateOverrides.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\Element\\\\IplStateOverrides\\:\\:setOptions\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/Element/IplStateOverrides.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\Element\\\\IplStateOverrides\\:\\:\\$options type has no value type specified in iterable type array\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/Element/IplStateOverrides.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\FormLoader\\:\\:load\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/FormLoader.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\FormLoader\\:\\:load\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/FormLoader.php + + - + message: "#^Parameter \\#1 \\$array of function array_pop expects array, array\\\\|false given\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/FormLoader.php + + - + message: "#^Cannot call method setDecorators\\(\\) on Zend_Form_Element\\|null\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Cannot call method setValue\\(\\) on Zend_Form_Element\\|null\\.$#" + count: 2 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHidden\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHidden\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHidden\\(\\) has parameter \\$value with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHtml\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHtml\\(\\) has parameter \\$html with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHtml\\(\\) has parameter \\$options with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHtmlHint\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHtmlHint\\(\\) has parameter \\$html with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addHtmlHint\\(\\) has parameter \\$options with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addPrefixPathsForBusinessprocess\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:addPrefixPathsForModule\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:callZfConstructor\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:callZfConstructor\\(\\) has parameter \\$options with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:handleOptions\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:handleOptions\\(\\) has parameter \\$options with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:initializePrefixPaths\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:loadForm\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:loadForm\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:optionalEnum\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:optionalEnum\\(\\) has parameter \\$enum with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:optionalEnum\\(\\) has parameter \\$nullLabel with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:setIcingaModule\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:translate\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:translate\\(\\) has parameter \\$string with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:valueIsEmpty\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:valueIsEmpty\\(\\) has parameter \\$value with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:\\$hintCount has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickBaseForm\\:\\:\\$icingaModuleName has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickBaseForm.php + + - + message: "#^Cannot call method setHttpResponseCode\\(\\) on Zend_Controller_Response_Abstract\\|null\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Cannot call method setIgnore\\(\\) on Zend_Form_Element\\|null\\.$#" + count: 2 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:addException\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:addException\\(\\) has parameter \\$elementName with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:addSimpleDisplayGroup\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:addSimpleDisplayGroup\\(\\) has parameter \\$elements with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:addSimpleDisplayGroup\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:addSimpleDisplayGroup\\(\\) has parameter \\$options with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:addSubmitButtonIfSet\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:beforeSetup\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:beforeValidation\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:beforeValidation\\(\\) has parameter \\$data with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:createIdElement\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:detectName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:getActionFromRequest\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:getSentValue\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:getSentValue\\(\\) has parameter \\$default with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:getSentValue\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:getSubmitLabel\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:getSuccessMessage\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:getSuccessMessage\\(\\) has parameter \\$message with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:getSuccessUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:handleRequest\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:hasBeenSent\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:hasBeenSubmitted\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:hasSubmitButton\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:isApiRequest\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:notifyError\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:notifyError\\(\\) has parameter \\$message with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:notifySuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:notifySuccess\\(\\) has parameter \\$message with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:onFailure\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:onRequest\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:onSetup\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:onSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:prepareElements\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:pressedButton\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:pressedButton\\(\\) has parameter \\$label with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:pressedButton\\(\\) has parameter \\$name with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:redirectAndExit\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:redirectAndExit\\(\\) has parameter \\$url with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:redirectOnSuccess\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:redirectOnSuccess\\(\\) has parameter \\$message with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:regenerateCsrfToken\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:removeCsrfToken\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setApiRequest\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setApiRequest\\(\\) has parameter \\$isApiRequest with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setHttpResponseCode\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setHttpResponseCode\\(\\) has parameter \\$code with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setPreferredDecorators\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setRequest\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setSubmitLabel\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setSubmitLabel\\(\\) has parameter \\$label with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setSuccessMessage\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setSuccessMessage\\(\\) has parameter \\$message with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setSuccessUrl\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setSuccessUrl\\(\\) has parameter \\$params with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setSuccessUrl\\(\\) has parameter \\$url with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:setup\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Parameter \\#1 \\$array of function array_pop expects array, array\\\\|false given\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$deleteButtonName has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$didSetup has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$fakeSubmitButtonName has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$formName has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$hasBeenSent has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$hasBeenSubmitted has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$isApiRequest has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$request has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$submitButtonName has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$submitLabel has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Form\\\\QuickForm\\:\\:\\$successMessage has no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/QuickForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Businessprocess\\\\BpNode\\|Icinga\\\\Module\\\\Businessprocess\\\\MonitoredNode\\:\\:addChild\\(\\)\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php + + - + message: "#^Parameter \\#1 \\$label of method ipl\\\\Web\\\\FormElement\\\\TermInput\\\\Term\\:\\:setLabel\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: library/Businessprocess/Web/Form/Validator/HostServiceTermValidator.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Navigation\\\\Renderer\\\\ProcessProblemsBadge\\:\\:getBpConfigName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Navigation/Renderer/ProcessProblemsBadge.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Navigation\\\\Renderer\\\\ProcessProblemsBadge\\:\\:setBpConfigName\\(\\) has no return type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Navigation/Renderer/ProcessProblemsBadge.php + + - + message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Navigation\\\\Renderer\\\\ProcessProblemsBadge\\:\\:setBpConfigName\\(\\) has parameter \\$bpConfigName with no type specified\\.$#" + count: 1 + path: library/Businessprocess/Web/Navigation/Renderer/ProcessProblemsBadge.php diff --git a/phpstan.neon b/phpstan.neon index 9698adb..d4fbc54 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,8 @@ +includes: + - phpstan-baseline.neon + parameters: - level: 5 + level: max checkFunctionNameCase: true checkInternalClassCaseSensitivity: true From b1025c6745896ecb05cd8e90a98fb2ec52e70e97 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 23 Aug 2023 15:52:20 +0200 Subject: [PATCH 096/105] phpstan: Don't report errors that we do not acknowledge as errors --- phpstan.neon | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index d4fbc54..8197570 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -16,7 +16,11 @@ parameters: - vendor ignoreErrors: - - '#Unsafe usage of new static\(\)#' + - + messages: + - '#Unsafe usage of new static\(\)#' + - '#. but return statement is missing#' + reportUnmatched: false universalObjectCratesClasses: - Icinga\Web\View From 8e5c3d349fb910b277e368073395bbedcbffc58e Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Thu, 24 Aug 2023 13:38:01 +0200 Subject: [PATCH 097/105] phpstan: Analyze tests is not necessary --- phpstan.neon | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpstan.neon b/phpstan.neon index 8197570..8c09b51 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -15,6 +15,9 @@ parameters: scanDirectories: - vendor + excludePaths: + - library/Businessprocess/Test + ignoreErrors: - messages: From 36cd13ad295c13118b9da6c5d7ef54101385c957 Mon Sep 17 00:00:00 2001 From: Sukhwinder Dhillon Date: Wed, 30 Aug 2023 10:16:31 +0200 Subject: [PATCH 098/105] Github Action: Do not cancel further tests if one fails --- .github/workflows/php.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index eded62d..7171ae8 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -40,16 +40,16 @@ jobs: git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git vendor/icinga-php-thirdparty - name: PHP Lint - if: success() || matrix.allow_failure + if: ${{ ! cancelled() }} run: ./vendor/bin/phplint -n --exclude={^vendor/.*} -- . - name: PHP CodeSniffer - if: success() || matrix.allow_failure + if: ${{ ! cancelled() }} run: phpcs - name: PHPStan + if: ${{ ! cancelled() }} uses: php-actions/phpstan@v3 - if: success() || matrix.allow_failure test: name: Unit tests with php ${{ matrix.php }} on ${{ matrix.os }} From d382738fcf923592646163cdb8f69d5126085698 Mon Sep 17 00:00:00 2001 From: raviks789 <33730024+raviks789@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:45:01 +0200 Subject: [PATCH 099/105] PHPStan: Update baseline --- phpstan-baseline.neon | 60 ------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index b259017..cd648b9 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2800,11 +2800,6 @@ parameters: count: 1 path: library/Businessprocess/Renderer/Breadcrumb.php - - - message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Breadcrumb\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" - count: 1 - path: library/Businessprocess/Renderer/Breadcrumb.php - - message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Renderer\\\\Renderer\\:\\:applyManualSorting\\(\\) has parameter \\$bpNodes with no value type specified in iterable type array\\.$#" count: 1 @@ -3715,36 +3710,6 @@ parameters: count: 1 path: library/Businessprocess/Storage/Storage.php - - - message: "#^Call to an undefined method Icinga\\\\Web\\\\Request\\:\\:shouldReceive\\(\\)\\.$#" - count: 1 - path: library/Businessprocess/Test/BaseTestCase.php - - - - message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Test\\\\BaseTestCase\\:\\:emptyConfigSection\\(\\) has no return type specified\\.$#" - count: 1 - path: library/Businessprocess/Test/BaseTestCase.php - - - - message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Test\\\\BaseTestCase\\:\\:makeLoop\\(\\) has no return type specified\\.$#" - count: 1 - path: library/Businessprocess/Test/BaseTestCase.php - - - - message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Test\\\\Bootstrap\\:\\:cli\\(\\) has no return type specified\\.$#" - count: 1 - path: library/Businessprocess/Test/Bootstrap.php - - - - message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Test\\\\Bootstrap\\:\\:cli\\(\\) has parameter \\$basedir with no type specified\\.$#" - count: 1 - path: library/Businessprocess/Test/Bootstrap.php - - - - message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\ActionBar\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" - count: 1 - path: library/Businessprocess/Web/Component/ActionBar.php - - message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:__construct\\(\\) has parameter \\$attributes with no type specified\\.$#" count: 1 @@ -3775,26 +3740,6 @@ parameters: count: 1 path: library/Businessprocess/Web/Component/BpDashboardTile.php - - - message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\BpDashboardTile\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" - count: 1 - path: library/Businessprocess/Web/Component/BpDashboardTile.php - - - - message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\Content\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" - count: 1 - path: library/Businessprocess/Web/Component/Content.php - - - - message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\Controls\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" - count: 1 - path: library/Businessprocess/Web/Component/Controls.php - - - - message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\Dashboard\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" - count: 1 - path: library/Businessprocess/Web/Component/Dashboard.php - - message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:__construct\\(\\) has parameter \\$attributes with no type specified\\.$#" count: 1 @@ -3825,11 +3770,6 @@ parameters: count: 1 path: library/Businessprocess/Web/Component/DashboardAction.php - - - message: "#^Property Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\DashboardAction\\:\\:\\$defaultAttributes type has no value type specified in iterable type array\\.$#" - count: 1 - path: library/Businessprocess/Web/Component/DashboardAction.php - - message: "#^Method Icinga\\\\Module\\\\Businessprocess\\\\Web\\\\Component\\\\RenderedProcessActionBar\\:\\:currentProcessParams\\(\\) has no return type specified\\.$#" count: 1 From 517fe787af1ea2b97d2566e9b1cb3b2a887abf31 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 12 Oct 2023 09:06:21 +0200 Subject: [PATCH 100/105] Update default branch references --- .github/workflows/L10n-update.yml | 2 +- .github/workflows/php.yml | 4 ++-- README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/L10n-update.yml b/.github/workflows/L10n-update.yml index 9dce59a..45599e8 100644 --- a/.github/workflows/L10n-update.yml +++ b/.github/workflows/L10n-update.yml @@ -3,7 +3,7 @@ name: L10n Update on: push: branches: - - master + - main jobs: trigger-update: diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 7171ae8..37078bb 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -3,11 +3,11 @@ name: PHP Tests on: push: branches: - - master + - main - release/* pull_request: branches: - - master + - main jobs: lint: diff --git a/README.md b/README.md index ea518fe..01f3d91 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Icinga Business Process Modeling [![PHP Support](https://img.shields.io/badge/php-%3E%3D%207.2-777BB4?logo=PHP)](https://php.net/) -![Build Status](https://github.com/icinga/icingaweb2-module-businessprocess/workflows/PHP%20Tests/badge.svg?branch=master) +[![Build Status](https://github.com/Icinga/icingaweb2-module-businessprocess/actions/workflows/php.yml/badge.svg)](https://github.com/Icinga/icingaweb2-module-businessprocess/actions/workflows/php.yml) [![Github Tag](https://img.shields.io/github/tag/Icinga/icingaweb2-module-businessprocess.svg)](https://github.com/Icinga/icingaweb2-module-businessprocess) ![Icinga Logo](https://icinga.com/wp-content/uploads/2014/06/icinga_logo.png) From 148b8f133f144f4133c52405439fcce61bc35c89 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 11 Oct 2023 15:14:11 +0200 Subject: [PATCH 101/105] doc: Adjust accordingly to our new packaging docs --- doc/01-About.md | 7 +++--- doc/02-Installation.md | 32 +++++++++++++----------- doc/02-Installation.md.d/From-Source.md | 15 +++++++++++ doc/03-Getting-Started.md | 13 ++++------ doc/04-Create-your-first-process-node.md | 6 ++--- doc/05-Importing-Processes.md | 9 +++---- doc/06-Customize-Node-Order.md | 9 +++---- doc/09-Operators.md | 12 ++++----- doc/12-Web-Components-Breadcrumb.md | 9 +++---- doc/13-Web-Components-Tile-Renderer.md | 3 +-- doc/14-Web-Components-Tree-Renderer.md | 3 +-- doc/16-Add-To-Dashboard.md | 6 ++--- doc/21-Store-Config.md | 6 ++--- doc/22-Upload-Config.md | 8 +++--- doc/31-Permissions.md | 9 +++---- doc/81-History.md | 11 +++----- 16 files changed, 74 insertions(+), 84 deletions(-) create mode 100644 doc/02-Installation.md.d/From-Source.md diff --git a/doc/01-About.md b/doc/01-About.md index 13eb925..44672b4 100644 --- a/doc/01-About.md +++ b/doc/01-About.md @@ -1,10 +1,9 @@ -# Icinga Business Process Modelling +# Icinga Business Process Modeling If you want to visualize and monitor hierarchical business processes based on -any or all objects monitored by Icinga, the Icinga Web 2 business process -module is the way to go. +objects monitored by Icinga, Icinga Business Process Modeling is the solution. -[![Dashboard](screenshot/16_dashboard/1603_businessprocesses_on_dashboard.png)](doc/16-Add-To-Dashboard.md) +[![Dashboard](screenshot/16_dashboard/1603_businessprocesses_on_dashboard.png)](16-Add-To-Dashboard.md) Want to create custom process-based dashboards? Trigger notifications at process or sub-process level? Provide a quick top-level view for thousands of diff --git a/doc/02-Installation.md b/doc/02-Installation.md index 54fb9e9..6d479b1 100644 --- a/doc/02-Installation.md +++ b/doc/02-Installation.md @@ -1,20 +1,24 @@ -# Installation + +# Installing Icinga Business Process Modeling -## Requirements +The recommended way to install Icinga Business Process Modeling is to use prebuilt packages for +all supported platforms from our official release repository. +Please note that [Icinga Web](https://icinga.com/docs/icinga-web) is required to run Icinga +Business Process Modeling and if it is not already set up, it is best to do this first. -* PHP (>= 7.2) -* Icinga Web 2 (>= 2.9) -* Icinga Web 2 libraries: - * [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (>= 0.8) - * [Icinga PHP Thirdparty](https://github.com/Icinga/icinga-php-thirdparty) (>= 0.11) -* Icinga Web 2 modules: - * The `monitoring` or `icingadb` module needs to be configured and enabled. +The following steps will guide you through installing and setting up Icinga Business Process Modeling. + + -## Install Icinga Business Process Modeling +## Installing the Package -Install it [like any other module](https://icinga.com/docs/icinga-web-2/latest/doc/08-Modules/#installation). -Use `businessprocess` as name. +If the [repository](https://packages.icinga.com) is not configured yet, please add it first. +Then use your distribution's package manager to install the `icinga-businessprocess` package +or install [from source](02-Installation.md.d/From-Source.md). + -## Create your first Business Process definition +## Configuring Icinga Business Process Modeling -That's it, *Business Process* is now ready for use. Please read more on [how to get started](03-Getting-Started.md). +That's it, Icinga Business Process Modeling is now ready to use. +Please read more on [how to get started](03-Getting-Started.md). + diff --git a/doc/02-Installation.md.d/From-Source.md b/doc/02-Installation.md.d/From-Source.md new file mode 100644 index 0000000..6941d54 --- /dev/null +++ b/doc/02-Installation.md.d/From-Source.md @@ -0,0 +1,15 @@ +# Installing Icinga Business Process Modeling from Source + +Please see the Icinga Web documentation on +[how to install modules](https://icinga.com/docs/icinga-web/latest/doc/08-Modules/#installation) from source. +Make sure you use `businessprocess` as the module name. The following requirements must also be met. + +## Requirements + +* PHP (≥7.2) +* [Icinga Web](https://github.com/Icinga/icingaweb2) (≥2.9) +* [Icinga DB Web](https://github.com/Icinga/icingadb-web) (≥1.0) +* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥0.8.0) +* [Icinga PHP Thirdparty](https://github.com/Icinga/icinga-php-thirdparty) (≥0.11.0) + + diff --git a/doc/03-Getting-Started.md b/doc/03-Getting-Started.md index e90dfc2..baacde0 100644 --- a/doc/03-Getting-Started.md +++ b/doc/03-Getting-Started.md @@ -1,13 +1,11 @@ -Getting Started -=========================================== +# Getting Started -Once you enable the *Business Process* module, it will pop up in your menu. -When you click on it, it will show you a new Dashboard: +Once you enable Icinga Business Process Modeling, it will pop up in your menu. +If you click on it, it will show you a new Dashboard: ![Empty Dashboard](screenshot/03_getting-started/0201_empty-dashboard.png) -A new Business Process configuration -------------------------------------------- +## A new Business Process configuration From here we choose to create a new *Business Process configuration*: @@ -65,8 +63,7 @@ first five configurations a user is allowed to see will be shown there: That's all for now, click `Add` to store your new (still empty) Business Process configuration. -Empty configuration -=================== +## Empty configuration You are redirected to your newly created Business Process configuration: diff --git a/doc/04-Create-your-first-process-node.md b/doc/04-Create-your-first-process-node.md index f5b8b84..ad3273d 100644 --- a/doc/04-Create-your-first-process-node.md +++ b/doc/04-Create-your-first-process-node.md @@ -1,5 +1,4 @@ -Create your first Business Process Node -================================================================================== +# Create your first Business Process Node A *Business Process Node* consists of a *name*, *title*, an *operator* and one or more child nodes. It can be a Root Node, child node of other Business Process @@ -7,8 +6,7 @@ Nodes - or both. ![Empty Config](screenshot/04_first-root-node/0301_empty-config.png) -Configuring our first node --------------------------- +## Configuring our first node To create our first *Business Process Node* we click the *Add* button. This leads to the related configuration form: diff --git a/doc/05-Importing-Processes.md b/doc/05-Importing-Processes.md index fccca97..3095bbf 100644 --- a/doc/05-Importing-Processes.md +++ b/doc/05-Importing-Processes.md @@ -1,5 +1,4 @@ -Importing Processes -=================================================== +# Importing Processes To avoid redundancy and make complex *Business Process Configurations* easier to maintain it is possible to import processes from other configurations. @@ -9,8 +8,7 @@ import processes into the root level. ![Subprocesses Only](screenshot/05_importing_nodes/0401_subprocesses_only.png) -Importing a Process -------------------- +## Importing a Process Once the related configuration form is open, choose `Existing Process` and wait for the form to refresh. @@ -37,8 +35,7 @@ to save your changes! ![Import Successful](screenshot/05_importing_nodes/0405_import_successful.png) -Navigation with Imported Processes ----------------------------------- +## Navigation with Imported Processes ### Seamless Breadcrumbs diff --git a/doc/06-Customize-Node-Order.md b/doc/06-Customize-Node-Order.md index a4373f2..880eaa6 100644 --- a/doc/06-Customize-Node-Order.md +++ b/doc/06-Customize-Node-Order.md @@ -1,5 +1,4 @@ -Customize Node Order -===================================================== +# Customize Node Order By default all nodes are ordered alphabetically while viewing them in the UI. Though, it is also possible to order nodes entirely manually. @@ -9,8 +8,7 @@ Though, it is also possible to order nodes entirely manually. > Once manual order is applied (no matter where) alphabetical order is > disabled for the entire configuration. -Reorder by Drag'n'Drop ----------------------- +## Reorder by Drag'n'Drop Make sure to unlock the configuration first to be able to reorder nodes. @@ -34,8 +32,7 @@ The tree view also has an advantage the tile view has not. It is possible to move nodes within the entire hierarchy. But remember to unfold processes first, if you want to move a node into them. -File Format Extensions ----------------------- +## File Format Extensions The configuration file format has slightly been changed to accommodate the new manual order. Though, previous configurations are perfectly upwards compatible. diff --git a/doc/09-Operators.md b/doc/09-Operators.md index ba2f51d..8d54ba3 100644 --- a/doc/09-Operators.md +++ b/doc/09-Operators.md @@ -1,15 +1,15 @@ -# Operators +# Operators Every Business Process requires an Operator. This operator defines its behaviour and specifies how its very own state is going to be calculated. -## AND +## AND The `AND` operator selects the **WORST** state of its child nodes: ![And Operator](screenshot/09_operators/0901_and-operator.png) -## OR +## OR The `OR` operator selects the **BEST** state of its child nodes: @@ -17,7 +17,7 @@ The `OR` operator selects the **BEST** state of its child nodes: ![Or Operator #2](screenshot/09_operators/0903_or-operator-without-ok.png) -## XOR +## XOR The `XOR` operator shows OK if only one of n children is OK at the same time. In all other cases the parent node is CRITICAL. Useful for a service on n servers, only one of which may be running. If both were running, @@ -27,7 +27,7 @@ race conditions and duplication of data could occur. ![Xor Operator #2](screenshot/09_operators/0907_xor-operator-not-ok.png) -## DEGRADED +## DEGRADED The `DEGRADED` operator behaves like an `AND`, but if the resulting state is **CRITICAL** it transforms it into a **WARNING**. @@ -36,7 +36,7 @@ analysis of the statuses. ![Degraded Operator](screenshot/09_operators/0905_deg-operator.jpg) -## MIN n +## MIN n The `MIN` operator selects the **WORST** state out of the **BEST n** child node states: diff --git a/doc/12-Web-Components-Breadcrumb.md b/doc/12-Web-Components-Breadcrumb.md index a9811da..27391f0 100644 --- a/doc/12-Web-Components-Breadcrumb.md +++ b/doc/12-Web-Components-Breadcrumb.md @@ -1,5 +1,4 @@ -Web Components: Breadcrumb -================================================================ +# Web Components: Breadcrumb All Business Process renderers show a **breadcrumb** component to always give you a quick indication of your current location. @@ -24,8 +23,7 @@ column view to make it obvious that you moved to another context. It is also perfectly legal to open any of the available links in a new browser tab or window. -Available actions below the Breadcrumb --------------------------------------- +## Available actions below the Breadcrumb ### Choose a renderer @@ -60,8 +58,7 @@ settings for the your currently loaded *Business Process Configuration*: But there is more. When unlocked, all nodes provide links allowing you to modify or to delete them. Host/Service Nodes now allow you to simulate a specific state. -Other main actions ------------------- +## Other main actions ### Add content to your Dashboard diff --git a/doc/13-Web-Components-Tile-Renderer.md b/doc/13-Web-Components-Tile-Renderer.md index d362f33..4d5df8c 100644 --- a/doc/13-Web-Components-Tile-Renderer.md +++ b/doc/13-Web-Components-Tile-Renderer.md @@ -1,5 +1,4 @@ -Web Components: Tile Renderer -====================================================================== +# Web Components: Tile Renderer The default Business Process *Renderer* is the *Tile Renderer*. It always shows one level of your tree, enriched with badges giving some hint on lower level diff --git a/doc/14-Web-Components-Tree-Renderer.md b/doc/14-Web-Components-Tree-Renderer.md index 7bf2137..b761360 100644 --- a/doc/14-Web-Components-Tree-Renderer.md +++ b/doc/14-Web-Components-Tree-Renderer.md @@ -1,5 +1,4 @@ -Web Components: Tree Renderer -====================================================================== +# Web Components: Tree Renderer The main advantage of the *Tree Renderer* is that it is able to show all nodes of Business Process trees at once. This works fine even for huge trees with lots diff --git a/doc/16-Add-To-Dashboard.md b/doc/16-Add-To-Dashboard.md index deda692..4b9f8a8 100644 --- a/doc/16-Add-To-Dashboard.md +++ b/doc/16-Add-To-Dashboard.md @@ -1,5 +1,4 @@ -Show Processes on a Dashboard -========================================================== +# Show Processes on a Dashboard When being in *Locked mode*, you can add any Business Process at top or sub level to any Icinga Web 2 Dashboard. The related link can be found in the Tab bar: @@ -13,8 +12,7 @@ want to create a dedicated Dashboard as shown in this example: ![Add to Dashboard - Form](screenshot/16_dashboard/1602_add_to_dashboard-form.png) -Want more? ----------- +## Want more? Head on and add multiple Business Processes to your Dashboard to show all of them at once: diff --git a/doc/21-Store-Config.md b/doc/21-Store-Config.md index 709c413..a8380e7 100644 --- a/doc/21-Store-Config.md +++ b/doc/21-Store-Config.md @@ -1,5 +1,4 @@ -Store your Configuration -================================================= +# Store your Configuration Changes to your *Business Process Configuration* are added to a stack and will not be stored immediately. In case there are pending unstored changes, this will @@ -13,8 +12,7 @@ you created your [very first configuration](03-Getting-Started.md): ![Store Config](screenshot/21_store-config/2102_Store-Config.png) -Config Diff ------------ +## Config Diff If unsure what changes you're going to store, you can still check the *Config Diff* before finally storing to disk: diff --git a/doc/22-Upload-Config.md b/doc/22-Upload-Config.md index 07e6b63..2afdb01 100644 --- a/doc/22-Upload-Config.md +++ b/doc/22-Upload-Config.md @@ -1,5 +1,4 @@ -Upload a Configuration File -===================================================== +# Upload a Configuration File You can upload a formerly downloaded or even a manually created file directly through the web frontend. Given sufficient permissions, the Dashboard provides @@ -7,14 +6,13 @@ a related link: ![From Dashboard to Upload](screenshot/22_upload-config/2201_go-to-upload.png) -Chose a file ------------- +## Chose a file This can be any file: ![Choose a File](screenshot/22_upload-config/2202_choose-file.png) -It should be valid of course, but don't worry - the *Business Process* module +It should be valid of course, but don't worry - Icinga Business Process Modeling protects you from syntax errors: ![Syntax Error](screenshot/22_upload-config/2203_syntax-error.png) diff --git a/doc/31-Permissions.md b/doc/31-Permissions.md index 47c9ca1..b6b8b98 100644 --- a/doc/31-Permissions.md +++ b/doc/31-Permissions.md @@ -1,10 +1,8 @@ -Permission System -================================================= +# Permission System The permission system of the module is based on permissions and restrictions. -Permissions ------------ +## Permissions The module has five levels of permissions: @@ -14,8 +12,7 @@ The module has five levels of permissions: * Permission to view all business processes regardless restrictions. (`businessprocess/showall`) * Full permissions. (`businessprocess/*`) -Restrictions ------------ +## Restrictions There are two ways to configure restrictions: prefix-based and access controls diff --git a/doc/81-History.md b/doc/81-History.md index 8366163..82a4024 100644 --- a/doc/81-History.md +++ b/doc/81-History.md @@ -1,15 +1,13 @@ -Project History -=============== +# Project History -The Business Process module is based on the ideas of the Nagios(tm) [Business +Icinga Business Process Modeling is based on the ideas of the Nagios(tm) [Business Process AddOn](http://bp-addon.monitoringexchange.org/) written by Bernd Strößenreuther. We always loved its simplicity, and while it looks pretty oldschool right now there are still many shops happily using it in production. ![BpAddOn Overview](screenshot/81_history/8101_bpaddon-overview.png) -Compatibility -------------- +## Compatibility We fully support the BPaddon configuration language and will continue to do so. It's also perfectly valid to run both products in parallel based on the very same @@ -33,8 +31,7 @@ backends like SQL databases or the Icinga 2 DSL. This would make it easier to distribute configuration in large environments. -Improvements ------------- +## Improvements Major focus has been put on execution speed. So while the Web integration shows much more details at once and is able to display huge unfolded trees, it should From 355123157cf84779708c924542bc2e7fe3bbd299 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 12 Oct 2023 09:12:38 +0200 Subject: [PATCH 102/105] Drop obsolete packaging files --- packaging/debian/README.1st | 18 ------------------ packaging/debian/changelog | 6 ------ packaging/debian/compat | 1 - packaging/debian/control | 15 --------------- packaging/debian/docs | 1 - packaging/debian/install | 10 ---------- packaging/debian/rules | 26 -------------------------- packaging/debian/source/format | 1 - 8 files changed, 78 deletions(-) delete mode 100644 packaging/debian/README.1st delete mode 100644 packaging/debian/changelog delete mode 100644 packaging/debian/compat delete mode 100644 packaging/debian/control delete mode 100644 packaging/debian/docs delete mode 100644 packaging/debian/install delete mode 100755 packaging/debian/rules delete mode 100644 packaging/debian/source/format diff --git a/packaging/debian/README.1st b/packaging/debian/README.1st deleted file mode 100644 index 9e96470..0000000 --- a/packaging/debian/README.1st +++ /dev/null @@ -1,18 +0,0 @@ -Building Debian packages -======================== - -This is work in progress, please expect build instructions to change any time -soon. Currently, to build custom Debian or Ubuntu packages, please proceed as -follows: - -```sh -apt-get install --no-install-recommends \ - debhelper devscripts build-essential fakeroot libparse-debcontrol-perl -# Eventually adjust debian/changelog -cp -a packaging/debian debian -dpkg-buildpackage -us -uc -rm -rf debian -``` - -Please move to your parent directory (`cd ..`) to find your new Debian packages. - diff --git a/packaging/debian/changelog b/packaging/debian/changelog deleted file mode 100644 index 9051952..0000000 --- a/packaging/debian/changelog +++ /dev/null @@ -1,6 +0,0 @@ -icingaweb2-module-businessprocesss (2.0.0-rc1) stable; urgency=low - - * First packaged release - - -- Thomas Gelf Fri, 09 Jan 2016 10:37:31 +0100 - diff --git a/packaging/debian/compat b/packaging/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/packaging/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/packaging/debian/control b/packaging/debian/control deleted file mode 100644 index 2e3c046..0000000 --- a/packaging/debian/control +++ /dev/null @@ -1,15 +0,0 @@ -Source: icingaweb2-module-businessprocesss -Section: admin -Maintainer: Icinga Development Team -Priority: optional -Build-Depends: debhelper (>=9) -Standards-Version: 3.9.4 -Homepage: https://www.icinga.com - -Package: icingaweb2-module-businessprocess -Architecture: all -Depends: icingaweb2-common (>= 2.2.0), php-curl|php5-curl, ${misc:Depends} -Suggests: icingaweb2 -Description: A businessprocess viewer and modeler - Supports legacy BPaddon config files - diff --git a/packaging/debian/docs b/packaging/debian/docs deleted file mode 100644 index 3959d9d..0000000 --- a/packaging/debian/docs +++ /dev/null @@ -1 +0,0 @@ -REAMDE.md diff --git a/packaging/debian/install b/packaging/debian/install deleted file mode 100644 index 8f7da70..0000000 --- a/packaging/debian/install +++ /dev/null @@ -1,10 +0,0 @@ -application usr/share/icingaweb2/modules/businessprocess -doc usr/share/icingaweb2/modules/businessprocess -library usr/share/icingaweb2/modules/businessprocess -public usr/share/icingaweb2/modules/businessprocess -test usr/share/icingaweb2/modules/businessprocess -run.php usr/share/icingaweb2/modules/businessprocess -configuration.php usr/share/icingaweb2/modules/businessprocess -module.info usr/share/icingaweb2/modules/businessprocess -phpunit.xml usr/share/icingaweb2/modules/businessprocess -README.md usr/share/icingaweb2/modules/businessprocess diff --git a/packaging/debian/rules b/packaging/debian/rules deleted file mode 100755 index 615fcf8..0000000 --- a/packaging/debian/rules +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/make -f -#export DH_VERBOSE=1 - -%: - dh $@ - -clean: - dh_testdir - dh_clean - -build: - dh_testdir - -binary: - dh_testroot - dh_prep - dh_installdirs - dh_install - dh_installchangelogs - dh_installinfo - dh_installinit - dh_fixperms - dh_installdeb - dh_gencontrol - dh_md5sums - dh_builddeb diff --git a/packaging/debian/source/format b/packaging/debian/source/format deleted file mode 100644 index af745b3..0000000 --- a/packaging/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (git) From d49a15065d54c3e74884c6e33323bd2aba2a6bb2 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 12 Oct 2023 09:13:32 +0200 Subject: [PATCH 103/105] README.md: Update tag badge link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 01f3d91..2caf704 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![PHP Support](https://img.shields.io/badge/php-%3E%3D%207.2-777BB4?logo=PHP)](https://php.net/) [![Build Status](https://github.com/Icinga/icingaweb2-module-businessprocess/actions/workflows/php.yml/badge.svg)](https://github.com/Icinga/icingaweb2-module-businessprocess/actions/workflows/php.yml) -[![Github Tag](https://img.shields.io/github/tag/Icinga/icingaweb2-module-businessprocess.svg)](https://github.com/Icinga/icingaweb2-module-businessprocess) +[![Github Tag](https://img.shields.io/github/tag/Icinga/icingaweb2-module-businessprocess.svg)](https://github.com/Icinga/icingaweb2-module-businessprocess/releases/latest) ![Icinga Logo](https://icinga.com/wp-content/uploads/2014/06/icinga_logo.png) From fcf8f1dd390446aae0a1fbafcf6ea8051935f2bc Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 12 Oct 2023 09:15:39 +0200 Subject: [PATCH 104/105] Raise required library versions --- doc/02-Installation.md.d/From-Source.md | 4 ++-- module.info | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/02-Installation.md.d/From-Source.md b/doc/02-Installation.md.d/From-Source.md index 6941d54..9e4f6ec 100644 --- a/doc/02-Installation.md.d/From-Source.md +++ b/doc/02-Installation.md.d/From-Source.md @@ -9,7 +9,7 @@ Make sure you use `businessprocess` as the module name. The following requiremen * PHP (≥7.2) * [Icinga Web](https://github.com/Icinga/icingaweb2) (≥2.9) * [Icinga DB Web](https://github.com/Icinga/icingadb-web) (≥1.0) -* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥0.8.0) -* [Icinga PHP Thirdparty](https://github.com/Icinga/icinga-php-thirdparty) (≥0.11.0) +* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥0.13.0) +* [Icinga PHP Thirdparty](https://github.com/Icinga/icinga-php-thirdparty) (≥0.12.0) diff --git a/module.info b/module.info index 2e988fa..343cb05 100644 --- a/module.info +++ b/module.info @@ -1,7 +1,7 @@ Name: Businessprocess Version: 2.4.0 Requires: - Libraries: icinga-php-library (>=0.8.0), icinga-php-thirdparty (>=0.11.0) + Libraries: icinga-php-library (>=0.13.0), icinga-php-thirdparty (>=0.12.0) Modules: monitoring (>=2.9.0), icingadb (>=1.1.0) Description: A Business Process viewer and modeler Provides a web-based process modeler for Icinga. It integrates as a module From 6804abc3756851de24ce3261e98f3161ce6e3940 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 12 Oct 2023 09:19:35 +0200 Subject: [PATCH 105/105] module.info: Raise version to 2.5.0 --- module.info | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.info b/module.info index 343cb05..c492473 100644 --- a/module.info +++ b/module.info @@ -1,5 +1,5 @@ Name: Businessprocess -Version: 2.4.0 +Version: 2.5.0 Requires: Libraries: icinga-php-library (>=0.13.0), icinga-php-thirdparty (>=0.12.0) Modules: monitoring (>=2.9.0), icingadb (>=1.1.0)

8Mst_-Vb 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