From 72fb93bf8a472074a64a6957c6416354839708e5 Mon Sep 17 00:00:00 2001 From: Martin Grzenia Date: Thu, 22 Aug 2024 09:23:38 +0000 Subject: [PATCH] Add an edge evaluator for bounding boxes This edge evaluator prevents vehicles from being routed to/through points where there is not enough space available (according to the vehicle's bounding box and the maximum allowed bounding box at a point). On this occasion, add a general section to the user's guide about bounding boxes. Merged-by: Stefan Walter --- .../org/opentcs/data/model/BoundingBox.java | 21 +++ .../java/org/opentcs/data/model/Vehicle.java | 4 +- .../src/docs/release-notes/changelog.adoc | 2 + .../docs/users-guide/02_system-overview.adoc | 77 +++++++- .../users-guide/04_default-strategies.adoc | 17 +- ...nding-box-for-vehicle-and-point.drawio.png | Bin 0 -> 58769 bytes .../bounding-box-vehicle-on-point.drawio.png | Bin 0 -> 57775 bytes .../images/bounding-box.drawio.png | Bin 0 -> 26097 bytes .../basic/routing/DefaultRouterModule.java | 4 + .../BoundingBoxProtrusionCheck.java | 127 +++++++++++++ .../EdgeEvaluatorBoundingBox.java | 97 ++++++++++ .../jgrapht/ShortestPathConfiguration.java | 5 +- .../BoundingBoxProtrusionCheckTest.java | 178 ++++++++++++++++++ .../EdgeEvaluatorBoundingBoxTest.java | 80 ++++++++ 14 files changed, 597 insertions(+), 15 deletions(-) create mode 100644 openTCS-Documentation/src/docs/users-guide/images/bounding-box-for-vehicle-and-point.drawio.png create mode 100644 openTCS-Documentation/src/docs/users-guide/images/bounding-box-vehicle-on-point.drawio.png create mode 100644 openTCS-Documentation/src/docs/users-guide/images/bounding-box.drawio.png create mode 100644 openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/edgeevaluator/BoundingBoxProtrusionCheck.java create mode 100644 openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/edgeevaluator/EdgeEvaluatorBoundingBox.java create mode 100644 openTCS-Strategies-Default/src/test/java/org/opentcs/strategies/basic/routing/edgeevaluator/BoundingBoxProtrusionCheckTest.java create mode 100644 openTCS-Strategies-Default/src/test/java/org/opentcs/strategies/basic/routing/edgeevaluator/EdgeEvaluatorBoundingBoxTest.java diff --git a/openTCS-API-Base/src/main/java/org/opentcs/data/model/BoundingBox.java b/openTCS-API-Base/src/main/java/org/opentcs/data/model/BoundingBox.java index ff0403888..ff9418bd5 100644 --- a/openTCS-API-Base/src/main/java/org/opentcs/data/model/BoundingBox.java +++ b/openTCS-API-Base/src/main/java/org/opentcs/data/model/BoundingBox.java @@ -11,6 +11,7 @@ import static org.opentcs.util.Assertions.checkInRange; import java.io.Serializable; +import java.util.Objects; /** * A bounding box that can be used, for example, to describe an object's physical dimensions. @@ -130,6 +131,26 @@ public BoundingBox withReferenceOffset(Couple referenceOffset) { return new BoundingBox(length, width, height, referenceOffset); } + @Override + public final boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof BoundingBox other)) { + return false; + } + + return length == other.length + && width == other.width + && height == other.height + && Objects.equals(referenceOffset, other.referenceOffset); + } + + @Override + public int hashCode() { + return Objects.hash(length, width, height, referenceOffset); + } + @Override public String toString() { return "BoundingBox{" + diff --git a/openTCS-API-Base/src/main/java/org/opentcs/data/model/Vehicle.java b/openTCS-API-Base/src/main/java/org/opentcs/data/model/Vehicle.java index 5118b9049..34ebe9b52 100644 --- a/openTCS-API-Base/src/main/java/org/opentcs/data/model/Vehicle.java +++ b/openTCS-API-Base/src/main/java/org/opentcs/data/model/Vehicle.java @@ -1110,7 +1110,7 @@ public Vehicle withProcState(ProcState procState) { *

* The bounding box is oriented so that its longitudinal axis runs parallel to the longitudinal * axis of the vehicle. For the reference point offset, positive x values indicate an offset in - * the forward direction of the vehicle, positive y values an offset towards the lefthand side. + * the forward direction of the vehicle, positive y values an offset towards the left-hand side. *

* * @return The vehicle's current bounding box (in mm). @@ -1124,7 +1124,7 @@ public BoundingBox getBoundingBox() { *

* The bounding box is oriented so that its longitudinal axis runs parallel to the longitudinal * axis of the vehicle. For the reference point offset, positive x values indicate an offset in - * the forward direction of the vehicle, positive y values an offset towards the lefthand side. + * the forward direction of the vehicle, positive y values an offset towards the left-hand side. *

* * @param boundingBox The value to be set in the copy. diff --git a/openTCS-Documentation/src/docs/release-notes/changelog.adoc b/openTCS-Documentation/src/docs/release-notes/changelog.adoc index f883ad944..15e270555 100644 --- a/openTCS-Documentation/src/docs/release-notes/changelog.adoc +++ b/openTCS-Documentation/src/docs/release-notes/changelog.adoc @@ -23,6 +23,8 @@ This change log lists the most relevant changes for past releases in reverse chr ** Add support for specifying a bounding box for a vehicle via the Model Editor application. A vehicle's bounding box, which, among other things, is defined by a length, width and height, replaces the vehicle's "length" property, which could previously be specified for vehicles. ** Add support for specifying a maximum vehicle bounding box for a point via the Model Editor application. +** Add an edge evaluator that prevents vehicles from being routed to/through points where there is not enough space available (according to the vehicle's bounding box and the maximum allowed bounding box at a point). + For more information, please refer to the user's guide. ** Update web API specification and implementation to version 1.8.0: *** The endpoint `POST /plantModel/topologyUpdateRequest` now also accepts an optional list of path names allowing the routing topology to be updated selectively. * Bugs fixed: diff --git a/openTCS-Documentation/src/docs/users-guide/02_system-overview.adoc b/openTCS-Documentation/src/docs/users-guide/02_system-overview.adoc index 58965c799..0836627f7 100644 --- a/openTCS-Documentation/src/docs/users-guide/02_system-overview.adoc +++ b/openTCS-Documentation/src/docs/users-guide/02_system-overview.adoc @@ -9,7 +9,7 @@ openTCS consists of the following components running as separate processes and w ** Model editor for modelling the plant model ** Operations desk for visualizing the plant model during plant operation ** Kernel control center for controlling and monitoring the kernel, e.g. providing a detailed view of vehicles/their associated drivers -** Arbitrary clients for comunicating with other systems, e.g. for process control or warehouse management +** Arbitrary clients for communicating with other systems, e.g. for process control or warehouse management .openTCS system overview image::system_overview.png[] @@ -64,13 +64,14 @@ A point carries the following attributes: ** _Reporting position_ (deprecated, scheduled for removal in openTCS 6.0): Indicates a position at which a vehicle is expected to report in _only_. Vehicles will not be ordered to a reporting position, and halting or even parking at such a position is not allowed. - Therefore a route that only consists of reporting points will be unroutable because the vehicle is not able to halt at any position. + Therefore, a route that only consists of reporting points will be unroutable because the vehicle is not able to halt at any position. ** _Park position_: Indicates a position at which a vehicle may halt for longer periods of time when it is not processing orders. The vehicle is also expected to report in when it arrives at such a position. * A _position_, i.e. the point's coordinates in the plant's coordinate system. * A _vehicle orientation angle_, which expresses the vehicle's assumed/expected orientation while it occupies the point. * A set of _vehicle envelopes_ describing the areas occupied by vehicles located at the point. +* A _maximum vehicle bounding box_ describing the maximum bounding box that a vehicle located at the point may have (see <> for more information). NOTE: In openTCS, an angle of 0 degrees is at the 3 o'clock position, and a positive value indicates a counter-clockwise rotation. @@ -88,17 +89,80 @@ To synchronize the layout coordinates with the model coordinates or the other wa * Select btn:[menu:Actions[Copy model values to layout]] or btn:[menu:Actions[Copy layout values to model]] to synchronize them globally. * Select a single layout element, right click it and select btn:[menu:Context menu[Copy model values to layout]] or btn:[menu:Context menu[Copy layout values to model]] to synchronize them only for the selected element. +===== Bounding box + +.A bounding box in openTCS +image::bounding-box.drawio.png[] + +A bounding box is characterised by a reference point that is -- by default -- located in the center of the bounding box's base (i.e. at height 0), named _base center_ for the remainder of this section. +The length and width of the bounding box are symmetrical in relation to the base center and the height is measured from the base of the bounding box. + +Optionally, a reference point offset describes the position of the reference point in relation to the base center. +The coordinates of the reference point refer to a coordinate system whose origin is located at the base center and whose axes run along the longitudinal and transverse axes of the bounding box -- i.e. the x-axis runs along the length and the y-axis along the width of the bounding box. + +For a vehicle, the bounding box is oriented so that its longitudinal axis runs parallel to the longitudinal axis of the vehicle. +For the reference point offset, positive x values indicate an offset in the forward direction of the vehicle, positive y values an offset towards the left-hand side. +As an example, a vehicle's physical reference point -- i.e. the point which its reported coordinates refer to -- and the reference point of its bounding box are probably always aligned. + +For a point, the bounding box is oriented according to the orientation angle of the point so that the longitudinal axis of the bounding box runs parallel to the longitudinal axis of a vehicle located at the point. +For the reference point offset, positive x values indicate an offset in the forward direction of the vehicle, positive y values an offset towards the left-hand side. + +The following figure shows examples of bounding boxes for a vehicle (on the left) and a point (on the right). +(Although a bounding box is three-dimensional in openTCS, the example bounding boxes shown here are only two-dimensional for an easy-to-understand visualisation.) + +.Bounding boxes for vehicles and points +image::bounding-box-for-vehicle-and-point.drawio.png[] + +In both cases, the blue dots represent the base centers of the respective bounding boxes and the green dots represent their reference points. +The dashed line represents the perimeter of the respective bounding box. +On the right, the orange dot represents the actual plant model point. +In the example above, the bounding boxes have the following properties: + +[cols="1,1,1,1,1,1", options="header"] +|=== +|Element +|Length [mm] +|Width [mm] +|Height [mm] +|Reference offset x [mm] +|Reference offset y [mm] + +|Vehicle +|1100 +|700 +|_omitted_ +|-300 +|0 + +|Point +|1700 +|1100 +|_omitted_ +|-500 +|-100 +|=== + +As an additional example, the following figure shows the bounding boxes in relation to each other and what it would look like if the vehicle was located at the point. +(Note that the reference points of both bounding boxes are aligned.) + +.Relation of vehicle and point bounding boxes +image::bounding-box-vehicle-on-point.drawio.png[] + +In this example, the point's bounding box encloses the vehicle's bounding box completely. +However, there may be situations where this is not the case and where the vehicle's bounding box would protrude beyond one or more sides of the point's bounding box. +To prevent a vehicle from being sent to a point in such situations, the router provides a dedicated cost function -- see <>. + ==== Path Paths are connections between points that are navigable for vehicles. A path's main attributes, next to its source and destination point, are: -* Its _length_, which may be a relevant information for a vehicle in plant operation mode. +* Its _length_, which may be relevant information for a vehicle in plant operation mode. Depending on the router configuration, it may also be used for computing routing costs/finding an optimal route to a destination point. -* A _maximum velocity_ and _maximum reverse velocity_, which may be a relevant information for a vehicle in plant operation mode. +* A _maximum velocity_ and _maximum reverse velocity_, which may be relevant information for a vehicle in plant operation mode. Depending on the router configuration, it may also be used for computing routing costs/finding an optimal route to a destination point. * A _locked_ flag, which, when set, tells the router that the path may not be used when computing routes for vehicles. -* A sequence of _peripheral operations_ describing operations that are to be perfomed by peripheral devices (in their given order) when a vehicle traverses the path. +* A sequence of _peripheral operations_ describing operations that are to be performed by peripheral devices (in their given order) when a vehicle traverses the path. * A set of _vehicle envelopes_ describing the areas occupied by vehicles traversing the path. ===== Peripheral operation @@ -156,7 +220,7 @@ A vehicle provides the following attributes: A vehicle's integration level can only be adjusted with the operations desk client, not with the model editor client. A vehicle can be ** ..._ignored_: - The vehicle and its reported position will be ignored completely, thus the vehicle will not be displayed in the operatiosn desk. + The vehicle and its reported position will be ignored completely, thus the vehicle will not be displayed in the operations desk. The vehicle is not available for transport orders. ** ..._noticed_: The vehicle will be displayed at its reported position in the operations desk, but no resources will be allocated in the system for that position. @@ -175,6 +239,7 @@ A vehicle provides the following attributes: Also see <>. * A _route color_, which is the color used for visualizing the route the vehicle is taking to its destination. * An _envelope key_, indicating which envelopes (defined at points and paths) should be considered for the vehicle. +* A _bounding box_ describing the physical dimensions of the vehicle (see <> for more information). ==== Block diff --git a/openTCS-Documentation/src/docs/users-guide/04_default-strategies.adoc b/openTCS-Documentation/src/docs/users-guide/04_default-strategies.adoc index 399e7426b..3aef8742c 100644 --- a/openTCS-Documentation/src/docs/users-guide/04_default-strategies.adoc +++ b/openTCS-Documentation/src/docs/users-guide/04_default-strategies.adoc @@ -29,7 +29,7 @@ To make this decision, the default dispatcher takes the following steps: ** The assignment mechanics are as following: *** If there are less unoccupied vehicles than processable transport orders, the list of vehicles is sorted by configurable criteria. The default dispatcher then iterates over the sorted list and, for every vehicle, finds all orders processable by it, computes the required routes, sorts the candidates by configurable criteria and assigns the first one. -*** If there are less processable transport orders than unocuppied vehicles, the list of transport orders is sorted by configurable criteria. +*** If there are less processable transport orders than unoccupied vehicles, the list of transport orders is sorted by configurable criteria. The default dispatcher then iterates over the sorted list and, for every transport order, finds all vehicles that could process it, computes the required routes, sorts the candidates by configurable criteria and assigns the first one. *** For configuration options regarding the sorting criteria, see <>. . Vehicles that are still unoccupied are sent to a recharging location, if possible. @@ -126,6 +126,11 @@ The following cost functions/configuration options are available: An exception to this is the string `Infinity`, which the property value can be set to, indicating that the path may not be used by vehicles of the respective routing group at all. * `HOPS`: The routing costs for every path in the model is 1, which results in the route with the least paths/points being chosen. +* `BOUNDING_BOX`: + Routing costs for a vehicle on a path are determined by comparing the vehicle's bounding box with the maximum allowed bounding box at the path's destination point -- see <>. + If the vehicle's bounding box protrudes beyond a destination point's bounding box, the routing costs for the corresponding path are considered infinitely high, indicating that the path may not be used by the vehicle at all. + Otherwise, the routing costs for the corresponding path are 0. + This can be used to prevent vehicles from being routed to/through points where there is insufficient space available. Developers can integrate additional custom cost functions using the openTCS API. @@ -194,21 +199,21 @@ To make this decision, the default peripheral job dispatcher takes the following ** Criteria for a peripheral device to be taken into account are: *** It must not be assigned to a peripheral job. *** It must have its reservation token set. -** Criteria for a periphreal job to be taken into account are: +** Criteria for a peripheral job to be taken into account are: *** It must match the reservation token of a peripheral device. *** It must be processable by a peripheral device. ** If there are multiple peripheral jobs that meet these criteria, the oldest one according to the creation time is assigned first. . Peripheral devices that could not be assigned to a peripheral job with a matching reservation token have their reservation released. ** The release of reserved peripheral devices is performed via a replaceable strategy. The default strategy releases peripheral devices according to the following rules: -*** A peripheral devices's state must be `IDLE`. -*** A peripheral devices's processing state must be `IDLE`. -*** A peripheral devices's reservation token must be set. +*** A peripheral device's state must be `IDLE`. +*** A peripheral device's processing state must be `IDLE`. +*** A peripheral device's reservation token must be set. . Peripheral devices that are currently unoccupied and do not have their reservation token set are assigned to processable peripheral jobs, if possible. ** Criteria for a peripheral device to be taken into account are: *** It must not be assigned to a peripheral job. *** It must not have its reservation token set. -** Cirteria for a peripheral job to be taken into account are: +** Criteria for a peripheral job to be taken into account are: *** It must be generally available to be processed by a peripheral device. *** It must be processable by a peripheral device. ** The selection of a peripheral job for a peripheral device is performed via a replaceable strategy. diff --git a/openTCS-Documentation/src/docs/users-guide/images/bounding-box-for-vehicle-and-point.drawio.png b/openTCS-Documentation/src/docs/users-guide/images/bounding-box-for-vehicle-and-point.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..74855280b5131e7e4daa78fac8d259e04903737b GIT binary patch literal 58769 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≺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 literal 0 HcmV?d00001 diff --git a/openTCS-Documentation/src/docs/users-guide/images/bounding-box-vehicle-on-point.drawio.png b/openTCS-Documentation/src/docs/users-guide/images/bounding-box-vehicle-on-point.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..144e2ed3375e1567a91acfc4ca785740706aec59 GIT binary patch literal 57775 zcmeEv2Ut_tx;7n=rlO#t;HZEoy#^!*iXhU9B1I4>A+!LYhK>!!f(n9Q2uKwXP^t)l zU>SOifOM1^qzNGm{a=AZnR4cw|J?JRd+vRHuc}#e&2p3LSI*def$3H zG&D5qn&;FEX=rF0z&{tZF@cf0ZUxdbG-3xl&tCF$@wJCL+tCO}pV|B-ASK~|Kza&D zs|iR+S-ZK3*}|=19@Z{MF;_cJFa(ZU!|YrsC+HwhaA#+00V#D^F$r+!mg zUv-Vaza%BVu=Hv04IGe@+5GBD{o>&*AgwAX1rd`F24`s4**GDrl+?QFL>3@#?G^eV!`*3N@61lA`dAbnOq zLKPe#|CK&Nc{cFF)!Kz}sgWJr(@vB!0o-=;VhOmNy#m78QQO4MQ%=*`2B9sh@%!nh zle+k7cv!nR=pbzEoWabtzME4>%R)96W$U*&ASX>(H_U^28_HeD14eKZ^;tF+E+ql; zg4^05DG#$bl_vt>>YscZ<9GGvc%raT;FzzxXtH)oIs zjQ+5vv3L;pvHR0ft09 zLDd-!BO8M!!VQc%c)B=)ACllJ*kw2J>@L2*e%&0zu397EHeznpo}P9duIj*S4L7vp zG_ZeXBg&08Rq-^^(+*6g2KHB)a@Ygm^j+!_VvygApFubyHjPZ$cHffpRpXwO6@5YAxg^qb3yj*SV$XpZsr?PvMWsC;ey2C-tAFeA0hk`GCg;k&7(J zzoU58NVm;!W)JrzE8y=H%3i`+TEZHPZ>k- z$XQx;^FCBLOH%f0i=2VW+3?d_&yh3bIsQt{Fc3}L{^qt)K&karD!!rkHaF`Z zFzde>yrq7(-IDTu;y~s8xZTo}vHzUyrYz{Mw)wl_cQL?8kq6X=%oHH55Aib`FuQ2jgU|5@D03~i2-qhtSS%aOcttvUy z1JK9D*%}D|Ke%`ci2E(#LwZ_!cv7H`95@kNO$9>Wmoqu@IBjj?M7C^KTdHDE;Fp~* z-18E+4H*rRznhZLmY6K%ml_#RlR+i0Rxh%!!Z1v~VF%LUuYfrd0 z8DE2GDA)d(*ZD_Q_`@3X5pclA{77Ob-h;A6Y084A_u1Sd$~FI3afhzU?elm+{i+{D_zr{9xhgA3zHfw8oNan15 za8qF8{=ho?hQ^}Or&P*nD}_Yiq&5}g@6eZjidi<4?XRO1HNt_?!*||M;(wx;DH{7% zVy5!m|8im+;p_(^mz7Stfp2FJpmelBv&fznkUhNt{LV-S$O7PYX5%*mAi*sIVBu%T zCs9xM{cpgTlP{3`e!}LATYmrcD0Ol$-{yjx;bhkHZ@_58cOo66yi^qZ@6~Z`wGvg|YsgSy5+%kSF+_gefRcfB%?oYZ^vA^Y^p;F*W<4QycDY zQ)>VBnHeQi{@u)sno4aVjLi(`Pu=0>iT^c!NR5PBqaJna-;<<$N0$^+k@|hi{nw{y z)H_g(lUiP&M)`jl+fj0*@1f_fW%IAktR(-P)rNmR3;m~7@Xvw*-%ZPsq0nU%T>uRk z8%}wPqo#7uTTO&IM%9@A05?rp_+J5r|2h)?e<1-$iQkHVYMom|K;>1oihw%yA0z?_ zCH7Y$_}@lWZ`N`C+RyzdCjaj3|EJm;g%8*w>_4Ncy{XLB|EH_})OS$pfPWtqZ5Y=- zp=cC8FCiu)DMu+WP~$!&$J*j(sL*GtqoI!dd*G1dznj;h`ccZJ{GKHLr?JovtEaN^ zR8Rdsk+YWkV|B`pYT8@MQ2%et{eLcL{ckky|4&;3!UJ@~QLT;Q_bBd!YJ2}{&3Pl4 z`Wrp6)U@nJGxF9rvT>B!|GasCasl8z0n)G_8VFs1RWBQhFupXt*DMM%fUtuxN7{4ee(fs`7>27>|(Z%jF-DiFt z$t)6nnDkS)ZFra;hb-5Ng6r#Zrb~fu`u$)d<*;_tw;EWx7qm=#IzOntzaDEpBE3)# zUFaHYz3a5U<0bCRe*3QJIyn2?|7xEe~^!0mK* zxKmPd?_^ph9sT(RL0<=yxxuNMrBYn)Edm> z&$l^K$hrI)Cbc37wIXvcWYHeXEOTo$Ui4)zQ=CEnh@g}pi@EPZ2{03sb8{w@)J|La z!{&PrcV~kkv9A^M@$Z5fxIejGtAB<-a_x({E~=!t7tDm&oJrzPt8*Uh15vgIljNb; z`F`34>k4~T=VDd+kHsYscQoH}V~(;ph&eTF&a`(2T&^>un)_z8H+iUTX*y(tym>|4 zhor~5d(?h8YR#&*%bQoGV&;aph?DRLzJGPfC*#Cr!ud0~c)E8%2{)H3t8T8|T%}0V z8|#zRJ)IFWo{_F4j+HU4fy%kE^>&{AQY{}D=lK5ou>WsQ{xq%89V8mS+bmLWqeU~Q z;AD+&`QT#Fr7H!o+)k?oY2r zd#80x-n2ftX_>)zb5)Uj;aVj7GW&AjraUK6(-({T^;SRX>BL&1;LjfVJNN8;lYis= z14N&zG_ZklS;zXNH!Zxy((FayS8R6!MLV)5+a1&cs}A9>hLR7-CKa@G*KHUhY14?> zm~R-Ak7y{8EQ(t&U&#h9NiowjV5Y}hjvRBD2SY#1G>db4NoMuNKz{@uos!X;@(CLCNw>MDV86BoQ=W_CT2Hhj@hzA3 zEw3*ouKT?idZ?9-2>fb}*IOs*HTCC8iL?ZN;Yx&Hf%!U%tp~4E1#3qWwwt_uOSCyf zvcZ3=;;%UGhxv8~Hj$d5yX)1cPx)Lzr*ib@buQhtCm+)d?%sPeoe@_ z6yEdm(AnxE85yTm3HZqMUnBKQ%D(K8pHC(|E$=8N6=q~84GZJv64zHg3@dyIKO$Fm z?XE+jMa%3nnvcRAL8zr^F3imJl4(Os@KQ!_ybw$FuyAjG7e@G$*Yb#bg~H{v+1SKH z-cwGGG76zz*QNuf{gHlUPAd3({egv3Y)77leioQ%cESi=`Dvc(;LTqaSu18(+m`Xi z&Gm-(*FN))(E3*0JBY73wf2p0jeli8jQeL_#r37!b;ZEt?tV-iav+phmos31-lrv^ zer0{Kf6XOX`{U$9eiKIb)G9HvBYyw-Fg1SD|z_-CWTRS zr@Hr{jE6083M@IziepLF(*679FnGO{_j=l~r9H!PlOMmBt`DAC8zfHoRQM}?eUWc( z4nL&v;sgG@^73@W`bu2lN=+g<$Gb3V(hx&bjTv7~m&d}Fnr|r=bc$V&&s|MzS|}>U zPI{*B_Bs@Co-!$^y)bfEt&4MkuviYZ<4NBdskkYMi+xC8`B{)a;JANBX`dHHDO3BC zk{MstI%c5^=1M2zR)+BA?_uIxP4&ak*!7 zPRrYhT$HPu=;}cOq(a^%6$(l2)@wgW_bBZ?&hT zB70qdjDD#__pHk6g&t&60`q0|ZQeAlElW!s70Q==Ki`;}xEB!NKUD&&tCF8C97uKL zu?qO66g5>+PD~STh@xw|tNJ`6Y8!gYVs+f4|3LNRp@YKw`BoTS9xtuR&SYlDH>uQj zG*P8xOIP`8J%>+N`SG|FjZ2nXnTf{YS=5aqQGsBvlM%g>w|hxSILWm@vr~9}2C72{ zoX@iAWkmPEkQK}#+7fX|S26?wJ9JSkW?eolS5615ezmH|aGcBMfwa6Gv0Oe8Xpl2q zM2vJ`MAezJTA3qMkOB^LJFnz1LHw%OM(WKvXoRk@UU~ZN1+A`9LE>UuVgxDl@|4y| z{wvd=ZY=2Rg!lBY+m;OIomg%+6e@c_gfJf_-DbXBH>;QlGMVbb?lyH#Q+)NBrg77w zuqc+(dclLG9r48W@y~^$7kOV~%O{!o(wU75i>7^w?7RhTo0c(*NgG(1fSo$obWs*> zv0XQ*hHnoF8#@``n+GI4|0dOAV1jT|7Ho*$z@724mHS$pXkj|J%xDFyz<~CAOqdaB zyi}{Qq*M?~ESAO9^nDFlp6qDr_ZYaNjqJl#sA+HdH#i>5_7N-Q)#1K)=0Oy;458H;b%)yv(3 z7QkA%jSyo(q~!^h=^A?#2$$*6+NfNwY^R13dRUXMsl{HUSsCm1hC6#9Ml(!|fwFZe z510NF? zYjcT-;mvlfrA&|`QGK)xE_6CH?`Y1yJKt3Qh$Lf#Cx+z993yUO2O-U%5X%RaAbt1w zWa#bzTYZ`#xUtJ^45LuuJ7i&%fmwl}+tqc*o(0CEbi8jCt3~Ky6Cvzz$WFTab270RG4);zdNu#hw z>$2nMuoBcWJS6JgDD5NSn2btf-hie?p4XKoW6s<=QU)BJhhemn$X6&8TByvkM3dsy zx#50cuKn=5&=_ycW(MX`;ad~Es2u(Ns)u{M>}nEmFP>rXv(H7p`HidZ^Iz6z?6X|1 z>uf3#sJ&`KYesbFP?C4Pqnl%C0PT`Hlr!IJ;V;%{u4uWO^C-7)I;Penzqq5^W$~pv z7k%M0#``GNtiR0{Rduq@{Y!@T*~DBEz11KWXp!R>@_|$2UEVW3YsV(wU2!cod~=V- ze;Ti@=b_ht0!_SKWs3j$4T3~zDK#1+GOL8KW^~ujUF(2q)9ec(XU{OuZP^#yYjPhN8O9Y&MIxpM<5guFHab@<_8vk7zEag zLSIC{`?K3RzH+7Y`!}UrD87N{=8mT+XkRqrJI??_9e?aEkS)%izk{ejF zqLo@MBU%>A=N3amRmP2rGG-9V>Q!6h!uhlU9z^?N1P96n!dTO>q^=Xu9=Yj4ZXTTe zIek*LnkN`x($b{U{ryp^h&quw=pIPokV=PZ>ID~qFC~ZcYIX${{PKx>LNy(D4 z-#AiA9HDNlauGSU%@*`%T<$`TGY7gL0y8{VD1;SoL#@8+>i=50)1fFV|6(~`B+^F@ zm9l!pH{QG%Z~UOOv5N14o)B<+Y4}X-!p07=>mxrf`HosB?1s19be-Y5Ts3DcdBY*{ zT360#JzPLzlyt+wNWDJ&Q^m~rSE9TATw7ODq%_a`6dlcP` z7VnBFL8#<^FpKl26{^!0f%*dV9k7+K^tgU#G9da@#?BaAXV*3;S?O@!BOW>YkmJav zKc6Tjl}F-9yh@Et0VC3L3LSk5?&;kkPC6*Y#%wwAP7wI>49KziK@W~rhc)6z{m)9# z;f+%s9fbGjM?h)(?4qk`_;zS)iz#O_nI5#=F$q0=pB~mU_bfF3LKFS>ut!$-jj%_K z^aQ`SYh`Os`=bOO(0|pkv~{U08A;`FYn?9YO6>^4J2erIGhoSp{b=r~p_AFKQpJW8 zb)(a^Zv`&+ZQkg9KO3#7mh^#@U*yYMhD%~_`v{)!5)f>@i)>4v-PE>oPSrox?jNx5 zZ`FD)Ig08SE4?E`eoWxIhkps#4}3O#JbiqrO4P94^bRji!G@i5hZ#EPgc4i*+^rmlFo(Ock;P=dO#!ccLfenG|LJxxSYw?XTy;}g3EO>r9<(sXBzaHw=E zASQ}wWw2wWPITQ4~7=RR11{*3@2~!Sbk#s zybEG}GJ&~~8@p{Iwh^h$^Lg=ZbSaV?zJ01vV>ORgnnF#sHwui}Bm1WdE83-UH^G`# zELThjUU^6sCkzFfTOjFiJ*4xw<(1OiXq6~vl0%mmB9mLMNPb3`xe=plLJ!NrFgKD- zh71v@!ML#(O1Qkeu~(MhqB)BpDX{8>9a`u{RE*7h?&E<6=Y*G7yI^S>dKq+V{VU^? zhtdWLHr)E@wQpl!o2M&`x4)LfX{Ip6Lvt0rl%x$zG$feO!SsZ3{>((@Nte6yTw6yH6#L=(~$l{BR z{gCRz0#T5!W2GM}bqc}zmuIiqlehOR*P*W40TJZ1%roO;Z)SYp(OG>n90=*OFwI;Z zbY`ES+xe!t1G^_h##&y|zS|FQ8jfD@S2(+yA*YgwR148U81gDOaujTRDl}u5viW3y z3dP2hKbe!U%d(7|%Zn$H!lGusT|AI{Q)}QrOTMli;wN|8=9&FoYVZ2+$vlLB?@^q5 zYh45jB)f0_Kr|*+;aHdJC*+D-V?*=FDanKq&K&G_sp0u$!_zt?B>8aKMPOeo;xQ zu&n7qs2(nVG>=b+zW-rQW@eSvVH+B26lj`nDq!7bE6%XvrL=;S;^rvY-{vr$kOg)cY)d6I^ zuk5AFGpo-|M=gyg^3!`XX}@7;JSX(3Xo2im2?11>vjGmt{%r#ph28+*jK-eb&C;!s z5pU@~DeDBXzwt^;Rxz9DbHw&W01M6iTFvQUsTJ0x=lbW9YNpLAO^+usj%o@e$dHL3 z-sTm9oA#nzCnf{5TF-&}X!585If^8RKj&f0$mrOI zcvJ6Lxi&`CBJz0?AQGqVt@6l zmvZvwb4M;{g$zI)SaoSy{I4HkZtPRPG#-$R;)A514BXU-6c0i+V@bpDq!pNclAD@hca?g??SRd%!!8q?*2Bh@5#1Hb2;Id48U!+5Kv0F53P@I zewdR<(-|EUC}OaBc0_z068DI!UHjKyGM`Z3fhE<2N?)xg=mDOOjEtzsDcOCI`2cd* zFhT*8=wL47@`Q25(9QLOW-en!$J%-C?t@W%JqnEuiw^w{Yz%;w`kR^~M4Gro_-_dE z3)!&2Lfd_BEAa`1a{5nW7nDu_XD`z(ps}sBQDdL~AqzT~QwnJ_g8v~2AfxcHSI#Ss zas%w}NI(r_D-!lVin~(f8DXixYP3AP$W`lcc844qo&D@z=W%v`Y=}@ek&*TyZNQc@ z{0Ku?^P7dd0V)8~%gFjW04&)h5Ns!{5N77$6QUW&X%vVc9$sQrbQTg(3cg30t89>;!_(Q(^BNVyL zYl?>&p}$^EnU=!5kOj|$B~|&hNMqEiw5H3?Eh@1uFOzFpd!`CG!E>D#e;9bwFyP(} zHxYYLw^oAp#3xDmKz6sQ`F*$y0Ps(00vhS}y7N8yAnulD4SxU#$dc}QH6*DmSyl*p zhxSwd9GiJj>ETHQ!~Wjk5)MG*oTAZj1rW$N#T4v(%WHy+Q^*{do3j=c_Z5biwhGR` zo1hC5sQtnamg}>M?u6T98tMJ-)P_nUt>j7(F0-PY^iUC_GmQ-#4vJ^Y0bWi??T9$C zpM-ga*_GwL^n-7*966MW@gDi*N~2}n{(&F3tH-%OnGh%p5igs0E4D3`Orso+{Zr_b zI$ewZnCb%We}oalI)xy8v{9Mjm8NMR)PIe6bNA zeZm#Di{9HIVcy2-92>^vkjH%8a@wvkLa3Yf*J%0-<_8vWPTyG@a{ja7m)5g%P#{TJ z0@NI0vhXT>d^bb9?TEER75($j{PqZc+;@Mu0X?b|OqAXLB5hgxQ4R2#c^-5!{#LP% z!t&*P99hsikELBMV%mU{Wb>zxfW+R`qi>3*(@~-zFJs38++|KT8ZsgmBG_U%?ccwg z&fEX%FL>))2QLC!j4(fGrIVX6H%w;Is3}FVZU*bNd7zGA{34mIP+0lNMXoa#dvCQ$6!xyRNn!J25~|zB;8(J57io#{*Loh0G__q z5B)&52jqc&NGd`O*n#Om-q!tbZPL)q<2p_CJYTh5rKYV+s4>)p0}U9KKt1;F%8EjX z1{N1xem8Bl?5YW3tDmVh%1Nux^5i_`*1{rj!Rc$^`w8dno_vi1?(gkM4|)t;h)>l{ z0>&V1t__e<-#2+PUFS!6?#7Xwv$o#J!xV_sAt0Vtl)LBM8WiKif_^|kE8hl0#fGya zlN1enZm6ifixh+;I)rR{*_mr?0w$lyV0VY3ayLD6e*EO zt?&496Xpd_h_OH)DMQI~ASlkhA^jQFYEf0}@_}Ocz@5pYnDmlT@~VpqwwFm~|B4yU zwbRoNFXgc9#B%8=xqlgr0C;8P-G@=%rbBg3BFn;yZfZ?2*LM4fWLgJ|KWfiD%Xw_f zfo-@}K<(a`d%$%m_mPLQA1(Wb2v5%(OdDh$5`Z!x#$&s>olG+M>f)j!JZ5^#taR+= zL+DTr`loVT(@0enMuIZOjHXRZ4&R8FO+S$5GtElx(7lPdG;*nSQ zeubL&bA8jxLIv)uP>x(-`ZIl{8(hvzWc-(zsKMB!2 z?-(AD-lyR*_#V&sksuNKO$NATCQ4pZu{gvG>FPjrYd_@&Sj++zsIv<<2Sf`{-~x!C zN##%*1NGS1)Kb3LgiM3)4fCdK|O4^8=UqOa(3?wDLr-R8zn8and zH)Io-X?FL(5(7tY8DKT*U!n4)k0>OWvPtf=dX>?=Dd_rQ6MwUaSNtTM&NwGT!J<*5 z3nWO486FuVCePFX+sNn4Zvmm;sn}Km7|IP(EezS<%c(JKQz8a$3qpZUEiolId#%8P zA#ud1(&_Tvs^Fs8RN&llp&5hG%#GoF)!T-&C5yRaBpEff?Y;hpuCeZdxm2Pee;u~t zO?#m|kgjGYDmD^1aL4nZ#X+rvTnbO~y-Yx6s9@i*FVuwi_|mSYB}@=m!r82ao)?Ux z05GHv+$k942GEU3hFQiZkLE6ueh?@ynKGgi7wcgo_k$U)0w`ONp!Q3l!4?UT-U}oe*i=uY^fS6miG)@;4i$a@wwVrTWlMuv0 z2jO*(O-tol`_0O;>;$~fc#%u(%F+8FZElA9PQP^7D~Gc6^}|2ulS%OIg6DU@Q+V*p zX(p`|H9D?Ry`aR{Z&AAok}~{Y4b+@+2nVNqtI87J*S+uxDJ@j$3BJbLb7d|N&6a%N zCkIi^1tUSa4BI254A-E!CwdDN>#II~X0od%dp>iN4n1#MJ<6F>{-$in<5ZnjG>bXE zNA*voN>+j_mVriYn4l%X9IUl2OT6xegS$bx)yfAe^igTcHK7zrM>)_p%@XNXq<2Z@dRGN89D@08r+A^Ph6e2eE!*TVeY#`HsvP2 zM&w3KK6bgr!SkbmhEBaiA@lnymd82!pWq{+6R%CEou|tkRbD7*o2?s6#Z8pN)UFdV zP6dkTz0tmWoO3=9G*G;TGc&Qo^xr$R_Uq!w^CUfJBM)}$tm#Q5a`D}z>U@Z(QKpif ze;3|6kG{zVaB}%1P+~V1;jDN$phQTG%3A>C>&V2fHyd2I6Ak^sZHN5v4BMikU?YWk zp>v#T1DxqRWdn?*Jxz0pOJgacdHRAyq9OK~O40o0sRo4wb1>*v(@v6eqPRRwBbP43 z8b#2udV^oh);Q2klOc#Ln3lbGd&YubQZ%hj>pG2>W3^!%MNO)`ywH@x4R7s!E|~-u zX+HfW{AmY9SdAE?5~Vndi-?_BTc`-;!^tMiz+CLtVuKfB=Wr1^!#eKkP3tR72oxvH z{rR=FK`3g_Vd_baiI%uI=;KF4yK0h?`LC=I@_#I^gP>`cz1JpEPCQB%Aq_PbRx=T|^xdh7jrjR+N{sHmcQ&8&6A!WYS~)vg@^D z<>`xnG`Plfr4!i%eW#$`Vk7YsFY#LH6Rm(~G2B$D>m>mEJ%0Ml+GdOD7m6LuLnhs& zs>d&w(h1uA%%^h>sym>O6zkD(HEZnAl)F?X4Ma_&cnGZ%>zK*9ev>I!U3zGU1j*#b zu$g@njkh?`JIGKQ|N7H`ioPUp{#B=OwI}+#;Y9f<%~(f&>1L5{5SPFX8cO{KICc!) zY~W*R>>40cv7}wu8B?1!$S?%w^Ba0F_wa%XE*rYLdr{`TL`cUj#ZjX3=wLpZ>#P!X ztjkz0A+nMMM^hd{Yk@MG`l;)FW0-vVcI}4Lef6}jnKawPw`)Vyahj{oqQ=|lv(B9UiMP>er=c$=@<3r$fA!@)!WcY{u2#} zaKn{w3{G?3#~2Tsv41AxJr;CDy=#d6yJz~*ldj&$EZFGPWdFcuuVuUF1*aC zhkQpTdh{Nf$^%`V7I>WB%joyBcu`mP+Y!T6W~80D0dzw2KktWUmkB`2cE^xtSQKr~ zMyLp6RN?4|dqWg_`#g$1jz0)vJ2n>1X7DCEmbh&drc$NL=KVna>`?jbp3F}_t47Td zr+OuLg`UxKZa1fI?7Q6wJ(TXM&4H3`mJq%Yd4Du5+yPMiwRaK}th9SS#uV^(J+GQ$ z9y9Ywx@XYT+;^)=tCWG^xKYl;gINRl3GHqY@QFfLkex*JwTJ)Onp*4=DV;zrnxo>0 z&$Wd?qVPi6W968N(S)fN!7*dJ@TI8FQ|2^+=W6r$;lM><5?_za5+mAyh ztqld4knHi<_fJPQCDC8cbjqCbYfiRg`{FCoMV}lbs`Wg8*^ZWBB|?Zf#7-!ejW8XD zez_3dyBHP0QJ0w=MJGsioD0Z9<*AU*aYdCI-tcP|j+v)Iv+i|irHdNqsn)9dYY>mI z+Fgx%%yu!)M{F3A!5r{v4=MdF3Y1Z??P*;PEvF4#bP+X%*=@H4{UWtzo#L*={1RS3 zD#2))6Hl7`T9i$a$)<(6p%OSm?ahL}@dQh*_B5^b9Jp$wRT4Yid4wJnDa5BQBh@s{ z^0@1r?Tib%gi7QQNpDUg`qP|{Zy2we(Usi((&0s6MyjW3d$q7M7%ADamBLpXIl0)A zLMF}0UpwQ6wQJK%5F6t)58qrB8dvu-S2C$&5iL(FdY|^@!B0XSuI)@#PZ=#dH2bh? zKanqYYd4%~BQj`<%1ejNg1Xc2JGsp&`*)<6ZOMWLiD@PFey1lXLP}ZtK=`8~Gpg@N+&9(tS2_{iddH+Q*BT-&~+oNf? zz2d``&!gy~P*+bK(ugy|#nBm&1bvP-=||CVqJ<^ADo7AhFB*>r+H%}rC$z6!a}e5| zdfaP%_v0@4dI6PZ^O3tB&+3DU;CU4HW0F7@sOp*H2zQx917oMN35BHIhvbHi;kx-= z(DtxR=efmrfThsq{Gt|+`R#0r_HR8wYcvw+txTLb>}ZhJ(pcp~r*r5b>k^z+2xp5M z(K{47)udht57mrojoqzL8AqRf&=!=Di_D`#grP|+dzIW`LNcf6!jw2M;#w)PZX+SW z2U&I3*qaIqtSsr$H+m(|fQ3)@JU>uBU%dPAfy-CDG^%_Y2ksE99tnSOS0^S1c3cyz zh$LNZdum)xZdz$A&yxNG)d)Gz^Sa`m5~s=g9*G#3`HKrQu%V}^(%G$iqe9BxA{NUI z&>yTMkd&D&VBczDQdgn_NHnX zM66&!cZC?F_mu8kbyA)~)6Shl`Lndc*e(A>`PGxbD1%bVIO1x2VcYn&7bT8%tJY zxS?}4Aqg`DW7e$W>Lr;*t_LE<4fq6vTNtDkt|&n}&AE=`Vm}g}@p>r@-jPm^3?im< zev=VRF)5FEWjXjlUb)yI&+Do3XrQY(Bb}eqjCXtOz`#K zWT~%P9=*cdyISvO?tO)t(UV$sDl(=(87^?QC*>wY01c5F|*Slet_ zb%I&fJGGSdV53Os%Z&?Ng+W#z5yw1Tt$kE+rfFRyNq(-U6`@a*qG z+4vRBFeo|9N_r`;HO?Bjs9!vpVSBQ_yMK*D5JmXa5kV)T=hCp%+HgAQX<6?6>Up6A zsbV!VE|?&@h0L`W4P0WqLkg-Ea{ZnX>#A_>q32aYY6GbgI90PEF$~|!DCVR3?Mj%3 z7$El)sWzoiG~c>lWah=<9_f6Pl9QiGkt-r#kT;`ZeYqlWZFGGlk&9);DfaMlavk^BFzXIj)5pHIo@sHK8sxE^7V)EPyak=GZomjG z)z;HK^L=er!F56g!84gJb5!VZV30ea&nQ7Us#??R`5DQDc@d!!&#@O0hJR zSt&tH4@K(gKe6Z(cz{-^eGbw4oU+O71ujpAdtPMwbD&!+aGC5{1I{~7kB?0%`=0^6%Ci#to&Wvt9T;O*D( zHthp)4?}@?ddJN|R1Vv~ibI4xLbc{BcgG>2D~2YMi>8l9CoZ?9xPGebGGE4tVzMT( z-x%-7{8elEp#wl>v!*zd`w@H7Rb z(_y~hR~iLWW|$0va-rHx?nD~C$*%H)0?AQ*`JSyOpxN9lf(xJ}sJW!m!q3RIbO^|k(We^m1|J{j@AHl;&Z zLeD-yWkuU&q3~UkhABFsnY7(g?jCwaOYbqJAC{ct%V4_FB&{8qDFu&|W`t>qGp1jG zEkKZ@MuO>;=dRw7Ms~HGo#SaZ)gmjt6PvGU6w^6U|3T|&aAmO)Hq-huQwuW2( za-R>Q!?XvIv0xAnMck`NQdW&ThyYku-rQ2;kusULKn z-KsnQInsP*LNW_*x(Pyb=z2F>$8!_8e%oUrL5;I3EkRU6p3F=6uWt5tVVm-3jA@CQR!bF~kdU z(`M{C^zm>=TzKHPQDQuOXmv39$@QAPm6}?$sm>T29NW)rlOgiD&jNAwxcB{l-^ zVDs&b7|q<#&Sp$#>6ZgBA#>7zv>GwL4$7-dd-R}7VK)nMKn2KSL8*gQhgk;XE)q_Y zac}LOf)a?22OqLt5~MaGh+ylla9O2eK^03D`D)(-Sb_(=xD9nN1(JwWQ~b*>Hy`GP{Ef!%RFyQx>C8= z8e8tEd*tj}68Y5yq>AQ(u%W}%@dJ<)+-{j~WfKaze&}pmG~aMhrD{kn<70(LBdwrp zoOWf+x>Iw8wuP*?h)W~EP?Q7gWVrrJn{KD`%(l03h*VxnnMe{Q{KgXSC1k3 zpQMi9OtmcZTk{8$mM1_bweCq5=>_LW(_vzAw}`@Ja=&=X5kCgn3!r_o>5=!RWo6wq zQ$8V=2u;JuMyIw4_OGuJ$nSPMjVR76ew3PCuPV)$A@xO# zqt)DD)`wMBKukZ{xsFD6(Z%h))PO_DD**@ECM}vGeDUC{36Ei;oHTQrY&rZlGp&}B%;VpoR66Z^%k<}>)Mo|$JrAI)cu_Epus zh>SX@$LYrB_0a%dXGzNQyD<8C@LrbkET9pF*}Q+-&ZBpUaHa0%=#2yqzR_?@FH`f! z`mtA$ffGHnPO!={-8&`cTGx_!unvmgB^#JSOyjqSnv8;|DHxlV>{g~%I( zL0x*A=q#Dys(l3CSyXe2p+h{)PsvdnUsi&JX-}(hE?4V%D@f0p`g7hNDtVd_p;A|3 znkB$XD@@aPMXi)Ztjztr?v6__!&fuoi%0LvJYo2%O|y3(yxKPNV%(hxKfHq!TkTUR z_*IP^ys>!q*oR)25L+Dg-U0Lfxs&w1g6^8hqG z4ukDRmmovUiiUhj29nI)6@*Hj*XP*L3T<>4EDDtztC@3V%m@qGYfN+PVcF=eL%w$T zs;8ovC!b-Bu9#gqE_{aAjt9@qlOKbVfaSux7m=v3Sz_$aa)wr71pz zP2?n9{b1y&AT!VqP1k6)xY<+>n!Z6%hv)M1`6bI#tnYpjsCu$HaKAuw41AM`I}6&g zX7$S&W3SnZjb(6Ocydt~%Hyygfvi-uytexzgEr$YpP;%-pQ~pbr!20B(T14_@(R?A z?%8I1K13g{m13L8Ij zsVx^X@2IiML-kbQvo6D6E{VANFAu)G9SL4fxoQQp<6RcFzCnnM|+p-SLITI*&mnOK=v=dMC*Lm3dgeh<DcGPM#TR`O2XH$Y+X>o*5jmPN0DYsku;wN1A0%j`b z_@Mndp2CE&>K&<2-J}R8_J~kVqLUWg==5sebVJ_=potZsKw=`N^SK4g>0mh(rdQ}z zID>zEH`gjV4+YGzc)q51lc*G5K}dc&XpMVlDZbH^bLW#dUESEx^s~49nPsju4;Af# z`15(Npt-Tttci0wAx+!1wd195Od6m?SVB$J)7~Q0_zA`tOW=a?OY5O7BL7`KN zHJ$iW(QkJ)T0t(vvUAj)&GxWre5YNyW8wbu$d5lqBY0Q4R#6CUH~*eE~pZQZ9PVG_FeZFbSy<0 z7PTgvBJWrC*)n{=oodNn9}HfJbj->K)Y2GmrcHmpPsZ;Xja=}D6PA+vUQeOLG}6qv zU3*H5%tK7+Vbe)wW}=R5b4ptpdl_^OXDUEn4)r)!=|h8$8uoKflKTNZn(@#ZyVj(c z1hYe#%;@-L`hNY^x8y#anW4KP;qc8y{N%ZWfY}=S$-Zy*_QkV7M0x06N|jy`*N2TI zoApF;#Lja><3gq*7#3&zJUx|8-_=n(Zlk7mUt4HrYo6B}(Kx-p)nTY?^r59A!n`S- z2Q%(R%7Mz~mEJ#eKrd>z3ysYbYPPM3@%~`wI++}R^4{s+QShnzXbGLcU?l2e%80p3 zUU&>L7iUs==?=5w*OrBQ&(THGc?}_}{#88PK3;t#umEeiq!g2}Pbp_aQJ-SmSxS?m zvP_I4XKAiZzkZZ)3kzQM9MwaA9v(Y*s;~}!`<~4kgbQ?*)M|gYqe#(Xmt?q-?*1_^ z@ZQF_sf73urYJV18x_Cau6Rr%1nZrVF&Fnko3*A?YP2S&fhKwteHjt2d8K#8S}Z#} z?<-#xyfpb7-6=4HqZ)VAK07nA}JsaC)@f2sG+|z)!oNh7|?q3HLm!+M|yKgg9Ck zXh7M^+F#tqvB7eq?eik$JRdA8W5|zOZUyZP8oQh;V;hDHy%M$l(d#v0E?<82yEEAR##-*vx~2=qqVDZe6U~r_-odbK{xuh=S&-~b?t;AR`P!dA1mDJyXg{X zByQ)GUuKdaop>qv_L1$s6Z)|8iOZ>bl1lY z9ZVpqGr>cn{5z2@HFS#P{HkI9 zob*%znIoWbOm;u3Hq&!?EI|j)zuLmzkZXF?PwtJCO=#w@9!R9`YiVqA#C=>moq*+n z?0bxTH$65I7UWT>$~UwbAmc5?#;Q)~VmxG!+GJ))R&tTX-QN!&1<~ zaMrHXaFVxg=B7d%ZIwzHw4rBb8hEYAg(gZvkIt*Cfm}qy2d_`B2d;&O@X%(kFZ~3k z$5?=!sylQrj;PKI$FY2j+Z&x1bhbbQ@(QYIN$$F`T564bL+-X@@W>v7H_dw2C_k7j z{NxSVnzCbbGj184WR1aVg|Zy-8e(wRHT-|5I`4QY{Qmvp7)g;)vXzz0>~)NiG7d$^ z2$elDGtS8_B`bR!BkLrqa7Y}ZlG2;nASkX==m-oWW7%NE0MzO)my9QW-1%^fXaRRLm?TF>Z5T~^7jJ6_s zur;K_k39C{RLvs5TEwi1)*!VDf;wIMU3OWycZh&4w#@IcQL+)HAEW83%{jA$-4aL4 ztL!HdA~CuzTA!XUiWl4zKfMKiKcbs~t|tuznX)e`=)U`z-LjW0+Ya?wh)*qwbY(-lfET{ z_|bAzoomDfZ`9~l5!L$rBCa+*RL=9q?)p-C8~+||wNQDU$;AXLD&;vxxDn?*`PR~{ z>%PPAYl4*4V^_)6r(7mhaUu{0JffhJ=t{n?fz!sM?=I)c(bQQt(^PCvXDBBTgf0vCbHrFjT$bU@8`V$;*X%p~hUC91^n?!^#nR~i#< zwx#5;LFjxRGYCfMuRVfUDOzWks{JTo6bCbO8iAyX>w@AiYt48|T1nbZR#Pix7F{er zm#WMCxT6r{!Tz{2ye92KzT6v2uUs%>`yN~PV7E*fje(8&p8yPA77IV^>4zjm?A$jutOweJ3UeqUQ_yVNLn<*@E4_-G(-{iqijO_wo4O2ZNu&R#h3RP8AR zIe#hn+-Jg}Mr~bTT?uJB7kOS(UkZ5J+O>$|PgyE-y4Y6CuCwYD>@r?mOmXVWXBe^(7~U#G+rYES^{@UisQgE#9RJV74P?LFNd_=2#&R{DhvABktAgsadXP|awXc2vfow8)OhHeXOZG|@}lh<4M63~-u zl2&}~%}v{xJ5%n)QEBmQn5{PnP|{em?j6_78^CP=M!&cw<)=-Re;q4(oZ%*UQtRL0 z^EGXET_J&)p}PU0iitW>Ct;)-cdJ3S?%LXz=Or!4139EVO$LL8utbtFO@9^!2VEGN z&;~Pif0_&h&fEvw+O$k(=GNr&TWyL0{@1Y13KbSpP;%}v21;yyUs|hjfm04)>gof} z{7Ze*0(oLnvyWAR<1Mbl=PsJBKRqd;+Tz1Y zX>OS@oz`N~+_881zTJC^MwF*0f%|&r`0diZHzsnrnuc@;$Vn2#xcLK$I#!02 zGd+F0KK%%u8~7SteBQxc)HGLL^1C+v*oROeEZWM!g`55zZ_V{{U+VGI=bMRicOXuF zgZh~n(t+mx@odk7!X5=;_&m;KFa#TyQqNP};uKGl0!+SxP8Bt*@p)-*VW&46r?!f-3mB`OB|`S3bE zCALowhtK{ zJ7dsviVKP^`WV>y{jELnwkCU~Xd0Y8JBr;7(W$J%Ld=$l9H9O; zDdI|hhE^_z8TG84F!Nhf6~>ZJF$+c$Vj4I2JCQ>SU{oLc8C zVa%%sv1eMv#^<6&ug@Y$*7+o9x2m&cP^Z%~dd;nQfmOx5T0#=z*=@!*nD1JOyo#c{ zTQ&V-+aT=2iKlj%=U#CK6TfY%i(r%N*lG2KPrtj>GP0)P^6Kn#S8Lbc`N*@2zaPPI z+2^2lS6zInrkIQ-jNy;cNIBbbx=D7s(&&{}BNBA5Rga`jF03{p!+_THHoExOF+BPl z;R*SK4;-K}^i*>OV*J0sGD{4L5=c*S$dx`ijRf2BZC5!#N#W}@qVqN<`z%x3*^r#I zdbg{K-{1!yntjcXlm5EVa6Rq%S)pu(SQi>p9NvClbjwMUGJ?)vh4i5V`bY&B#}qt+ ziG_U77D8vqqyWXzGT<5>mz=Ne_F3-sJpVnVDcqcDpqsAbk_fwLcBHVw=ZW^3FOgqH z6qZnIrdCub<`IP;(1QMF=Kd#1sO-h){OFqV2#B`| z)_t3CN$dBvbl!56mRL-U2)Q^j$4k5a_gSBE#7Fkh9BH??B&6QznB=u(Ll*mnyO!Mc z0>XV*v;g}WZs~z;PO&bP0kvVg(~JlH$bh8C!S>idXiDm9$e3YIC;BOC>2ux23(FLv zyy??{6~kv0NMn*m32}cKKIu3Ubu6Uz`VSkeCV!k$#WX}BzpjN|jMsoACl-&s2;0%l`Kl@M_yhZf}jERKUC6;4!-uz>?p80>ajsM5zu<)v$ zHquyDR-8DACLX^yvTS}xzO~|guAc0#3O!nV#94~8sobW7rR@fOrlyGmw z#}!8XGxi**OXl4~{Aja3EuZFYQt0ZWIInbvMc@dW&Z(!tJUrRo$@aY6dY`d|M-Ia~ zU$##Wk$GH9*jZxX(Jj~s{Ub#%U1_2JnXdlNX)Uf4Z68lP2kh&V+`E-zyEr9G{Xtt- z>tb=@<)BKJ#aXnS;OJMJ{i{dH{)ymvVi>^|X-4FBT=6!xYrd*-nvRQrv+&12N9|SRJ2QvNxZsF#2HQVx5vAD z-1nFg_Wly1*dKp9H@|pf-rZi-rlkHU+ZPB8t9LXKg5}!26~!#RVSB}Wqis7j@br_! z{yv}3%16b%*%GC<8^pU&v(JT8LiE@n`98^Y!u0R5d-F{^AP+xc96eP*z{vwDyMSip>6K*(S&Ud zD=URi)15SbCMa*qyPYAyV%6q?%EVF0S|g6 zlN;GTWqe8MJ3}TSAsc}ms{I-bG4u%$?=1<6*{=6l*RC~|sHMCQXd0xx7JZdXdgN_K zMp5B?mrv21zfmf#)lcKTb)^ct?KsaKbS2=96h3Nn1UI5NcTjK2|4PvWP5V%~a2Ajp z^mIzDyjQ#iao~uXVOE31)79Fjm_-QZm@kTApq)fSEvn>51QCzho-0oab4iXsb=)oh zk^$S#zs!_jUAiqda5eT1%V{8@pz+4p&c$Uc@`ys#9XThv<93~piBR>>kH52RbD^-N z>iVX6306uuiQE#+i1aY0s3S^97o(*bjOX@SA#``Ny(%dR)I8D2(mALM5{o~EU{o{qrf^Ko)Pz>20V zlG_0m8Il2Y<+#1)V2aAJ;UpH$&$1}F4X|B8Ygi!?(I6t-JVZE2sAfI8?qZle5t!T_ zf0(-4%?VQyd>2TSzzg{p<0hy z(u-Ux)0E?}=oSiiv+jYvWD!sKUPH%@brcMTx1)W?)QVpQ6XLa=X{`ca|B?l^-3WpK z4$zLqWplwX{mqTX2q8=_bfDcm`e5RpMC0%^@;-vkD7>q+V9BE2nFU&QC&=cCel)`x za|Ds+rE;J3knryKO#UQu#2qnqp&n?%8%w6F;!ESkcRa{81lnV~azBfliQU^{W-t6! z>RL|B+luShV-ac8@{g)e|9#S^hOE?QmM{95ciZfYwr?lEQ&cHrf8)%4UXIRn&}GE3 zsLo%k)%P$V875pRZqu@?lnTmTe$O(vcIC|o*a#hcInF&U)7=ED0Q3dk5IOS-I>QjG zaiG16ED9uM>q$h-QtJK_DNSdyi9y5^Pfgrieh~Us?b?7}0;jud1-Eo*WWP(b+<|@z zQGdG?9BR}CH7LVYBa~J+z2C)n7i?^&^Pqj?{nM~-)|i%5oX)ky+op<}2JeEu zzSQgIxeb=@I|{yw(%~)p;3*i0VD#Je8nD5Sa^C=12pwx0h+Gretih^pUmoF{X(tih z7aDW;&eUQHi4Byn#nSo@Rf)7jTl%aa5jw*O=M$IjgK40e6i1;Ta3)+6&vZE)2N9ls zf8&H6u%c2fG ztjd#$WT@WXL3|Oj4gNSHU#W0(5Na)R@35i@t6y#HqQl>>nWSp&soZtCxw>BXN^zJl z6F89cZ>0Fl)Dna(B8C*#z&c3nE})~acbTrnSuFh$E;JsI+T32=?7DjWV1P?IEh0JE zm-zceWjVM-Ip(s;dy|?jFFF5AC;y( z-Ppx!1}{2K+8&^7vsndF2=N!!ksZ1l7HQ*SPWER^Qrty%*UD^`)v9KWWm_Wm~kyi9bu;3x$>p2 zVV@G_Ks|`KOw&I^@DHkUECXJeG9e2@Y{x{6VO!VH+A>bk!c6$YSH{lbR1pS4^&2lg zlbMyi5iduM0av8%$v-i3{;GScyWFa{uSiWpVL(NNyxX!Eb+%v-|l4%8F z0*=Ty@%6aJ%Vk=|94lfula~_JaL!^>WDQXlT>ra5uz@ zsC}nb&3rR5P2Hc~G$+KW(F93NjW7duuzw8<{{-B5K3x$Gs?=}oN>oKs1XVSts}?u` z9*(@M3LsxDw8`wsSZB6P_!e(}uaG`N0c%PhG>s76Wk8ZTb*L{lX!RhVXKQYU(LeoA z>9rT9EoVM{g5u+#TrfhQ2X7kkk z@E#XJa`{TqrMn*zpy$*++&p6nOXrY_l*Gog)2e+YFd)hd#CfWT=XYe*1Mt0C)h0l& z&*JV+dtP-4syEONY`yN8fsblo2yI~+x4FZ@*3xJSr__c)WUWnTp}3%65C{#aK$mrm zvf_ap^aW_VGx^qg{~J;E$T@ooFNCe2?SGTI`=n6i+ph-GDj`QFD`7>7tiz%Hi0iyt zR@3_<%3?jx4ex|yo86D*S1fC3Vb2a_Kh#pZ_LID&-{j&oz~O|v(t>~KmRGiZmX_s#<@xVxYD|FU3G0ZXo_@2HZ|e;@-B8s~X#WY%t{I=rjcz>l8V1gh2_eL1tSnm8Sy!X78*Y$6mNv7_L26j#^IBr0uj;Vv*iRNq-mt&)FRM-JNl zbwQY`bS&?nmx>BaZ|vUaSbTFFRsw-JmYzzJBZBNA?@RJ2>HF7gP^(91&|KHQ66m|& z`tT6B5t!TqGoO-W>^;rydyJ1c-WgmT@(qG?v27{I|DG^Up9kmqX*}Z$c+R`({m4q5 zR*NLlAz3YJbP9r3nv(UPc`exo`NBLFv)AXDTj;bG(9~o79M~U^u1XBU7ac``rg0$G zW%h74wjw|>VcN=2;=0gcfh*K`A^w+hX<8U>6U=9!d!jtZha$N;lO1kH;hZ5oq-}P9+m(uwDVu2a+^DsH)_}o>whjBG~}mE*HEF5x0>NSA-k2` zu;l&u!9fcI1ST9(^zHL!7^D+S@BNbv7Rx~$fyQ1VRH?3uHhVl}yeXNh@<4-bI&~K> z%O)LOa!+Ts-@A@D{ele4`FA(}uT_G$qMFa~u9fNYiw5T^vY(1rtC#srn6Ye>>E{JzVsjZ{!%QGbyt|%9Bc6Sp*}7Gq8CBg0 zvw}gIE~O)?yO*&&yf>7|9=ZtvsZJI10S_tZUZ8pG&Bx0XSvI&dPt|F^IoU9NN&0af zjR>g|I(@T%tub2UKVEp^RV2gw^V2cQMIGxLDVj<`P9RY#E)DyLX>E(pwB3&M~CiB zbQwBC)f<2C#5vnPo~ps5!n_9ieSE!S&Lg0nVxyZMqmc~d;Wc&I8CEvsKqXT0y0AyR zgPF`7&5~@uODHn(*)%Z^Hh#bTXFHSYb@3mi(ez+lMgj^LP@_+;`8bH0d$45;;>3!4 zn9Ikq1&p|_P-Ib4rAl5Ou6~j&toc)|_l^m;1LD|ewL#=2UKKibfhqHVAZEMQJ-)Ew z$!w?R1dtrQGwvKk;3WdoSu$U%rpT#n@1=RugKrJvU+=?F6PW!vS0?8=OL2%{ywVWu z#pVJ(Ls1%$DzA%|o=(=BVoUVRSXyj#DO7OtEV0{s9==@1)mnSIIxr)kdG}#UsN4@m zE?b|xxI8h=$X{mV^`3`^eYU9(MIkPN;F3Xv|R6OV3F#K>UZJR;1lK!NAw!ubNiDDbB!Geo>=%hhvdi8Bu434?)oSoit+5RS( zg!;O7Qaueb=j=vW8~g^dBWfPM`dM(w;U37ooxXL3>h* z(oC57uc5t<(+{8?D(ghqW~SZ)(^ESOn~~eC6I1a00ju0bT->Ir@9g=muLR+NA<7jw z?{GR8wS>~IFu#Q>=_zfvnwj=yJ+{`{`D9P-G~Gglk+}KqSuQD|X$p~^e(J5IIQ}R6 zNx_|I3EFhj3p3~~$5Rp#I^ixCdZ#6nhI!vBF3OD;{#BJl6o2xU`_?ExjEf#A-#hq3 z5#q@ztKG=QS>E(hWKnXL9E61prP=G_!S*ndm{#k9Ktdz^{+AdMwp|~3P!Ik>kgR8E zLsx&?L;=(rfS}c+j2+aC;V!vVep2DXiizF!g^L90_qva*F{#nHkg)~>}-T)s=5ge#}sz2p^DUo$R z}Fp|H>_4BLznX~z1(XZve;{$F~#eKG^j|+o;6ga|^RZ`XD zq^|NQSHd9%{=hP6IK63>XEOuq;lqsX{&rFZ?=>P{J@{&bJy_`ED~uHsrez{^V93h< zn|2?odWp{?Q6`mzUz_;zL{Nvg*K3VLL2j;jm*~)Q?2QW11?palR5q0lAQS@^!tvhw2_%@^%UHO9d`QhG$DGm*^z750f zEknn-WxE^H{2HgC4#)H(=^?C$tWz_Anc_FD)52V?@LvgBm8H_pgiwF!C!nKk>e>WG?$Mi^?Ddc!A=h5-=(BrOUtLZ6UMrys} z&t*s|!*wh7so&g>XS*e^aQI;^1J7|h2;oG(%&C0;t9*0cu;o);;FetQ!r9~CoB-)I ze*S1aH7wp?wQT>AKvKw!N-NSvXF!k7JCw-8nA4r=dh_cOjHc=m-|Ff-3Fow11d~XB zFMyq#KH;N}>9Y*2nV%ouzDTuZy3%NKL`2l-oVU89zaCtZ%bUzAe1d2}Mj&@+@Rvuw zHgmiw?zna%dI=qiVuoU)$i7tO78Y3eICb9}=b|k)EZaqRg{(kz`49_# z3h}43%Mjd_--(K2CgV1we<|s%QrdGHfn%B2@g~h}ZqM&^y zd`d9e;LSA`nG0v^eLVMWP6V#FR44RJ7=8FDr)+i~i_Q_#gpwu8B#z8TUf`F$M?ya+_C;Ri3!WpR3dk@GEJ2VN7uZBi?VTE5 zSOhr(4-=2m8wn0$?fh9DUJ@|Z-pqonYc%ufCX5N5)&@5>{4SX+rTnd(?EW1$v~KE! z0^pXj%uNK@qm#GJ*}dk#xFttpNb6!o*L3!I7C??;)2Z3XpFJxcAGdVC$r$jlRLyaG zB=3c<>ZVMdo|vQ6Ob$oU_IF;P!#ul~K6me1jfQ`*m_a~eAKJ<8a{Ai6jf0d;5xEyS z*hhjYzX!7OWa%>y?sG*)t2NE?M-u_Z!T&@EWFEFzbmwp?F94`6V^-orM(ximy4-QO zLf_iBJ+iHNl^#DzlR5h8dH9vP?~J(9@6Q9O)UxVm)Fj!`EOw1mxoSH#Eb}U>r^!JvK;wo*myj+3oy47*s;YzN)WN%j&(&k1@qGhMf05 z(y>vNP@8x?U|($jk2FG_%amng;fC9+dB59{!qNf5t)+{tzTX?~el5Ev@3jSmyZEge zRLOwyfhbg_&Y~saVbvhBQ1^1UEIPoWp^4UTqWPDM?VtToBQmN2*$(9?`j?(Ez7)x% z9(Y`O&;QoW{v&G1!I+}Sn5Fm6u5#Hehn)7>VhOs~>=FP>Op6}oRu>crdr*74eaF>zv&}YgdbCfGfCn zwh4Sb$ZqR0UN>^*mgoYG+o?A#$Ez(i9&yTE1w9mRK8~bKRRn^&+$6@OEle1jp;oy@ zgNM!!5fala(_1rZ>g%0yASjP%?(h5s=cSS%Ths+}YT1Lv6^iynv!FTPAEpqZj!eM@ zWgvOSMDE{3?6<(C%p-a@iNJ1wnvade5@gXWpyL79W>#hOg&Al|qZ&yPxKp z?7BW1Y}U`*F^t)HD2rZMjTLM)C$fy#kPfG90*L4|*h_VSI|d zfwIrJ=glO${0~4sR#GgNlc{oWv{&ULFvY#p(C5`z7aF2M(Ux{6=jmpNpz1+x02qA9lP#fm76&nz>2+^WazAZ;2-}DJ;!+m@_kE%7(8#!K3o$wzT@L#XY z4%1PtfZMrN%%Wp4J5OHWJm8B2W}WT9oq6%J=UHuiZ|u^OwXRoXY)13Is}jI2_wBX8 zsjO3%ier^rQU|qSEQBM4^<7l*qIf+o<_k1z;^b^!K^%Jy2Rp5q-CrGl|I`r1Q`Or%~f_zqoxDKS4oc4s>B z>!lwQz^m)~KI_+(@5t;KdY)RK+(y?~`VTzNd@wWorPXCuiT>md zZf@Sioq)CdEa|drs$`*Y?7iPdyUx|rfs3ls%0naT4VuE#mMZSLLMW-h22HIGY07WR zl-xYs+l4-8?_Su84YrCFKJi37fPY%nY+psb?O8QEx9pj)DBt5;;A{k8TnQ9OdQUMo zyUB&2|AbrxMwIK1(H&vt8qEldL6ZTKPs(%kp54N>!PfxY^#{Q8$ytm45~MMf3;C2V zR6zZ!F|JEZhAewe;0dF;g9lJRvKn#@6V@ocHl*wf{IkTvfLCB?_ zAK$HRjy*)x=l$F~m!aKd1NPnhS{l~WG+vUjRP5{5@PFkY?Ob2Dntw_~E63I|T0(;|Ab0tL^A=3UicbjL+{%WS#FGR(IU@Pr)~gbA#xQ9Pj z?(Zhf(>Zysf-1THBL?01c^fPyzH%##qwHMZxE}mZwW{Vs*Ub*aY7UzXJ@aWLlfe1q z3HDIL{?@2uF800;r8@1Ui(HT2wb1qh5eTGk`f2JSWSu-u?e*3b zFo-CKSKauqobfO|)BG`LV-jJLrTcX+@wg}WfAF<`eM&ZrWC#gG7EpdbRYOj@LKeCA z=}QXYTvm~DVIdH^1ZM8!pH8S?)6Ig2K=^0uLthljNT%HzZ{e4Y+_pJo)|%(8VLzm$ z;o}VT0X`PPO=~+~=%IhfLll@Pr)1?S=1$Nh>zWd}zZQU9)w9Z1G%qqHr z0AZOkDrUwI6qJ352h$mD;_)oLYX)r4g?L#aSuNasv?Rd9hGZbNa)6%*uUYtp$_3eN zUTGQ_{||{_9iW^vkJ1j@^)lW~$E-Q{3SL(BaHF4~6xk7@d3YU*u}nzzDfTF$HL!ai z;OOF1t3i`_izx>OR$1BLG!sg;QGEyJb+T7`_5T$L1%WfIty|1iY;I%(bnB^w1OE(u z@1jeQPp(_#HnYS{pLGCRu+3$Caijmf@iT6vv&7G>4_F;XIqv~K#hI7vfdy^c(8fF2 z`qne+L8+}4oUQs`{QMh}SqJn3>Worgss=kI3`lp6ACSw9-K>(Ss5VBK}s0VlvK)VaFSRtz)hiS<-rQ_b(wUu65J(NtBZlpm@_RN&o zrFAmXEn6idV;9r1q0R+hd%NW|-?W$oJk08w65;7YV3Jo!+ri&aS_S!JwCTRIYj{i;|b_w zlK-3F`OHgtSDAhbWHbsm9{R|-(Aouke0ko~zA!!fD{!``#Pk2Qe5V5*GCYYAn*O0R z@*NE-zGz5oKP$J@rDqQ2=L4rgxj$TAKh09gi-pmju@}J1Qya-r!E&FIluS#KFqo}U zwK05M_@uoiB6Fmtc0UkVRA65m>8^2D)H)X;1&P~H8buPTpBl898c}VNiGjiYAqE1! zH@7G5zdn|Ks1|=aiz4p>)DD`iFXRGKI{Ph%A&c9rOP!7QGkRmaurpmkSqHr9p3B^* zG&8kJU@T+%ldHNqR?vZIHF>-mE!IQWCwx znynE>mg_+az=yCj`X9jk`r>V9mF?0$`AYH4zB}t3{ThD``;O9hy<}KLK1B6n8Q#ph zR97ua^o{$BwbS(Ga;%*{10Sq&F^bzXV&&K7(r^Hg%Dq2CCA~XF2v_G5NDv6i%_R-J z$?msHqxA_FSfrnT8o20yiC7IL5&pna>g|YnK$+7zY)bC-eWPTGtaHvf;N`K=v$=o( z>C^o0L7Di^O-ltajt65y9{Q~fUyDX1hmG0m+`wR!GzEMX@0vS&K|+G=qC6Se_!aje zcXVNGa}<1z-QS0Nx8Xh6qg`CzIof=+)&ADP^UssiRNoz_V6@LqD1p4@oj1jn>R2DM zT2_?Sr7i0@@5|pmIDIr8FyiE%(~95Jjl2cUOL>gk5}ik`mW1yuLn(G5t8#o&q?fBF z_`Yc?-I@oZQoqLUNR14vn$By{1Y-|Tu<+SYDrJ~A;m=arW<%ztyF`ZkJQKuMbei#j zMJ+p0Uj(y4MQcg7tS*l? z5-06FLp&!K{^a7byDsJ~kP$V@-U*0F!z4?Ke6^F01_LSB8jq1LDLxh@0xXB^Sn@!(2U??u zmMblFy!xAC(moz#zFEwXOT4PM%Q-aqPL`$5!73^TCkQ72bj;@ASrzzZeahRn zl}y#K1cI{R_|U?J1dUu`qv;L9o4$9m)b3;P%*AgyT-I}}GGAdtrFegO{vmm85`|fZ zB?8I?cicgp)Zq4@gH8uEH!XU?_+#&zbJ*A}MnrvJWnx$ZvTg^&jxrnJRiHd2maz5f zryP%4efgdauXX!T!qOc7=vKoZ#%0eZ2dj`J0ye|jykK{-PT?U-_1!~;A2ioc3g?-& zGVnA|8+uZhPjQ@D4l6GH4AK!o;EMkjec^A1J_vi#&nU?&U2H-{PQ8@Wy3S}D-H53D zbSol*&Mo5}5wdpgfb+VtF`t_w=Z=>T=`!iGtviA;1O(re`=n=}YpZ`=s1=#mnle%77{HB2V z+jag+!#G}^>@Ly0wv%>2KSzmXk!&7a{A7QNe?pfr!@0P@2~C$0A$!t5D|u54uqdcZ z5^@YLPJr=FqP2Er?!ZE_debkK3Is#l1+emD5(Zl2MrN({`EfqUaFb+4ri{xb0P0h( z)?k^L!o0+s5ZJzkE)v}>$KZ5tR5pUSmWmZIOv(t#8S*?{@a%WtwEg{wy}zf%8r@D) ztXoU7s1L$l%gTUBibSMQs-A>x0J8GiCqN>q$iJEp^7Vb3{9lA{@0Ih;G5yg|7K!Z zdyM=j(s><5tMmKWWCGoSq^Zu1N6$Z06@7PbFHu(?pp#wuzOLsw)f$v`lm;)Jvm^5Z zzojjn9e*eZm>}H*imyEbg3iFHpO8amfKRbe&%vv*WLyW>+%3=QdYJVsTp{L97ihus z10bD1IKVAvFwGTB;#M)>n(iuQL?wdwU~mVK-@x`?TS@+LnW3zo^qh&AstPV?npU~Z#wpw1AL zlTccJy#t_M&|KXlzl1uDcjzlWSMa`Al`IM#;@?|CTN)advF|;+#1I3|Xj#>O5_H zQFj^i%;uiXK@K2hRyiDa1Hu@6mN?IM4jBP4dD_j_1ABz6w0Z+4kdRtK6F?9{Qhk?2 zZZC}1=eY9oQDV5FqO*i@?IZAM&&6AGSYAu#?Mb8116Qf@6k68IQZqu=aFd zn4d4X>1NA}&(DrfQXs@E!q#}gtxv+5%}IvXG##RQLnhl8`*RfK10f92T9}ss;V=|K zdH%zqWL3*A4jVes5B8QooALXZb)>b6$u^tUN9z8kgpyo3F`=EH;DPOvq;#6w)9E>v zX^(dH2E~DG4t;*ld_6iMNn2Cr!`44WRBbEZ-fQ$z~+vJYXQ+Zzq`m6 z2|^IYvuxDAp|@@oRZY#tD!At`6p0U+Xgcp$dJH6_cYPJhM%SlZwd(KFv&F_#Tim?f z-*-#^kO1yyqDCf&jD6gOcbz8q&tm5{JF)qF zsHomQ9*2t|-Anz8V*C$6oLq$UYSc*W;JU^%-p2AVog9yIwaC@>3j}?7qzwvZuB~G0 zVr0@fWb7>QwvJl)7AURw2lAVo@ zYj2}(dzIX-c3wJVU#5tO!UWN}yh=6WnQK_E!8+#UJQJq)o`k{G7izO^p|mt=1sHtC zRYA_gflM1wUBCYzG>tJR3XFRDT&+dcD8O=lBAJzLPG-~KmxIA|))lbbX^%iZADQGp z_Gyrtg<|7Tx5vo*a*i-z8<7J+0PI#{tJHEzF{JLpXBYT6sS;}_ZcficrPovYeoWtNw`A=4YcvqM6 zJS&aUGIz~1Py$k>G0{rUtep^8S6H??CxYfUUPHFGd zfcScPI)F{;wPo_&PfQPLoS1rKxSCF7q9WwAux|yhRG=fG_>a!t61smF2LFaW$U1SQ zZ_RD#k&W%O(S4rJIQQDSK#pcA9@=x)$){7Bp;VP9OjQ%`ELDI@4nUlU)^^m$Z@%HY zO2F{x+XMb}i)JXdk??($n-H*J3R+wEnKJg(b6aS<9vNlEYObBFMp+=_GpN$^L}%21 zyy^nUn{!BV-LL=|EqS;M-I3#bI_M=o#+n6hnGBh2^RMTn@O9LNs$nUeYC-obax3nM z^R3>D=>uU>kbup}{?b?+{AW4ucp2FqhUp!A&te6#3)Ps`F^cTyoKhEyS_iA#PPdncQIAwK~YY^)Ag$0bvJObsRQoG zR55nV^yEn_Qki%eJAgceGJB^J$Pqj2|H>DY&PScn9!md%6*76VTnwmI;7K5X+`(+O zke?eNi>?nK>df~@40jWxLid0NiUqc!#R^?3qdo!0AlE!t*#oC;Y@RUH;fjxVb@bdf z699xlNi>7XFb2c!>l;I6c4@6$Vz{Qs(gqnofl;}M_-`wkAz%ej88r2Q%q`r2AsS=Y zv59%k^6lMjd9g@BvX+M~d9F0J#E@64U`Vd-8)%oSlFmMs7?RLhTCAQe z$WNubY~f|uIu1p@0d$&N zb2(S5#h@B?2?+D-RAOyMsgsauP}$j1C5Ut#9OUWM5Ls&uNq%9&32FK>MLDdLy^FxU zz8u8iyv8f?(Pm@FSlM@Gjl=f;%5Y^1I=(@Z8c#Vt@^v;2R^j7$9yvx{<8NGVqNoMR z>n;pzl~qyCH4eYmpvK`>@(0G`f69DLfJZF{T*^|3A$V@3t!g^{Q9W?oQtD-T6XS zC6rf&ttvcq26D4V@7<}Mo=7PVzQh1O%v6nM88)$a^H72^0)>Jar0PBv%b6`-zJ0Fy zOI{XR;P@@Q9?W2Y^|#qeW6HzHnDtCuHJDA?@DG=TwH$=%OU1A&-@e0y*Bq(^d#pm1 z#45`8o-pZGi=!^Tz6Q`veyrdIebwJV z(JNSkJE)doOn$8%$+ z5Dq}UlsHP)mD;(zF;qO$?ytE)_D1)N9sj8h@Rw>dHRWrbPL5YwDSFBu8&PysO*F1s z23O5rz;x*i|D}ja)EYkN69aMv65$`GDL`dwFQ9QhU^Zm^I)$Q_w0Ic#t#&*`j5MGQ`1Z!j5h(T@h8`^%37sOWO!cp1Y z=2am%#R%clq5z7k6)00G)^}GHx8ppYJhV{m`RVRk5a6t|XHC4N-y5xfsmMoqbo*$SsNb5b3P8 zGt16~I9{9k>_;ggbV0$<@%)Jkdy9E3)^Q!uSH3-Rg?n?N#4v&KHLvsH3->(tC|lK3gO8 z%{xnjOE&G}R%rT5OQpu&<)p@4*K{VhsSVXNR8-L;VPb!Tl;nrZ#9p40_DC^}sG)86 zR+j{hBi|@=a_Y@wIxsYjO+XBZbA0G*&jCAT+JQMq^McxuNQrL{ZM12%jn`$**2J?l z&ei5bK*_gkR-x+mNiFB8bPtz33408$rx5Y292}=Y#;(1qKbP+bW|b=p>`u9yO7&5L z&8s;w&N6=0!;!dN#>}C?nQsS&iyAGn&rNL)iMhs19R;s1_Q|OW75U95w4hkV`j*_4 z8&)eD{Xq{M!XH41RdcH=3TRb1MR<=YcH#+T6$db zsaywglxKk<>(wZy?Rd7|u8K>wBB#9Vd(tuZ!=nADmH(u^zJD+f2!X2jM))oJ`Z?Nr zYBiO67Tw^v<~J}qX%X_`(cZ5S+m%X{`$N+lHxt!)2a6Q=;nCrP`UK?@5q`Cd$e(pJ zet~k>KF;TzLkUNWD-uDo+hf^s>Qn1AirA(_mrVh9tj{YatnV#`a7Xytkrx#&YR=wY zshJhl|+x;5f*{q3deC#uD>4#`e61si{pEc{AGd1z{DJD76(rGu%QiXYmtkqQi7^;j~xaYQM zGbc4=)-GyGRic@7DLFLL#5BbPHxi>{bs+7Qc+>NZ|Imk2cwvnz240vPsiU&5O8H_X z^_+TND>pRC)uOBXnb9|z2)*PuB~f2e-=iIF_o8K?_ZW_X2=CDA0Cy?n~Y7!(jvniqQRdgHHAt+mnQcE8|_ySQ9k<|@#dqUBQlxHoSQ zz$t2hq05#bPlt|u=wu!D+xb7DjU%tzdz4+Tq4#qPowvrgjyRPZJi9&RI!?*`f?k9@ zzU4|1hW{k^7)RjZdGmb_*6XEiFMuKuj5Tf;?mDx^V?FTJvj*%ADnOs~1Ql`#3Wm>n zjPDjL82X>{g#<1O>N-g%flZj&b}!FCua!|{F3&4TnT5ux0l|A8r;W@-(S!KNk2E6v z(KUm1b({?&6e#&uh5b0Ti9 z5IfP5tiWI3!Kas?=s8$DGj#4u6~+TD4xYu6R>G(6eR)9SR&?Q!e-a_g5Z(`(5(@=( zyBlu#-C(G3hxb6v*n1XmEEsX5DgnZn*NdSD6M@SWkqq#izKG-}@rD`~r7(t@z1&Wv z_2-a-V&=pB{oVyA)~q^;MY1pP3u?eM+;_b*r#^m&Frl*a^5=Sfl+zXUvzfkks6=}C_uyzId(7b`?E%UDNOA$M8bKCGTbBv-h^1_*10t^XUo~QG#NL{s)SAq zslD+&&HJ>5o04qxjrS#}?+^WmvL?&+o|n6__5{O|gp4{QAA;l=B_i<+LM^sb`_jUI9KxUuj6lc_0>Yq0_E*dA8 z=V>tCoSR7@0I|w5r)^~DUL6a%HFJRbuI$wZMs2Z|qi=j}o*gc{4;m9dbw_fd@kduF2`uf3jY3*7+o8LBvLl9V${oeiW3)~v9?f2lWaAOEz1y-bw~_~vTrl?y{uy`%ZRbO=jeW(-}Aih z`^Wq5>o1?V<~rxRj^n(J^E|%C^8I`j=Xc?KZB|-_tG^8ukYZ{1=awhdSoyKUAfY%3s?c=4W z?{_{g{o+sV7E32{=;RsURkC`Dg()YY48=UVu4mX}^Oh!0l79w)VDOzY)8yPaRYT-$ zRbt+?)YP)M6yn&>iywnZ$YHMvnP>qz`4?%VbB;u9v^0#+RTdKl<$X3*QM&-ov39efdt~&$}L{W?k>|TnA)E1l47qI~p6kg<%0fWlixlhha#B{K5P6 zXALe0M!f7&JMD_7Bj@@1@|PEe{H{NBSE$nJp|e-FsrNN6DY*jNE1b*`eq9XoJw7xt zlM3^=dwY}FU8r=Vk^B_4bk4d;_S=W|8+w>*LUVHZ>5up8tV@+@Gw&7GzZ3H5KEP`pTq578y|Z=WEq-S zKrb$+bGLV5PcMBJz-fg7_Ym_CMal!eEYLaM$eRbFKu`dUX$}-Zhn{vXv};g)FRDnK zO4tW+txG^7hOQLLX2j>qLwv#>xL2_c;-6*U#KqKvCwk6VD-Z+s&Vh~6_OkK~K6;n- zF~t%g!Ah$b*;WEtr*9}Tuc_K98GBZJsb+J$9#iWKt zrbdn2mC`Cz44S5Q@jB(~b-$aj!;&Q%Q!g0lSGIC3lLc=gNh&BhY~7 zc3#lW=Z_GJW1Oz7(8udpNjWPgq<9^^7_V0rxRErg0Wj0nZA*su7Y5ejeSrv^px(rK z8OvPoXJul{gHo&#V+VR{?&YSCw%*pp^R|JY^1hgYLFL@uQr!1PHq&dz48idXglqLy zZmuBuxj3JfCxY1QATNx;<&M1r2WDEMZA?1}kR!72md#8dCKh$qv+XKTB)wq~2ltO@ zuDRtXl4T%=Y&O;rG*&4-(>OuPyIVr;uw$P9CRAL87^fjuMc03 zd0uwWlgU`XX-M8V@>s0I?C2^XLY@JLxtRUvUHVeyb{?3^a54|z$rJHGY*bII1Jc+* zkRu+_;g>r3>HbK(28-egyFnX>NPEIWbz=jt-rvtL${? z!!`U6$64E>>(-EH3WV?uf zj6L5YrDcA3Ru4+cHghA3z_q?H8k;fi_2BfULW+k{hh_~c@rx$gi#5jYjHznBCmzPU z7=1pj@-aQxN*6PLW^7Z?*6Oia=2&je@ERq{Y~JgD5^0GfY7^`8v~|M`Q@EkIIvY1O zw>CXq(P!ie*CtVH+^)c8+3;NN`p)UPV$}J(4v49DeFOIg#bG4&_l2f9%XU#ncTG+s7-<(nfRIc#v6qa^Y%@83APwIv5na3Hlf^% zj3F5nzy>$6C?~(#!{AcZeJWD^-7Gy;pM(0dzOpg1F;j_H6h3YP$rvoE3BvQT^H|Zl znXgF0_aU>KZ@f$A% zNSmHso$vm5)*JfKkRuHE0s@{ZuuL#JI~rG9=`j0PE6-&K2fc8I z|FL+mIl6`MXn_gROnjx=wYZ)6^_8f$yw%A;LklTec={R8)vij*#nkF*L*+HB)r3w( z`OjwaWRD4q+d2}!PO)|5?o9P*3n*OYt$OS5?b;#L)OFo5ZZxNd!dP~rq3$n?#?^Sb z*D9ja1(4LZOe+gr2GzJLa)o^4*kNS_g&8PXzOmd5&d$OKJC484u`XU1c*Ia zy4$R5ckfv9YWWd?v-oFy9geS*JjGJb1Y5Gy63!!8&+L{-=g`|~kUhF#h+NyR1C@;1 zM7dYrW1)E6%iR@Go<>O2JL8s!(#vGytD3MfI_kpf>cg&yw)o+7$``k?ZgvfW=96DzW+~-oI*&$o8VFnjAbf%Y>3^=NYAW@WiHiRUC z$b=5ZM0^;Mh{7w`!XsvmTixhRLCzwxtvb|`Cq#*)8sn;4mgD)?N_N<$Jdd5C$1;m| zW&N_8!ZX9vQ^pLat6i5kWJH+fj}bA=BE`R#2H)KQ<-^W+ z2+8uVDjd_tK7Kb2n32PeS|^d4phJ%dgIkhaAxVJ#Z$wYb+>#`ICB1DA7#N6O9cHSG z8MY-P+z(tk6I)jJq9(rv+*KU8F6qSF5JwY~5XVa_0!3Yrjqbd_62_F20KRvK4wlq#JZV02*zdr+Ugk&iDK z|Dv1p{g6x=#UGIgGKPWYSB;j29*Y33{$4{;${-bXxdLS0@==|UrrIR>_C_IO+X8p} zrsUM%nHT7f`YV9$b8L4;sdkXCnpk+!F5Q-t>F9XkQPfGg!hA@np&pHz46S)Q7T7y`nE@NN8E$+2j6b$nK9A{tJjSWeRB3T{nRBqpLILh z)FT^0XT_pxwvt<8W?J-gSy~MEN%}^pZ?>0O?e|ubgFH(ezjJF6usu=>AA*jT*3{1r znx)PW@Rq3kZ*bSL7qF9xS*A4?2a8@C=66nWq;@8)$bQNA>Yb^;U54Gkgzs&cFOiM6 z-KUH7^wXSr8p_|Ow?9&VvJ-=H`7DnjMsvrV&+EI zBz-d&f-7!b_o9rtJxOx3(Y=*g--bJ)c*Z0mV*M9{o!S=QG!^InQpvwJz29|L`kN%P!6wp?kGx@+N7IXvBRf>=X2ay|%tpah&)9L|t%)stZAM z%k@MPj^mP8c<;|tdp2BVG*10p5$L03YRWm=51ji^8eQge9mOCkZ|4Kwdl^!N;*SFt z4RZ9bD^%fPB`y~B%Sa|)8P@H;}F=kg}myx>)s8d3# zXdP^-`T;3QRm}NMxmEhOZ2jrmu;+(P>SKSc>r7;)o;wu_+q$JN?doXS&Wf+QXvW~C zEioi75$ax$=kJ2K_ia_)oZiiI@JF2sp4qjB?e4XU{Jiaca+qm+P@aDD?61aC_MQ*h zyYDzYm$1RxK>h0;cRE7&)u70VCuOVOTz)d{u-KNOxRAee`1y9?pm9e8Vd>XOw(k}S zsqnieh4+WJWwF2_#p=J=1|XPuO>f^c8s`TY>M|hHH@eutI~6|>^80&qa!0zq^ZZiY zqmd?iH7ED+%dU#jITwDTLZ(EFzM3;$Lxx&NGDxt~#eSAN=St?}%uRlBgrLfi?v7}a z=QN{ZfRod|uWMMM44&;vFnrO&>58j+X>=wr?TIl6%VfEgukHePSRE}du1;WVL6U{P zG>i=h3Wljs&MQ2vD^g-lPvf+SL}RmIJTJQjx|?**rL7w<|2@xo zR;WszTbWX^KcmBglwu__;riquZP}8FUWV5R0vu?63p)D5k3lX@?J@z!_|mW=zmr35 zl^SHy$zJB(nke0o^q%UU>@-Z{*_|-eDby**dK&JPsbZLRbNykgYnLq*h9pn=O~q~; zHukGt&xVW=zO#D|WRXD0KO|J16Ce#H4K$A&yRHYITSwksny8sR1Zz7zlyBzy4?F(6 zKC;M|_AlUF0Y^;u?>zkS-?C#zTqmc3 z$9dyK$Y1b?r??YxcS?i|G6b2yp14K&<-Mc90B19vj@>d5)(yB{J#kD{p)*=Bn56aV z#)%2OWqh5*Aie6&#o+pW{g?HfE!Rp^URN>A=7#lHHd8En%V|`DH6r13uU8j<>u-1} zc%$#;nBYG?%7G7V>CNWzVsVx}JJiL4@W?rnsU_47Dk|fn_t#hRtpYpt*M=p$04$2k z(^ItBViJzL7-vg|h8Oy1gJhD7DhG88$SqVgrsf z*Xuy`FW?yKy}QwKlLHzo!O&s1{Vt#)vBq_DNh|MA$D7bnGg$f9W>VoMl?!cWq`qax zhUwPkyQTq%-TCMx5N+H;hf6(g5E4;mtj|?1f0K$nM@TfSW1`cB0Rkv0ogRks5J0?~8EYgP15-pTWaX(^ysRWnxLKu#82=q=|%w2UmVxD}r zVuqqOQC64bxSS#>$Kb+h93|y3eF2=d0D@b@(!nW1$t*TOd#F|@Vhz*mv?Sa<=JsN|B;i$3PWs2}6 zYK7S-4zGn<2W|UIcfWy_6k`m>Jaf`kKQ)GN?$VC9`(YJK5^Lg_%BOMPrfo26=RZ1_ z{g`0lkN1tFPrg#B&P+F8?(o}l$wn|Dr2l4+;7$4*vHj}SX6-Cg)0Mhob*%*pyS^{t zH^a9{X+mCia=INHO(5!ktqt;mr_NRKX8_=BTBhY6uOe5ozmI|(_1i)FyPIhiTtvv{ zEx<4rsE?*&PQ0<{_^#8X#qixu($5M1lVgy`W??RkOcq)B5!W@3&%r+$o{rMm3r+`k z)?Y#o*y*5K8fTI>>HjYO`1?mpGB@(RwCqadZ0cxX*rfLNMLIfeuFE=F7906Fp-m9m zThPX*GQUmdYF>I_xb6)!On5C2)F?IT&V7?fr}% zW#mxvDN}z2=XPqOW?>gYdUv?fg11`jYX%Mv7dbVa-~KGol31>=Ul8e+VfsjO-BC-D_pP zn=ov4LT~!DI$Zv2TA$t$S~1NjzfGb4Myd28hmR()Hx@$4$%!bD=7IcAit3H1Q{#fF zfu5J62|Z{pdQ4IesbXRZErr10Hd|M{rg?|`e3;qOiHtY&DBYWXVL-DZtDuSz-Wm=d!V=s^u|2&X87(#YgeCSEqXG`s*`@+qje$k)b895%}@8~=;9SU$Bj_Cc6D38 zuMTNsRiCaub4np4X%|wpSR&~5gC1SSYroy*qQSk|$%RRUd*fo=fE+?WY1@Ir3t{Mp z6AIw1%^B+uQsnfSthl>^vwP&t67Vq+`;rOHuaw@SN|(`xv^4!#5CZDxOh3h0y;00J zvCx^k?5|&ld3ekw&MNOVa;AKhv$89`-#n(eAjt$J_(61)7SRqN#(8HNm=7_`(s&94 zyN#quPE1>I&U)Cbp+{-OlJS(|Nlv}3kcm4UjNQ(ad9}x%_OHfpU_vQ_`okiNKhnpV zF7jE&D}6{7;qNiD9V}FmyAo5-sXU8uYK^q%0;%f2qp?I@VVpfIEQ9+`{G~VmU@b?k35!zdn$0DJ1PPPfYab{K z80gHR-=biItYI21Bq9gH$R9ekN5D*$S)JAOw@K{0tw~kSY~k$|Xur2g5F&sWVHS4Y z`s5VtgYuRSZH2;c6+gmPEg^!hs-efdE1iV~ry_3u{#cHZ{}EqJop{J`zQ}WFavfx* z1C5xLGGS+S2xQ5HyTNo18q-===7DmQ-dBxn>mdzg>wH4Io;90mIxmt<>~&PXR6KkJ z6~V5SBI2UnSMau(OTG`e7%y{zpJy$kJf!hKymHkbb?A38uyr8oK>m?Q8@lJYgNLVFEA7kMT`!>N5_{KOrEn4JE(x68M&{pMq-+cVwW zsD{;-5pYp^xjRVys^pes{d=kslVNEOx*AjcwL8qmg}tl~ z;(YXNDoMF&ZFBy%^ee=x7KzEQ!a!vaKV{{`nA zz>cK1^aqg;BLe=PNXYK+CsM2Bshb2a?q)V=xMa2|jWC_QSq|W_yMMRK)a7XldA*~k za3GFBUA_XaK#`Qmtvp3A&IdVF& zh^`R@Qch0cA@!zcZxA7FlPFf!M5sP9DFo!ynW3e)>b^SiuVggX+sz2TVj}Dg@YO|f zd&GfSuX@YCOs`>sW^9Uy5Iz}%xC&ux^l(=HWcXP5yv3YT)?l$lq4a zM7KVWc1xD}JqZx>wpN-R^tShqhsgcx~z&EmK!JRdNX?BnANj|j-#fxr(&SN9}-Fe6NL6( ziIaQI|4sQ#N6EM_s})nNOUhb_BXs}rzi&gX*O-c3{ecbg`6`JTc)KcMpLMzXROp8t zRZ5PC)%L6YwCu)ajVX44RycljBZ~uR9+>qs4IPdoN+2gMtw#23qSl)Pf)hGi2WqpU z?O)XzjN*F76#^=Hq(a>iDlDmuD;2p_Whno1m-P#meSh$3Vh~?VSNIYO8zC;cgPHBy zY^zJbN8HoI4>?Lc6vA5e;3JggFY8CU1NHywM68EJ-9O2uPRZ^VDY`;(884vx`Ps0)D9n23J|oU+Gk{&6MqAGy)M7OL|bMk3DxU^a!0HVs}HBM35# zNqug<(f>EJ`+X!$zGaj;zFvXIe^&6-Abk-p`Ahgt9jwy7qCS?is8x2Q9w*kS(-wgD z2lA`4CIRYs+Uu3Aq@vu!c5eN;L7jHIOkML+!=dmhW>|n@-QukRF3fN0-;Zo3)_?n1 z^Za9W=YkiO52JU~|LWM!ffrW5H^$Zy^rw)*Boqt&Xs!b0N({{9uWT03bOgH^41y5< z3YPqD@mt*k&tYpAJln@)qt|=1T@MeM+rec>7fKzHV+!ot! z%VDz;+*(gnXKjzlM%@1C)Ufq?5@ouPWjpblXEk?Kmlh>BhJ_ez?~-_%j&aGv_yZZTMSri4#-TE8jF7$APuAcSDhz_LO=7{cP=rVfy5lo>9B) zmQOL7!77fK>%rf14vZ@NVrfB$G}jw-RnQdrjrQ`jn%uF&7&~?EX#twk^?zFE+x1T` zEGE7sph}q}$OuYl8i6j9&F2S)$MRd5&#WUZ|FvHD-ftX;c)onO1lLwNJ{Yf22tg5f zySuAs9%!ZP#sjwV*T>FzqphZ^W>b-YAcN5!KCc_>or9&Hi58)rC#(}kX(4>9#jTb0 z_4gq(R@&u;r`-DN$KIkUclzH7t+u#ysBeypiY4FhB`!$@jofQo1}ur1&Atku=f-KR z97jRGu`&D0004k$3qUAjRMJ%GRD_Ee-z;(xeV{@=%YOk*`E0h1zVX z12VK^dB4`LTA8cwr#CxPS8kLmo;A^N8CxycQlG{60nzJ|&$7MRxoVdn$j+qrqw%c} znH(x?bwr?RX9-M{AYw8tPh^?OVjZ67^c!k>!IqxN7m@ROUA&wRgkd24|1Ulx4!oMrelA$2sJbntmV zo8fs<_`vjIVd6v73y=5K^z_i|9=(YCZi72Le&=h4hW$vh)!W^v^9JL?=7}A-vzjFN zit-pebmn@(^sBAi@R<9%xb-yY@%@x%1x}45!k#!Zt?c5X2B9x2$W9T`?AfmrRkzwQ z`vwLwgwrEs=kAbq%C2yTYOag~XK4<%UO{3aY*%bo>{jG@@)JBfl=`achLun&mXz1e zcVQ`+5_A1DxQH|7h`S_(dNiZ5Z{(V@`-KNqrYF885EzFIIlWY2Pcd@+0IoU@K|CWp znd-%jo~Qxta!b?gaTOzRX#XH2;|+z)_Ot-5sF@2y65OzZpK8RQ*q9%hr$#tjdt5cBZm&Mv1u=gtN&uCfo;;jbqB7g1y>1)2JGnO2UE{XbDxNbN>p>J4b z_LXyR+pz4ClDDeH8;TKCSGova>(c?#XGElqUWdVY+ILx|M?v`;>eIa7kXg_cphc;0}QrS zKYG}Bwe--HkDZ3xxX`2=Y9~u+x6S|4J$!C(RTFK$A%8x%yAGcg{XHETz(hrI4n!vk z73p)Ye*523Zuvfl+ZD^G?AVvPYWP2Mp8Dx|r1PJ#l+~&t$t9%XNKS6_!t>V$@_X6! z{JK=M3%4&B;>aeN@C9h#K1$>}O)BswSwQ;+Pac^h9UZ*=Lxu*RuJHDzr1Y5U#WHTkavw?6+knQZ*84~EzQX2@;@=LFJ z6B*oUFW2uk$U zlf7yWk8`2f?VAjJ5mv9H$EC;rsDFE9!Cw^Gp9reQXfHsMo`PoyW^#B^x#kj>`OK&7 zw+G9@$2Hb?Mrl!a@bbVUTwB{O1qg@~2E?fI1-urE7j%xarvXXNduz)t@s`(RD9F7T zFN(P%;fPXYr7bSZ!6+|}vc8o*Q_^@;85$0E{g7YFda!(=`SPrn-R0D?b1mK>Nv)HX`v`>{SMVT$GRTFS~BccK#WKH4eOn!pOhl z{(qjh`JwiJUSZ7?9s{;4W}x`U-Lg7vQ?>7g1N&-Q?^aBbZ`36G`x>dAfwi4f;VJLp z7Fl-D=Cn*vF*6rhKma;TyAymev5vo}y|ykh+-41~z63XVdPY8)`F6;p^5FX~d0?S3 zAaN?RRnaf$pJ4@TPiIsXYnh)v_$flP+8qK9s}3Ao?Qt>|4i}! cHjO=wwi9_9JK{xG>A>G*UAWE%ZHEW{3zU2N%>V!Z literal 0 HcmV?d00001 diff --git a/openTCS-Documentation/src/docs/users-guide/images/bounding-box.drawio.png b/openTCS-Documentation/src/docs/users-guide/images/bounding-box.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..eba5437772de09dd3f9a1cc46e5004d0118430c2 GIT binary patch literal 26097 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 literal 0 HcmV?d00001 diff --git a/openTCS-Strategies-Default/src/guiceConfig/java/org/opentcs/strategies/basic/routing/DefaultRouterModule.java b/openTCS-Strategies-Default/src/guiceConfig/java/org/opentcs/strategies/basic/routing/DefaultRouterModule.java index 2548d0f56..cb5f3dc4c 100644 --- a/openTCS-Strategies-Default/src/guiceConfig/java/org/opentcs/strategies/basic/routing/DefaultRouterModule.java +++ b/openTCS-Strategies-Default/src/guiceConfig/java/org/opentcs/strategies/basic/routing/DefaultRouterModule.java @@ -11,6 +11,7 @@ import jakarta.inject.Singleton; import org.opentcs.components.kernel.routing.GroupMapper; import org.opentcs.customizations.kernel.KernelInjectionModule; +import org.opentcs.strategies.basic.routing.edgeevaluator.EdgeEvaluatorBoundingBox; import org.opentcs.strategies.basic.routing.edgeevaluator.EdgeEvaluatorComposite; import org.opentcs.strategies.basic.routing.edgeevaluator.EdgeEvaluatorDistance; import org.opentcs.strategies.basic.routing.edgeevaluator.EdgeEvaluatorExplicitProperties; @@ -106,6 +107,9 @@ private void configureRouterDependencies() { edgeEvaluatorBinder() .addBinding(EdgeEvaluatorTravelTime.CONFIGURATION_KEY) .to(EdgeEvaluatorTravelTime.class); + edgeEvaluatorBinder() + .addBinding(EdgeEvaluatorBoundingBox.CONFIGURATION_KEY) + .to(EdgeEvaluatorBoundingBox.class); bind(EdgeEvaluatorComposite.class) .in(Singleton.class); diff --git a/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/edgeevaluator/BoundingBoxProtrusionCheck.java b/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/edgeevaluator/BoundingBoxProtrusionCheck.java new file mode 100644 index 000000000..25ab34d9d --- /dev/null +++ b/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/edgeevaluator/BoundingBoxProtrusionCheck.java @@ -0,0 +1,127 @@ +/** + * Copyright (c) The openTCS Authors. + * + * This program is free software and subject to the MIT license. (For details, + * see the licensing information (LICENSE.txt) you should have received with + * this copy of the software.) + */ +package org.opentcs.strategies.basic.routing.edgeevaluator; + +import org.opentcs.data.model.BoundingBox; + +/** + * Provides a method for checking whether one bounding box protrudes beyond another one. + */ +public class BoundingBoxProtrusionCheck { + + public BoundingBoxProtrusionCheck() { + } + + /** + * Checks whether one (inner) bounding box protrudes beyond another (outer) one. + * + * @param inner The inner bounding box. + * @param outer The outer bounding box. + * @return The result of the check, indicating where and how much the inner bounding box protrudes + * beyond the outer one. + */ + public BoundingBoxProtrusion checkProtrusion(BoundingBox inner, BoundingBox outer) { + return new BoundingBoxProtrusion( + (inner.getLength() / 2.0 - inner.getReferenceOffset().getX()) - + (outer.getLength() / 2.0 - outer.getReferenceOffset().getX()), + (inner.getLength() / 2.0 + inner.getReferenceOffset().getX()) - + (outer.getLength() / 2.0 + outer.getReferenceOffset().getX()), + (inner.getWidth() / 2.0 - inner.getReferenceOffset().getY()) - + (outer.getWidth() / 2.0 - outer.getReferenceOffset().getY()), + (inner.getWidth() / 2.0 + inner.getReferenceOffset().getY()) - + (outer.getWidth() / 2.0 + outer.getReferenceOffset().getY()), + inner.getHeight() - outer.getHeight() + ); + } + + /** + * Describes where and how much an inner bounding box protrudes beyond an outer one. + */ + public static class BoundingBoxProtrusion { + + private final double front; + private final double back; + private final double left; + private final double right; + private final double top; + + /** + * Creates a new instance. + * + * @param front The protrusion from the front. + * @param back The protrusion from the back. + * @param left The protrusion from the left. + * @param right The protrusion from the right. + * @param top The protrusion from the top. + */ + public BoundingBoxProtrusion(double front, double back, double left, double right, double top) { + this.front = Math.max(0, front); + this.back = Math.max(0, back); + this.left = Math.max(0, left); + this.right = Math.max(0, right); + this.top = Math.max(0, top); + } + + /** + * Indicates whether there is a protrusion from the front. + * + * @return {@code true}, if there is a protrusion from the front, otherwise {@code false}. + */ + public boolean protrudesFront() { + return front > 0; + } + + /** + * Indicates whether there is a protrusion from the back. + * + * @return {@code true}, if there is a protrusion from the back, otherwise {@code false}. + */ + public boolean protrudesBack() { + return back > 0; + } + + /** + * Indicates whether there is a protrusion from the left. + * + * @return {@code true}, if there is a protrusion from the left, otherwise {@code false}. + */ + public boolean protrudesLeft() { + return left > 0; + } + + /** + * Indicates whether there is a protrusion from the right. + * + * @return {@code true}, if there is a protrusion from the right, otherwise {@code false}. + */ + public boolean protrudesRight() { + return right > 0; + } + + /** + * Indicates whether there is a protrusion from the top. + * + * @return {@code true}, if there is a protrusion from the top, otherwise {@code false}. + */ + public boolean protrudesTop() { + return top > 0; + } + + /** + * Indicates whether there is a protrusion anywhere (i.e. from the front, back, left, right or + * top). + * + * @return {@code true}, if there is a protrusion anywhere, otherwise {@code false}. + */ + public boolean protrudesAnywhere() { + return protrudesFront() || protrudesBack() + || protrudesLeft() || protrudesRight() + || protrudesTop(); + } + } +} diff --git a/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/edgeevaluator/EdgeEvaluatorBoundingBox.java b/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/edgeevaluator/EdgeEvaluatorBoundingBox.java new file mode 100644 index 000000000..2acb9c9fa --- /dev/null +++ b/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/edgeevaluator/EdgeEvaluatorBoundingBox.java @@ -0,0 +1,97 @@ +/** + * Copyright (c) The openTCS Authors. + * + * This program is free software and subject to the MIT license. (For details, + * see the licensing information (LICENSE.txt) you should have received with + * this copy of the software.) + */ +package org.opentcs.strategies.basic.routing.edgeevaluator; + +import static java.util.Objects.requireNonNull; + +import jakarta.annotation.Nonnull; +import jakarta.inject.Inject; +import org.opentcs.components.kernel.routing.Edge; +import org.opentcs.components.kernel.routing.EdgeEvaluator; +import org.opentcs.components.kernel.services.TCSObjectService; +import org.opentcs.data.model.Point; +import org.opentcs.data.model.Vehicle; +import org.opentcs.strategies.basic.routing.edgeevaluator.BoundingBoxProtrusionCheck.BoundingBoxProtrusion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Compares the bounding box of a vehicle with the maximum allowed bounding box at the destination + * point of an edge and uses {@link Double#POSITIVE_INFINITY} as the edge's weight (effectively + * excluding the edge from routing) if the vehicle's bounding box protrudes the one of the point; + * otherwise, it uses 0. + */ +public class EdgeEvaluatorBoundingBox + implements + EdgeEvaluator { + + /** + * A key used for selecting this evaluator in a configuration setting. + * Should be unique among all keys. + */ + public static final String CONFIGURATION_KEY = "BOUNDING_BOX"; + private static final Logger LOG = LoggerFactory.getLogger(EdgeEvaluatorBoundingBox.class); + private final TCSObjectService objectService; + private final BoundingBoxProtrusionCheck protrusionCheck; + + /** + * Creates a new instance. + * + * @param objectService The object service. + * @param protrusionCheck Checks whether one bounding box protrudes beyond another one. + */ + @Inject + public EdgeEvaluatorBoundingBox( + TCSObjectService objectService, + BoundingBoxProtrusionCheck protrusionCheck + ) { + this.objectService = requireNonNull(objectService, "objectService"); + this.protrusionCheck = requireNonNull(protrusionCheck, "protrusionCheck"); + } + + @Override + public void onGraphComputationStart( + @Nonnull + Vehicle vehicle + ) { + } + + @Override + public void onGraphComputationEnd( + @Nonnull + Vehicle vehicle + ) { + } + + @Override + public double computeWeight( + @Nonnull + Edge edge, + @Nonnull + Vehicle vehicle + ) { + Point destPoint = objectService.fetchObject(Point.class, edge.getPath().getDestinationPoint()); + BoundingBoxProtrusion protrusion = protrusionCheck.checkProtrusion( + vehicle.getBoundingBox(), destPoint.getMaxVehicleBoundingBox() + ); + + if (protrusion.protrudesAnywhere()) { + LOG.debug( + "Excluding path '{}'. Bounding box of '{}' > max bounding box at '{}': {} > {}", + edge.getPath().getName(), + vehicle.getName(), + destPoint.getName(), + vehicle.getBoundingBox(), + destPoint.getMaxVehicleBoundingBox() + ); + return Double.POSITIVE_INFINITY; + } + + return 0; + } +} diff --git a/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/jgrapht/ShortestPathConfiguration.java b/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/jgrapht/ShortestPathConfiguration.java index ed0c0a9fd..a914ae4ae 100644 --- a/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/jgrapht/ShortestPathConfiguration.java +++ b/openTCS-Strategies-Default/src/main/java/org/opentcs/strategies/basic/routing/jgrapht/ShortestPathConfiguration.java @@ -42,7 +42,10 @@ public interface ShortestPathConfiguration { "'TRAVELTIME': A route's cost equals the vehicle's expected travel time.", "'EXPLICIT_PROPERTIES': A route's cost equals the sum of the explicitly given costs " + "extracted from path properties.", - "'HOPS': A route's cost equals the number of paths it consists of." + "'HOPS': A route's cost equals the number of paths it consists of.", + "'BOUNDING_BOX': A route's cost equals 0 if the vehicle's bounding box does not protrude " + + "beyond _any_ bounding boxes of points along the route. Otherwise, a route's cost " + + "is considered infinitely high, resulting in the route to be effectively discarded." }, changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START ) diff --git a/openTCS-Strategies-Default/src/test/java/org/opentcs/strategies/basic/routing/edgeevaluator/BoundingBoxProtrusionCheckTest.java b/openTCS-Strategies-Default/src/test/java/org/opentcs/strategies/basic/routing/edgeevaluator/BoundingBoxProtrusionCheckTest.java new file mode 100644 index 000000000..b11ee8a31 --- /dev/null +++ b/openTCS-Strategies-Default/src/test/java/org/opentcs/strategies/basic/routing/edgeevaluator/BoundingBoxProtrusionCheckTest.java @@ -0,0 +1,178 @@ +/** + * Copyright (c) The openTCS Authors. + * + * This program is free software and subject to the MIT license. (For details, + * see the licensing information (LICENSE.txt) you should have received with + * this copy of the software.) + */ +package org.opentcs.strategies.basic.routing.edgeevaluator; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.opentcs.data.model.BoundingBox; +import org.opentcs.data.model.Couple; +import org.opentcs.strategies.basic.routing.edgeevaluator.BoundingBoxProtrusionCheck.BoundingBoxProtrusion; + +/** + * Tests for {@link BoundingBoxProtrusionCheck}. + */ +class BoundingBoxProtrusionCheckTest { + + private BoundingBoxProtrusionCheck boundingBoxProtrusionCheck; + + @BeforeEach + void setUp() { + boundingBoxProtrusionCheck = new BoundingBoxProtrusionCheck(); + } + + @Test + void detectProtrusionFromTheFront() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(200, 0)); + BoundingBox inner = new BoundingBox(600, 300, 200) + .withReferenceOffset(new Couple(-100, 0)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertTrue(result.protrudesFront()); + assertFalse(result.protrudesBack()); + assertFalse(result.protrudesLeft()); + assertFalse(result.protrudesRight()); + assertFalse(result.protrudesTop()); + } + + @Test + void detectProtrusionFromTheBack() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(-200, 0)); + BoundingBox inner = new BoundingBox(600, 300, 200) + .withReferenceOffset(new Couple(100, 0)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesFront()); + assertTrue(result.protrudesBack()); + assertFalse(result.protrudesLeft()); + assertFalse(result.protrudesRight()); + assertFalse(result.protrudesTop()); + } + + @Test + void detectProtrusionFromTheLeft() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(0, 200)); + BoundingBox inner = new BoundingBox(600, 300, 200) + .withReferenceOffset(new Couple(0, -100)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesFront()); + assertFalse(result.protrudesBack()); + assertTrue(result.protrudesLeft()); + assertFalse(result.protrudesRight()); + assertFalse(result.protrudesTop()); + } + + @Test + void detectProtrusionFromTheRight() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(0, -200)); + BoundingBox inner = new BoundingBox(600, 300, 200) + .withReferenceOffset(new Couple(0, 100)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesFront()); + assertFalse(result.protrudesBack()); + assertFalse(result.protrudesLeft()); + assertTrue(result.protrudesRight()); + assertFalse(result.protrudesTop()); + } + + @Test + void detectProtrusionFromTheTop() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(0, 0)); + BoundingBox inner = new BoundingBox(600, 300, 1100) + .withReferenceOffset(new Couple(0, 0)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesFront()); + assertFalse(result.protrudesBack()); + assertFalse(result.protrudesLeft()); + assertFalse(result.protrudesRight()); + assertTrue(result.protrudesTop()); + } + + @Test + void noProtrusionWhenInnerIsFlushWithTheFrontOfOuter() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(200, 0)); + BoundingBox inner = new BoundingBox(600, 300, 200) + .withReferenceOffset(new Couple(0, 0)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesAnywhere()); + } + + @Test + void noProtrusionWhenInnerIsFlushWithTheBackOfOuter() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(-200, 0)); + BoundingBox inner = new BoundingBox(600, 300, 200) + .withReferenceOffset(new Couple(0, 0)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesAnywhere()); + } + + @Test + void noProtrusionWhenInnerIsFlushWithTheLeftOfOuter() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(0, 200)); + BoundingBox inner = new BoundingBox(600, 300, 200) + .withReferenceOffset(new Couple(0, 100)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesAnywhere()); + } + + @Test + void noProtrusionWhenInnerIsFlushWithTheRightOfOuter() { + BoundingBox outer = new BoundingBox(1000, 500, 1000) + .withReferenceOffset(new Couple(0, -200)); + BoundingBox inner = new BoundingBox(600, 300, 200) + .withReferenceOffset(new Couple(0, -100)); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesAnywhere()); + } + + @Test + void noProtrusionWhenInnerIsEqualToOuter() { + BoundingBox outer = new BoundingBox(1000, 1000, 1000); + BoundingBox inner = new BoundingBox(1000, 1000, 1000); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesAnywhere()); + } + + @Test + void noProtrusionWhenInnerIsSmallerThanOuter() { + BoundingBox outer = new BoundingBox(1000, 1000, 1000); + BoundingBox inner = new BoundingBox(500, 500, 500); + + BoundingBoxProtrusion result = boundingBoxProtrusionCheck.checkProtrusion(inner, outer); + + assertFalse(result.protrudesAnywhere()); + } +} diff --git a/openTCS-Strategies-Default/src/test/java/org/opentcs/strategies/basic/routing/edgeevaluator/EdgeEvaluatorBoundingBoxTest.java b/openTCS-Strategies-Default/src/test/java/org/opentcs/strategies/basic/routing/edgeevaluator/EdgeEvaluatorBoundingBoxTest.java new file mode 100644 index 000000000..be1e8040d --- /dev/null +++ b/openTCS-Strategies-Default/src/test/java/org/opentcs/strategies/basic/routing/edgeevaluator/EdgeEvaluatorBoundingBoxTest.java @@ -0,0 +1,80 @@ +/** + * Copyright (c) The openTCS Authors. + * + * This program is free software and subject to the MIT license. (For details, + * see the licensing information (LICENSE.txt) you should have received with + * this copy of the software.) + */ +package org.opentcs.strategies.basic.routing.edgeevaluator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.opentcs.components.kernel.routing.Edge; +import org.opentcs.components.kernel.services.TCSObjectService; +import org.opentcs.data.model.BoundingBox; +import org.opentcs.data.model.Path; +import org.opentcs.data.model.Point; +import org.opentcs.data.model.Vehicle; +import org.opentcs.strategies.basic.routing.edgeevaluator.BoundingBoxProtrusionCheck.BoundingBoxProtrusion; + +/** + * Tests for {@link EdgeEvaluatorBoundingBox}. + */ +class EdgeEvaluatorBoundingBoxTest { + + private TCSObjectService objectService; + private BoundingBoxProtrusionCheck protrusionCheck; + private EdgeEvaluatorBoundingBox edgeEvaluator; + + @BeforeEach + void setUp() { + objectService = mock(); + protrusionCheck = mock(); + edgeEvaluator = new EdgeEvaluatorBoundingBox(objectService, protrusionCheck); + } + + @Test + void excludePathWhenVehicleBondingBoxProtrudesPointBoundingBox() { + BoundingBox pointBoundingBox = new BoundingBox(1, 1, 1); + Point destPoint = new Point("2").withMaxVehicleBoundingBox(pointBoundingBox); + Path path = new Path("1 -- 2", new Point("1").getReference(), destPoint.getReference()); + Edge edge = new Edge(path, false); + + BoundingBox vehicleBoundingBox = new BoundingBox(3, 3, 3); + Vehicle vehicle = new Vehicle("vehicle").withBoundingBox(vehicleBoundingBox); + + when(objectService.fetchObject(Point.class, destPoint.getReference())).thenReturn(destPoint); + when(protrusionCheck.checkProtrusion(vehicleBoundingBox, pointBoundingBox)) + .thenReturn(new BoundingBoxProtrusion(1, 1, 1, 1, 1)); + + double result = edgeEvaluator.computeWeight(edge, vehicle); + + assertThat(result).isEqualTo(Double.POSITIVE_INFINITY); + verify(protrusionCheck).checkProtrusion(vehicleBoundingBox, pointBoundingBox); + } + + @Test + void includePathWhenVehicleBondingBoxDoesNotProtrudePointBoundingBox() { + BoundingBox pointBoundingBox = new BoundingBox(3, 3, 3); + Point destPoint = new Point("2").withMaxVehicleBoundingBox(pointBoundingBox); + Path path = new Path("1 -- 2", new Point("1").getReference(), destPoint.getReference()); + Edge edge = new Edge(path, false); + + BoundingBox vehicleBoundingBox = new BoundingBox(1, 1, 1); + Vehicle vehicle = new Vehicle("vehicle").withBoundingBox(vehicleBoundingBox); + + when(objectService.fetchObject(Point.class, destPoint.getReference())).thenReturn(destPoint); + when(protrusionCheck.checkProtrusion(vehicleBoundingBox, pointBoundingBox)) + .thenReturn(new BoundingBoxProtrusion(0, 0, 0, 0, 0)); + + double result = edgeEvaluator.computeWeight(edge, vehicle); + + assertThat(result).isEqualTo(0); + verify(protrusionCheck).checkProtrusion(vehicleBoundingBox, pointBoundingBox); + } +}